git_x/
command.rs

1use crate::Result;
2
3/// Trait for all git-x commands
4///
5/// This trait provides a unified interface for all git-x commands, allowing for
6/// consistent error handling, testing, and potential plugin architecture.
7pub trait Command {
8    /// The input type for this command (can be () for no input)
9    type Input;
10
11    /// The output type for this command
12    type Output;
13
14    /// Execute the command with the given input
15    fn execute(&self, input: Self::Input) -> Result<Self::Output>;
16
17    /// Get the name of this command (for logging/debugging)
18    fn name(&self) -> &'static str;
19
20    /// Get a description of what this command does
21    fn description(&self) -> &'static str;
22
23    /// Whether this command requires a git repository to function
24    fn requires_git_repo(&self) -> bool {
25        true
26    }
27
28    /// Whether this command performs destructive operations
29    fn is_destructive(&self) -> bool {
30        false
31    }
32}
33
34/// Trait for commands that don't return data but perform actions (print output)
35pub trait ActionCommand: Command<Output = ()> {
36    /// Execute the command and handle output internally
37    fn run(&self, input: Self::Input) -> Result<()> {
38        self.execute(input)
39    }
40}
41
42/// Trait for commands that return formatted output
43pub trait QueryCommand: Command<Output = String> {
44    /// Execute the command and return formatted output
45    fn query(&self, input: Self::Input) -> Result<String> {
46        self.execute(input)
47    }
48}
49
50/// Auto-implement ActionCommand for commands that output ()
51impl<T> ActionCommand for T where T: Command<Output = ()> {}
52
53/// Auto-implement QueryCommand for commands that output String  
54impl<T> QueryCommand for T where T: Command<Output = String> {}
55
56/// Helper trait for commands with no input parameters
57pub trait SimpleCommand: Command<Input = ()> {
58    fn run_simple(&self) -> Result<Self::Output> {
59        self.execute(())
60    }
61}
62
63/// Auto-implement SimpleCommand for commands with () input
64impl<T> SimpleCommand for T where T: Command<Input = ()> {}
65
66#[cfg(test)]
67mod tests {
68    use super::*;
69
70    struct MockActionCommand;
71
72    impl Command for MockActionCommand {
73        type Input = String;
74        type Output = ();
75
76        fn execute(&self, input: String) -> Result<()> {
77            println!("Mock action: {input}");
78            Ok(())
79        }
80
81        fn name(&self) -> &'static str {
82            "mock-action"
83        }
84
85        fn description(&self) -> &'static str {
86            "A mock action command for testing"
87        }
88    }
89
90    struct MockQueryCommand;
91
92    impl Command for MockQueryCommand {
93        type Input = ();
94        type Output = String;
95
96        fn execute(&self, _input: ()) -> Result<String> {
97            Ok("Mock query result".to_string())
98        }
99
100        fn name(&self) -> &'static str {
101            "mock-query"
102        }
103
104        fn description(&self) -> &'static str {
105            "A mock query command for testing"
106        }
107    }
108
109    #[test]
110    fn test_action_command_trait() {
111        let cmd = MockActionCommand;
112        assert_eq!(cmd.name(), "mock-action");
113        assert_eq!(cmd.description(), "A mock action command for testing");
114        assert!(cmd.requires_git_repo());
115        assert!(!cmd.is_destructive());
116
117        let result = cmd.run("test input".to_string());
118        assert!(result.is_ok());
119    }
120
121    #[test]
122    fn test_query_command_trait() {
123        let cmd = MockQueryCommand;
124        assert_eq!(cmd.name(), "mock-query");
125        assert_eq!(cmd.description(), "A mock query command for testing");
126
127        let result = cmd.query(());
128        assert!(result.is_ok());
129        assert_eq!(result.unwrap(), "Mock query result");
130    }
131
132    #[test]
133    fn test_simple_command_trait() {
134        let cmd = MockQueryCommand;
135        let result = cmd.run_simple();
136        assert!(result.is_ok());
137        assert_eq!(result.unwrap(), "Mock query result");
138    }
139}