delta_funnel/orchestrator/session/
handles.rs1use std::fmt;
2
3use crate::{
4 MssqlTargetConfig, MssqlTargetOutputPlan, PhaseTimingReport, ResolvedMssqlTarget,
5 support::sanitize_text_for_display,
6};
7
8#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
10pub enum RunMode {
11 #[default]
13 Execute,
14 DryRun,
16}
17
18#[derive(Debug, Clone, PartialEq, Eq)]
20pub struct LazyTable {
21 id: LazyTableId,
22 kind: LazyTableKind,
23 name: String,
24}
25
26impl LazyTable {
27 #[cfg(test)]
29 #[must_use]
30 pub(crate) fn placeholder(id: u64, kind: LazyTableKind) -> Self {
31 Self {
32 id: LazyTableId(id),
33 kind,
34 name: format!("table_{id}"),
35 }
36 }
37
38 pub(super) fn delta_source(id: u64, name: String) -> Self {
39 Self {
40 id: LazyTableId(id),
41 kind: LazyTableKind::DeltaSource,
42 name,
43 }
44 }
45
46 pub(super) fn derived_sql(id: u64) -> Self {
47 Self {
48 id: LazyTableId(id),
49 kind: LazyTableKind::DerivedSql,
50 name: format!("table_{id}"),
51 }
52 }
53
54 pub(super) fn with_name(&self, name: String) -> Self {
55 Self {
56 id: self.id,
57 kind: self.kind,
58 name,
59 }
60 }
61
62 #[must_use]
64 pub const fn id(&self) -> u64 {
65 self.id.0
66 }
67
68 #[must_use]
70 pub const fn kind(&self) -> LazyTableKind {
71 self.kind
72 }
73
74 #[must_use]
76 pub fn name(&self) -> &str {
77 &self.name
78 }
79}
80
81#[derive(Debug, Clone, Copy, PartialEq, Eq)]
82struct LazyTableId(u64);
83
84#[derive(Debug, Clone, Copy, PartialEq, Eq)]
86pub enum LazyTableKind {
87 DeltaSource,
89 DerivedSql,
91}
92
93#[derive(Clone, PartialEq, Eq)]
95pub struct MssqlOutputTarget {
96 output_name: String,
97 target: MssqlTargetConfig,
98 run_mode: RunMode,
99}
100
101impl MssqlOutputTarget {
102 #[must_use]
104 pub fn new(
105 output_name: impl Into<String>,
106 target: MssqlTargetConfig,
107 run_mode: RunMode,
108 ) -> Self {
109 Self {
110 output_name: output_name.into(),
111 target,
112 run_mode,
113 }
114 }
115
116 #[must_use]
118 pub fn output_name(&self) -> &str {
119 &self.output_name
120 }
121
122 #[must_use]
124 pub const fn target(&self) -> &MssqlTargetConfig {
125 &self.target
126 }
127
128 #[must_use]
130 pub const fn run_mode(&self) -> RunMode {
131 self.run_mode
132 }
133}
134
135impl fmt::Debug for MssqlOutputTarget {
136 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
137 formatter
138 .debug_struct("MssqlOutputTarget")
139 .field("output_name", &sanitize_text_for_display(&self.output_name))
140 .field("target", &self.target)
141 .field("run_mode", &self.run_mode)
142 .finish()
143 }
144}
145
146#[derive(Debug, Clone, PartialEq, Eq)]
148pub struct OutputWritePlan {
149 table: LazyTable,
150 target: MssqlOutputTarget,
151}
152
153impl OutputWritePlan {
154 #[must_use]
156 pub const fn new(table: LazyTable, target: MssqlOutputTarget) -> Self {
157 Self { table, target }
158 }
159
160 #[must_use]
162 pub const fn table(&self) -> &LazyTable {
163 &self.table
164 }
165
166 #[must_use]
168 pub const fn target(&self) -> &MssqlOutputTarget {
169 &self.target
170 }
171}
172
173#[derive(Debug, Clone, PartialEq, Eq)]
175pub struct PlannedMssqlOutput {
176 request: OutputWritePlan,
177 resolved_target: ResolvedMssqlTarget,
178 output_plan: MssqlTargetOutputPlan,
179 phase_timings: Vec<PhaseTimingReport>,
180}
181
182impl PlannedMssqlOutput {
183 pub(super) fn new(
184 request: OutputWritePlan,
185 resolved_target: ResolvedMssqlTarget,
186 output_plan: MssqlTargetOutputPlan,
187 phase_timings: Vec<PhaseTimingReport>,
188 ) -> Self {
189 Self {
190 request,
191 resolved_target,
192 output_plan,
193 phase_timings,
194 }
195 }
196
197 #[must_use]
199 pub const fn request(&self) -> &OutputWritePlan {
200 &self.request
201 }
202
203 #[must_use]
205 pub const fn table(&self) -> &LazyTable {
206 self.request.table()
207 }
208
209 #[must_use]
211 pub const fn target(&self) -> &MssqlOutputTarget {
212 self.request.target()
213 }
214
215 #[must_use]
217 pub const fn resolved_target(&self) -> &ResolvedMssqlTarget {
218 &self.resolved_target
219 }
220
221 #[must_use]
223 pub const fn output_plan(&self) -> &MssqlTargetOutputPlan {
224 &self.output_plan
225 }
226
227 #[must_use]
229 pub fn phase_timings(&self) -> &[PhaseTimingReport] {
230 &self.phase_timings
231 }
232}
233
234#[cfg(test)]
235mod tests {
236 use crate::{
237 DeltaFunnelError, LoadMode, MssqlConnectionConfig, MssqlTargetConfig, MssqlTargetTable,
238 };
239
240 use super::{LazyTable, LazyTableKind, MssqlOutputTarget, OutputWritePlan, RunMode};
241
242 #[test]
243 fn output_request_shapes_preserve_table_target_and_run_mode() -> Result<(), DeltaFunnelError> {
244 let table = LazyTable::placeholder(7, LazyTableKind::DerivedSql);
245 let target_config = MssqlTargetConfig::new(MssqlTargetTable::new("dbo", "orders")?)
246 .with_load_mode(LoadMode::CreateAndLoad)
247 .with_connection(
248 MssqlConnectionConfig::new(
249 "server=tcp:sql.example.com;database=warehouse;user=admin;password=secret-token",
250 )?
251 .with_display_label("warehouse-primary"),
252 );
253 let target = MssqlOutputTarget::new("orders_output", target_config, RunMode::DryRun);
254 let plan = OutputWritePlan::new(table.clone(), target.clone());
255
256 assert_eq!(table.id(), 7);
257 assert_eq!(table.kind(), LazyTableKind::DerivedSql);
258 assert_eq!(target.output_name(), "orders_output");
259 assert_eq!(target.run_mode(), RunMode::DryRun);
260 assert_eq!(target.target().load_mode(), LoadMode::CreateAndLoad);
261 assert_eq!(plan.table(), &table);
262 assert_eq!(plan.target(), &target);
263
264 let debug = format!("{target:?}");
265 assert!(debug.contains("orders_output"));
266 assert!(!debug.contains("secret-token"));
267 assert!(!debug.contains("password"));
268 assert!(!debug.contains("server=tcp"));
269 Ok(())
270 }
271}