-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathhandler.rs
More file actions
150 lines (134 loc) · 4.88 KB
/
handler.rs
File metadata and controls
150 lines (134 loc) · 4.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
//! Exists Command Handler
//!
//! This module handles the exists command execution at the presentation layer,
//! checking whether an environment exists and outputting a boolean result.
use std::cell::RefCell;
use std::sync::Arc;
use parking_lot::ReentrantMutex;
use crate::application::command_handlers::exists::{
ExistsCommandHandler, ExistsCommandHandlerError,
};
use crate::domain::environment::name::EnvironmentName;
use crate::domain::environment::repository::EnvironmentRepository;
use crate::presentation::cli::input::cli::OutputFormat;
use crate::presentation::cli::views::commands::exists::{ExistsResult, JsonView, TextView};
use crate::presentation::cli::views::Render;
use crate::presentation::cli::views::UserOutput;
use super::errors::ExistsSubcommandError;
/// Presentation layer controller for exists command workflow
///
/// Checks whether an environment exists and outputs a boolean result.
/// This is a read-only command that checks local data only.
///
/// ## Responsibilities
///
/// - Validate environment name format
/// - Delegate to application layer for existence check
/// - Output `true` or `false` to stdout
///
/// ## Output Contract
///
/// - **stdout**: `true` or `false` (bare value, valid JSON)
/// - **exit code 0**: Command completed successfully (result is on stdout)
/// - **exit code 1**: An error occurred (e.g., repository failure)
///
/// ## Architecture
///
/// This controller intentionally does NOT use `ProgressReporter` because
/// the exists check is a sub-millisecond operation. Progress reporting
/// would add noise without value.
pub struct ExistsCommandController {
handler: ExistsCommandHandler,
user_output: Arc<ReentrantMutex<RefCell<UserOutput>>>,
}
impl ExistsCommandController {
/// Create a new `ExistsCommandController` with dependencies
///
/// # Arguments
///
/// * `repository` - Environment repository for checking existence
/// * `user_output` - Shared output service for result display
#[allow(clippy::needless_pass_by_value)] // Arc parameters are moved to constructor for ownership
pub fn new(
repository: Arc<dyn EnvironmentRepository + Send + Sync>,
user_output: Arc<ReentrantMutex<RefCell<UserOutput>>>,
) -> Self {
let handler = ExistsCommandHandler::new(repository);
Self {
handler,
user_output,
}
}
/// Execute the exists command workflow
///
/// This method orchestrates a simple workflow:
/// 1. Validate environment name
/// 2. Check existence via application layer
/// 3. Output boolean result to stdout
///
/// # Arguments
///
/// * `environment_name` - Name of the environment to check
/// * `output_format` - Output format (Text or Json)
///
/// # Errors
///
/// Returns `ExistsSubcommandError` if any step fails
pub fn execute(
&self,
environment_name: &str,
output_format: OutputFormat,
) -> Result<(), ExistsSubcommandError> {
// Step 1: Validate environment name
let env_name = Self::validate_environment_name(environment_name)?;
// Step 2: Check existence via application layer
let result = self
.handler
.execute(&env_name)
.map_err(|e| Self::map_handler_error(e, &env_name))?;
// Step 3: Output boolean result
self.display_result(&result, output_format)?;
Ok(())
}
/// Step 1: Validate environment name format
fn validate_environment_name(name: &str) -> Result<EnvironmentName, ExistsSubcommandError> {
EnvironmentName::new(name.to_string()).map_err(|source| {
ExistsSubcommandError::InvalidEnvironmentName {
name: name.to_string(),
source,
}
})
}
/// Map application layer errors to presentation errors
fn map_handler_error(
error: ExistsCommandHandlerError,
env_name: &EnvironmentName,
) -> ExistsSubcommandError {
match error {
ExistsCommandHandlerError::RepositoryError(e) => {
ExistsSubcommandError::ExistenceCheckFailed {
name: env_name.to_string(),
message: e.to_string(),
}
}
}
}
/// Step 3: Display boolean result
///
/// Outputs `true` or `false` to stdout. The output is the same
/// for both Text and Json formats since bare `true`/`false` are
/// valid JSON values.
fn display_result(
&self,
result: &ExistsResult,
output_format: OutputFormat,
) -> Result<(), ExistsSubcommandError> {
let output = match output_format {
OutputFormat::Text => TextView::render(result)?,
OutputFormat::Json => JsonView::render(result)?,
};
// Write result to stdout via UserOutput
self.user_output.lock().borrow_mut().result(&output);
Ok(())
}
}