hamelin_lib/tree/builder/
command.rs

1//! Command builder system for constructing Command AST nodes
2//!
3//! This module provides a fluent API for building command trees programmatically.
4//! Builders follow the same patterns as expression builders but for commands.
5
6use std::rc::Rc;
7
8use crate::tree::ast::clause::{
9    Assignment, AssignmentClause, FromClause, Selection, SortExpression, SortOrder, TableAlias,
10    TableReference,
11};
12use crate::tree::ast::command::{
13    AggCommand, AppendCommand, Command, DropCommand, ExplodeCommand, FromCommand, JoinCommand,
14    LetCommand, LimitCommand, LookupCommand, MatchCommand, NestCommand, ParseCommand, RowsCommand,
15    SelectCommand, SortCommand, UnionCommand, UnnestCommand, WhereCommand, WindowCommand,
16    WithinCommand,
17};
18use crate::tree::ast::expression::{ColumnReference, Expression};
19use crate::tree::ast::identifier::{
20    Identifier, ParsedIdentifier, ParsedSimpleIdentifier, SimpleIdentifier,
21};
22use crate::tree::ast::node::Span;
23use crate::tree::ast::pattern::{Pattern, PatternKind, QuantifiedPattern, Quantifier};
24
25use super::IntoExpressionBuilder;
26
27// ============================================================================
28// TableReference convenience functions
29// ============================================================================
30
31/// Create a TableReference from an identifier
32pub fn table_ref(identifier: impl Into<Identifier>) -> TableReference {
33    TableReference {
34        span: Span::NONE,
35        identifier: ParsedIdentifier::Valid(identifier.into()),
36    }
37}
38
39// Implement Into<TableReference> for Identifier types
40impl From<Identifier> for TableReference {
41    fn from(identifier: Identifier) -> Self {
42        table_ref(identifier)
43    }
44}
45
46impl From<&str> for TableReference {
47    fn from(s: &str) -> Self {
48        table_ref(s)
49    }
50}
51
52impl From<String> for TableReference {
53    fn from(s: String) -> Self {
54        table_ref(s)
55    }
56}
57
58// ============================================================================
59// Pattern convenience functions
60// ============================================================================
61
62/// Create a quantified pattern from a table reference (e.g., for MATCH commands)
63///
64/// Examples:
65/// - `pattern_quantified(table_ref("events"), None)` - Simple pattern: `events`
66/// - `pattern_quantified(table_ref("events"), Some(quantifier_at_least_one()))` - Pattern: `events+`
67pub fn pattern_quantified(
68    from_clause: impl Into<FromClause>,
69    quantifier: Option<Quantifier>,
70) -> Pattern {
71    let kind: PatternKind = QuantifiedPattern {
72        span: Span::NONE,
73        from_clause: Rc::new(from_clause.into()),
74        quantifier: quantifier.map(Rc::new),
75    }
76    .into();
77    Pattern {
78        span: Span::NONE,
79        kind,
80    }
81}
82
83/// Create an "at least one" quantifier (+)
84pub fn quantifier_at_least_one() -> Quantifier {
85    crate::tree::ast::pattern::QuantifierKind::AtLeastOne.into()
86}
87
88/// Create an "any number" quantifier (*)
89pub fn quantifier_any_number() -> Quantifier {
90    crate::tree::ast::pattern::QuantifierKind::AnyNumber.into()
91}
92
93/// Create a "zero or one" quantifier (?)
94pub fn quantifier_zero_or_one() -> Quantifier {
95    crate::tree::ast::pattern::QuantifierKind::ZeroOrOne.into()
96}
97
98/// Create a pattern with a table alias (e.g., e=events)
99pub fn pattern_with_alias(
100    alias: impl Into<SimpleIdentifier>,
101    table: impl Into<Identifier>,
102) -> Pattern {
103    pattern_quantified(table_alias_from_clause(alias, table), None)
104}
105
106/// Create a pattern with a table alias and quantifier (e.g., e=events+)
107pub fn pattern_with_alias_and_quantifier(
108    alias: impl Into<SimpleIdentifier>,
109    table: impl Into<Identifier>,
110    quantifier: Quantifier,
111) -> Pattern {
112    pattern_quantified(table_alias_from_clause(alias, table), Some(quantifier))
113}
114
115/// Helper to create a TableAlias FromClause
116fn table_alias_from_clause(
117    alias: impl Into<SimpleIdentifier>,
118    table: impl Into<Identifier>,
119) -> FromClause {
120    let alias_simple: SimpleIdentifier = alias.into();
121    let table_ident: Identifier = table.into();
122    FromClause::TableAlias(Rc::new(TableAlias {
123        span: Span::NONE,
124        alias: alias_simple.into(),
125        table: TableReference {
126            span: Span::NONE,
127            identifier: table_ident.into(),
128        },
129    }))
130}
131
132/// Create an "exactly n" quantifier ({n})
133pub fn quantifier_exactly(n: impl Into<String>) -> Quantifier {
134    crate::tree::ast::pattern::QuantifierKind::Exactly(n.into()).into()
135}
136
137// Implement Into<Pattern> for common types
138impl From<TableReference> for Pattern {
139    fn from(table: TableReference) -> Self {
140        pattern_quantified(table, None)
141    }
142}
143
144impl From<&str> for Pattern {
145    fn from(s: &str) -> Self {
146        pattern_quantified(table_ref(s), None)
147    }
148}
149
150impl From<String> for Pattern {
151    fn from(s: String) -> Self {
152        pattern_quantified(table_ref(s), None)
153    }
154}
155
156/// Builder for LET command
157#[derive(Debug)]
158pub struct LetCommandBuilder {
159    assignments: Vec<Assignment>,
160}
161
162impl LetCommandBuilder {
163    pub fn new() -> Self {
164        Self {
165            assignments: Vec::new(),
166        }
167    }
168
169    /// Add a named field to the LET command
170    pub fn named_field(
171        mut self,
172        identifier: impl Into<Identifier>,
173        expression: impl IntoExpressionBuilder,
174    ) -> Self {
175        let expr = expression.into_expression_builder().build();
176        self.assignments.push(Assignment {
177            span: Span::NONE,
178            identifier: ParsedIdentifier::Valid(identifier.into()),
179            expression: Rc::new(expr),
180        });
181        self
182    }
183
184    pub fn build(&self) -> Command {
185        Command {
186            span: Span::NONE,
187            kind: LetCommand {
188                assignments: self.assignments.iter().cloned().map(Rc::new).collect(),
189            }
190            .into(),
191        }
192    }
193}
194
195impl Default for LetCommandBuilder {
196    fn default() -> Self {
197        Self::new()
198    }
199}
200
201/// Builder for WHERE command
202#[derive(Debug)]
203pub struct WhereCommandBuilder {
204    condition: Expression,
205}
206
207impl WhereCommandBuilder {
208    pub fn new(condition: impl IntoExpressionBuilder) -> Self {
209        Self {
210            condition: condition.into_expression_builder().build(),
211        }
212    }
213
214    pub fn build(&self) -> Command {
215        Command {
216            span: Span::NONE,
217            kind: WhereCommand {
218                condition: Rc::new(self.condition.clone()),
219            }
220            .into(),
221        }
222    }
223}
224
225/// Builder for SELECT command
226#[derive(Debug)]
227pub struct SelectCommandBuilder {
228    clauses: Vec<AssignmentClause>,
229}
230
231impl SelectCommandBuilder {
232    pub fn new() -> Self {
233        Self {
234            clauses: Vec::new(),
235        }
236    }
237
238    /// Add a named field (identifier = expression)
239    pub fn named_field(
240        mut self,
241        identifier: impl Into<Identifier>,
242        expression: impl IntoExpressionBuilder,
243    ) -> Self {
244        let expr = expression.into_expression_builder().build();
245        self.clauses.push(
246            Assignment {
247                span: Span::NONE,
248                identifier: ParsedIdentifier::Valid(identifier.into()),
249                expression: Rc::new(expr),
250            }
251            .into(),
252        );
253        self
254    }
255
256    /// Add a column reference field (identifier inferred from column name)
257    pub fn field(mut self, column: impl Into<ColumnReference>) -> Self {
258        let col_ref = column.into();
259        let identifier = col_ref.column_name.clone().into();
260        let expr = Expression::from_kind(col_ref);
261        self.clauses.push(
262            Assignment {
263                span: Span::NONE,
264                identifier,
265                expression: Rc::new(expr),
266            }
267            .into(),
268        );
269        self
270    }
271
272    pub fn build(&self) -> Command {
273        Command {
274            span: Span::NONE,
275            kind: SelectCommand {
276                clauses: self.clauses.iter().cloned().map(Rc::new).collect(),
277            }
278            .into(),
279        }
280    }
281}
282
283impl Default for SelectCommandBuilder {
284    fn default() -> Self {
285        Self::new()
286    }
287}
288
289/// Builder for DROP command
290#[derive(Debug)]
291pub struct DropCommandBuilder {
292    selections: Vec<Selection>,
293}
294
295impl DropCommandBuilder {
296    pub fn new() -> Self {
297        Self {
298            selections: Vec::new(),
299        }
300    }
301
302    /// Add a field to drop
303    pub fn field(mut self, identifier: impl Into<Identifier>) -> Self {
304        self.selections.push(Selection {
305            span: Span::NONE,
306            identifier: ParsedIdentifier::Valid(identifier.into()),
307        });
308        self
309    }
310
311    pub fn build(&self) -> Command {
312        Command {
313            span: Span::NONE,
314            kind: DropCommand {
315                selections: self.selections.iter().cloned().map(Rc::new).collect(),
316            }
317            .into(),
318        }
319    }
320}
321
322impl Default for DropCommandBuilder {
323    fn default() -> Self {
324        Self::new()
325    }
326}
327
328/// Builder for FROM command
329#[derive(Debug)]
330pub struct FromCommandBuilder {
331    clauses: Vec<FromClause>,
332}
333
334impl FromCommandBuilder {
335    pub fn new() -> Self {
336        Self {
337            clauses: Vec::new(),
338        }
339    }
340
341    /// Add a table alias (name = table_reference)
342    pub fn table_alias(
343        mut self,
344        alias: impl Into<SimpleIdentifier>,
345        table_reference: impl Into<Identifier>,
346    ) -> Self {
347        self.clauses.push(
348            TableAlias {
349                span: Span::NONE,
350                alias: ParsedSimpleIdentifier::Valid(alias.into()),
351                table: TableReference {
352                    span: Span::NONE,
353                    identifier: ParsedIdentifier::Valid(table_reference.into()),
354                },
355            }
356            .into(),
357        );
358        self
359    }
360
361    /// Add a direct table reference
362    pub fn table_reference(mut self, table_reference: impl Into<Identifier>) -> Self {
363        self.clauses.push(
364            TableReference {
365                span: Span::NONE,
366                identifier: ParsedIdentifier::Valid(table_reference.into()),
367            }
368            .into(),
369        );
370        self
371    }
372
373    pub fn build(&self) -> Command {
374        Command {
375            span: Span::NONE,
376            kind: FromCommand {
377                clauses: self.clauses.iter().cloned().map(Rc::new).collect(),
378            }
379            .into(),
380        }
381    }
382}
383
384impl Default for FromCommandBuilder {
385    fn default() -> Self {
386        Self::new()
387    }
388}
389
390/// Builder for UNION command
391#[derive(Debug)]
392pub struct UnionCommandBuilder {
393    clauses: Vec<FromClause>,
394}
395
396impl UnionCommandBuilder {
397    pub fn new() -> Self {
398        Self {
399            clauses: Vec::new(),
400        }
401    }
402
403    /// Add a table alias
404    pub fn table_alias(
405        mut self,
406        alias: impl Into<String>,
407        table_reference: impl Into<Identifier>,
408    ) -> Self {
409        self.clauses.push(
410            TableAlias {
411                span: Span::NONE,
412                alias: ParsedSimpleIdentifier::Valid(SimpleIdentifier::new(alias)),
413                table: TableReference {
414                    span: Span::NONE,
415                    identifier: ParsedIdentifier::Valid(table_reference.into()),
416                },
417            }
418            .into(),
419        );
420        self
421    }
422
423    /// Add a direct table reference
424    pub fn table_reference(mut self, table_reference: impl Into<Identifier>) -> Self {
425        self.clauses.push(
426            TableReference {
427                span: Span::NONE,
428                identifier: ParsedIdentifier::Valid(table_reference.into()),
429            }
430            .into(),
431        );
432        self
433    }
434
435    pub fn build(&self) -> Command {
436        Command {
437            span: Span::NONE,
438            kind: UnionCommand {
439                clauses: self.clauses.iter().cloned().map(Rc::new).collect(),
440            }
441            .into(),
442        }
443    }
444}
445
446impl Default for UnionCommandBuilder {
447    fn default() -> Self {
448        Self::new()
449    }
450}
451
452/// Builder for LIMIT command
453#[derive(Debug)]
454pub struct LimitCommandBuilder {
455    count: Expression,
456}
457
458impl LimitCommandBuilder {
459    pub fn new(count: impl IntoExpressionBuilder) -> Self {
460        Self {
461            count: count.into_expression_builder().build(),
462        }
463    }
464
465    pub fn build(&self) -> Command {
466        Command {
467            span: Span::NONE,
468            kind: LimitCommand {
469                count: Rc::new(self.count.clone()),
470            }
471            .into(),
472        }
473    }
474}
475
476/// Builder for WITHIN command
477#[derive(Debug)]
478pub struct WithinCommandBuilder {
479    duration: Expression,
480}
481
482impl WithinCommandBuilder {
483    pub fn new(duration: impl IntoExpressionBuilder) -> Self {
484        Self {
485            duration: duration.into_expression_builder().build(),
486        }
487    }
488
489    pub fn build(&self) -> Command {
490        Command {
491            span: Span::NONE,
492            kind: WithinCommand {
493                duration: Rc::new(self.duration.clone()),
494            }
495            .into(),
496        }
497    }
498}
499
500/// Builder for SORT command
501#[derive(Debug)]
502pub struct SortCommandBuilder {
503    pub(crate) expressions: Vec<SortExpression>,
504}
505
506impl SortCommandBuilder {
507    pub fn new() -> Self {
508        Self {
509            expressions: Vec::new(),
510        }
511    }
512
513    /// Add a sort expression with no explicit order (database default)
514    pub fn by(mut self, expression: impl IntoExpressionBuilder) -> Self {
515        self.expressions.push(SortExpression {
516            span: Span::NONE,
517            expression: Rc::new(expression.into_expression_builder().build()),
518            order: None,
519        });
520        self
521    }
522
523    /// Add an ascending sort expression
524    pub fn asc(mut self, expression: impl IntoExpressionBuilder) -> Self {
525        self.expressions.push(SortExpression {
526            span: Span::NONE,
527            expression: Rc::new(expression.into_expression_builder().build()),
528            order: Some(SortOrder::Asc),
529        });
530        self
531    }
532
533    /// Add a descending sort expression
534    pub fn desc(mut self, expression: impl IntoExpressionBuilder) -> Self {
535        self.expressions.push(SortExpression {
536            span: Span::NONE,
537            expression: Rc::new(expression.into_expression_builder().build()),
538            order: Some(SortOrder::Desc),
539        });
540        self
541    }
542
543    pub fn build(&self) -> Command {
544        Command {
545            span: Span::NONE,
546            kind: SortCommand {
547                expressions: self.expressions.iter().cloned().map(Rc::new).collect(),
548            }
549            .into(),
550        }
551    }
552}
553
554impl Default for SortCommandBuilder {
555    fn default() -> Self {
556        Self::new()
557    }
558}
559
560// Typestate markers for ParseCommandBuilder
561pub struct NoPattern;
562pub struct NoIdentifiers;
563pub struct ValidParse;
564
565/// Builder for PARSE command with compile-time safety
566///
567/// Uses typestate pattern to ensure pattern and at least one identifier are provided.
568#[derive(Debug)]
569pub struct ParseCommandBuilder<State = NoPattern> {
570    source: Option<Expression>,
571    pattern: Option<Expression>,
572    identifiers: Vec<ParsedIdentifier>,
573    nodrop: bool,
574    _state: std::marker::PhantomData<State>,
575}
576
577impl ParseCommandBuilder<NoPattern> {
578    pub fn new() -> Self {
579        Self {
580            source: None,
581            pattern: None,
582            identifiers: Vec::new(),
583            nodrop: false,
584            _state: std::marker::PhantomData,
585        }
586    }
587
588    /// Set the pattern to parse (transitions to NoIdentifiers state)
589    pub fn pattern(
590        self,
591        pattern: impl IntoExpressionBuilder,
592    ) -> ParseCommandBuilder<NoIdentifiers> {
593        ParseCommandBuilder {
594            source: self.source,
595            pattern: Some(pattern.into_expression_builder().build()),
596            identifiers: self.identifiers,
597            nodrop: self.nodrop,
598            _state: std::marker::PhantomData,
599        }
600    }
601}
602
603impl Default for ParseCommandBuilder<NoPattern> {
604    fn default() -> Self {
605        Self::new()
606    }
607}
608
609impl ParseCommandBuilder<NoIdentifiers> {
610    /// Add an identifier to extract (transitions to ValidParse state)
611    pub fn identifier(
612        mut self,
613        identifier: impl Into<Identifier>,
614    ) -> ParseCommandBuilder<ValidParse> {
615        self.identifiers
616            .push(ParsedIdentifier::Valid(identifier.into()));
617        ParseCommandBuilder {
618            source: self.source,
619            pattern: self.pattern,
620            identifiers: self.identifiers,
621            nodrop: self.nodrop,
622            _state: std::marker::PhantomData,
623        }
624    }
625}
626
627impl ParseCommandBuilder<ValidParse> {
628    /// Add another identifier to extract
629    pub fn identifier(mut self, identifier: impl Into<Identifier>) -> Self {
630        self.identifiers
631            .push(ParsedIdentifier::Valid(identifier.into()));
632        self
633    }
634
635    /// Set the source expression
636    pub fn source(mut self, source: impl IntoExpressionBuilder) -> Self {
637        self.source = Some(source.into_expression_builder().build());
638        self
639    }
640
641    /// Set nodrop flag
642    pub fn nodrop(mut self, nodrop: bool) -> Self {
643        self.nodrop = nodrop;
644        self
645    }
646
647    pub fn build(&self) -> Command {
648        Command {
649            span: Span::NONE,
650            kind: ParseCommand {
651                source: self.source.clone().map(Rc::new),
652                pattern: Rc::new(
653                    self.pattern
654                        .clone()
655                        .expect("pattern should be set in ValidParse state"),
656                ),
657                identifiers: self.identifiers.clone(),
658                nodrop: self.nodrop,
659            }
660            .into(),
661        }
662    }
663}
664
665/// Builder for AGG command
666#[derive(Debug)]
667pub struct AggCommandBuilder {
668    clauses: Vec<AssignmentClause>,
669    group_by: Vec<AssignmentClause>,
670    sort: Vec<SortExpression>,
671}
672
673impl AggCommandBuilder {
674    pub fn new() -> Self {
675        Self {
676            clauses: Vec::new(),
677            group_by: Vec::new(),
678            sort: Vec::new(),
679        }
680    }
681
682    /// Add a named aggregation field
683    pub fn named_aggregate(
684        mut self,
685        identifier: impl Into<Identifier>,
686        expression: impl IntoExpressionBuilder,
687    ) -> Self {
688        let expr = expression.into_expression_builder().build();
689        self.clauses.push(
690            Assignment {
691                span: Span::NONE,
692                identifier: ParsedIdentifier::Valid(identifier.into()),
693                expression: Rc::new(expr),
694            }
695            .into(),
696        );
697        self
698    }
699
700    /// Add a named group by field
701    pub fn named_group(
702        mut self,
703        identifier: impl Into<Identifier>,
704        expression: impl IntoExpressionBuilder,
705    ) -> Self {
706        let expr = expression.into_expression_builder().build();
707        self.group_by.push(
708            Assignment {
709                span: Span::NONE,
710                identifier: ParsedIdentifier::Valid(identifier.into()),
711                expression: Rc::new(expr),
712            }
713            .into(),
714        );
715        self
716    }
717
718    /// Add a column reference to group by (identifier inferred from column name)
719    pub fn group_by(mut self, column: impl Into<ColumnReference>) -> Self {
720        let col_ref = column.into();
721        let identifier = col_ref.column_name.clone().into();
722        let expr = Expression::from_kind(col_ref);
723        self.group_by.push(
724            Assignment {
725                span: Span::NONE,
726                identifier,
727                expression: Rc::new(expr),
728            }
729            .into(),
730        );
731        self
732    }
733
734    /// Set sort expressions using a SortCommandBuilder
735    pub fn sort(mut self, sort_builder: SortCommandBuilder) -> Self {
736        self.sort = sort_builder.expressions;
737        self
738    }
739
740    pub fn build(&self) -> Command {
741        Command {
742            span: Span::NONE,
743            kind: AggCommand {
744                clauses: self.clauses.iter().cloned().map(Rc::new).collect(),
745                group_by: self.group_by.iter().cloned().map(Rc::new).collect(),
746                sort: self.sort.iter().cloned().map(Rc::new).collect(),
747            }
748            .into(),
749        }
750    }
751}
752
753impl Default for AggCommandBuilder {
754    fn default() -> Self {
755        Self::new()
756    }
757}
758
759/// Builder for WINDOW command
760#[derive(Debug)]
761pub struct WindowCommandBuilder {
762    clauses: Vec<AssignmentClause>,
763    group_by: Vec<AssignmentClause>,
764    sort: Vec<SortExpression>,
765    within: Option<Expression>,
766}
767
768impl WindowCommandBuilder {
769    pub fn new() -> Self {
770        Self {
771            clauses: Vec::new(),
772            group_by: Vec::new(),
773            sort: Vec::new(),
774            within: None,
775        }
776    }
777
778    /// Add a named window field
779    pub fn named_field(
780        mut self,
781        identifier: impl Into<Identifier>,
782        expression: impl IntoExpressionBuilder,
783    ) -> Self {
784        let expr = expression.into_expression_builder().build();
785        self.clauses.push(
786            Assignment {
787                span: Span::NONE,
788                identifier: ParsedIdentifier::Valid(identifier.into()),
789                expression: Rc::new(expr),
790            }
791            .into(),
792        );
793        self
794    }
795
796    /// Add a named group by field
797    pub fn group_by(
798        mut self,
799        identifier: impl Into<Identifier>,
800        expression: impl IntoExpressionBuilder,
801    ) -> Self {
802        let expr = expression.into_expression_builder().build();
803        self.group_by.push(
804            Assignment {
805                span: Span::NONE,
806                identifier: ParsedIdentifier::Valid(identifier.into()),
807                expression: Rc::new(expr),
808            }
809            .into(),
810        );
811        self
812    }
813
814    /// Set sort expressions using a SortCommandBuilder
815    pub fn sort(mut self, sort_builder: SortCommandBuilder) -> Self {
816        self.sort = sort_builder.expressions;
817        self
818    }
819
820    /// Set within duration
821    pub fn within(mut self, duration: impl IntoExpressionBuilder) -> Self {
822        self.within = Some(duration.into_expression_builder().build());
823        self
824    }
825
826    pub fn build(&self) -> Command {
827        Command {
828            span: Span::NONE,
829            kind: WindowCommand {
830                clauses: self.clauses.iter().cloned().map(Rc::new).collect(),
831                group_by: self.group_by.iter().cloned().map(Rc::new).collect(),
832                sort: self.sort.iter().cloned().map(Rc::new).collect(),
833                within: self.within.clone().map(Rc::new),
834            }
835            .into(),
836        }
837    }
838}
839
840impl Default for WindowCommandBuilder {
841    fn default() -> Self {
842        Self::new()
843    }
844}
845
846/// Builder for APPEND command
847#[derive(Debug)]
848pub struct AppendCommandBuilder {
849    table: TableReference,
850    distinct_by: Vec<Selection>,
851}
852
853impl AppendCommandBuilder {
854    pub fn new(table: impl Into<TableReference>) -> Self {
855        Self {
856            table: table.into(),
857            distinct_by: Vec::new(),
858        }
859    }
860
861    /// Add a distinct_by identifier
862    pub fn distinct_by(mut self, identifier: impl Into<Identifier>) -> Self {
863        self.distinct_by.push(Selection {
864            span: Span::NONE,
865            identifier: ParsedIdentifier::Valid(identifier.into()),
866        });
867        self
868    }
869
870    pub fn build(&self) -> Command {
871        Command {
872            span: Span::NONE,
873            kind: AppendCommand {
874                table: Rc::new(self.table.clone()),
875                distinct_by: self.distinct_by.iter().cloned().map(Rc::new).collect(),
876            }
877            .into(),
878        }
879    }
880}
881
882/// Builder for JOIN command
883#[derive(Debug)]
884pub struct JoinCommandBuilder {
885    other: FromClause,
886    on: Option<Expression>,
887}
888
889impl JoinCommandBuilder {
890    pub fn table_alias(
891        alias: impl Into<SimpleIdentifier>,
892        table_reference: impl Into<Identifier>,
893    ) -> Self {
894        Self {
895            other: TableAlias {
896                span: Span::NONE,
897                alias: ParsedSimpleIdentifier::Valid(alias.into()),
898                table: TableReference {
899                    span: Span::NONE,
900                    identifier: ParsedIdentifier::Valid(table_reference.into()),
901                },
902            }
903            .into(),
904            on: None,
905        }
906    }
907
908    pub fn table_reference(table_reference: impl Into<Identifier>) -> Self {
909        Self {
910            other: TableReference {
911                span: Span::NONE,
912                identifier: ParsedIdentifier::Valid(table_reference.into()),
913            }
914            .into(),
915            on: None,
916        }
917    }
918
919    /// Set the ON condition
920    pub fn on(mut self, condition: impl IntoExpressionBuilder) -> Self {
921        self.on = Some(condition.into_expression_builder().build());
922        self
923    }
924
925    pub fn build(&self) -> Command {
926        Command {
927            span: Span::NONE,
928            kind: JoinCommand {
929                other: Rc::new(self.other.clone()),
930                on_condition: self.on.clone().map(Rc::new),
931            }
932            .into(),
933        }
934    }
935}
936
937/// Builder for LOOKUP command
938#[derive(Debug)]
939pub struct LookupCommandBuilder {
940    other: FromClause,
941    on: Option<Expression>,
942}
943
944impl LookupCommandBuilder {
945    pub fn table_alias(
946        alias: impl Into<SimpleIdentifier>,
947        table_reference: impl Into<Identifier>,
948    ) -> Self {
949        Self {
950            other: TableAlias {
951                span: Span::NONE,
952                alias: ParsedSimpleIdentifier::Valid(alias.into()),
953                table: TableReference {
954                    span: Span::NONE,
955                    identifier: ParsedIdentifier::Valid(table_reference.into()),
956                },
957            }
958            .into(),
959            on: None,
960        }
961    }
962
963    pub fn table_reference(table_reference: impl Into<Identifier>) -> Self {
964        Self {
965            other: TableReference {
966                span: Span::NONE,
967                identifier: ParsedIdentifier::Valid(table_reference.into()),
968            }
969            .into(),
970            on: None,
971        }
972    }
973
974    /// Set the ON condition
975    pub fn on(mut self, condition: impl IntoExpressionBuilder) -> Self {
976        self.on = Some(condition.into_expression_builder().build());
977        self
978    }
979
980    pub fn build(&self) -> Command {
981        Command {
982            span: Span::NONE,
983            kind: LookupCommand {
984                other: Rc::new(self.other.clone()),
985                on_condition: self.on.clone().map(Rc::new),
986            }
987            .into(),
988        }
989    }
990}
991
992// Typestate markers for ExplodeCommandBuilder
993pub struct NoClause;
994pub struct WithClause;
995
996/// Builder for EXPLODE command with compile-time safety
997///
998/// Uses typestate pattern to ensure either expression() or assignment() is called.
999#[derive(Debug)]
1000pub struct ExplodeCommandBuilder<State = NoClause> {
1001    clause: Option<AssignmentClause>,
1002    _state: std::marker::PhantomData<State>,
1003}
1004
1005impl ExplodeCommandBuilder<NoClause> {
1006    pub fn new() -> Self {
1007        Self {
1008            clause: None,
1009            _state: std::marker::PhantomData,
1010        }
1011    }
1012
1013    /// Set an assignment to explode (identifier = expression)
1014    pub fn named_field(
1015        self,
1016        identifier: impl Into<Identifier>,
1017        expr: impl IntoExpressionBuilder,
1018    ) -> ExplodeCommandBuilder<WithClause> {
1019        let expr = expr.into_expression_builder().build();
1020        ExplodeCommandBuilder {
1021            clause: Some(
1022                Assignment {
1023                    span: Span::NONE,
1024                    identifier: ParsedIdentifier::Valid(identifier.into()),
1025                    expression: Rc::new(expr),
1026                }
1027                .into(),
1028            ),
1029            _state: std::marker::PhantomData,
1030        }
1031    }
1032
1033    /// Set a column reference to explode (identifier inferred from column name)
1034    pub fn field(self, column: impl Into<ColumnReference>) -> ExplodeCommandBuilder<WithClause> {
1035        let col_ref = column.into();
1036        let identifier = col_ref.column_name.clone().into();
1037        let expr = Expression::from_kind(col_ref);
1038        ExplodeCommandBuilder {
1039            clause: Some(
1040                Assignment {
1041                    span: Span::NONE,
1042                    identifier,
1043                    expression: Rc::new(expr),
1044                }
1045                .into(),
1046            ),
1047            _state: std::marker::PhantomData,
1048        }
1049    }
1050}
1051
1052impl Default for ExplodeCommandBuilder<NoClause> {
1053    fn default() -> Self {
1054        Self::new()
1055    }
1056}
1057
1058impl ExplodeCommandBuilder<WithClause> {
1059    pub fn build(&self) -> Command {
1060        Command {
1061            span: Span::NONE,
1062            kind: ExplodeCommand {
1063                clause: Rc::new(
1064                    self.clause
1065                        .clone()
1066                        .expect("clause should be set in WithClause state"),
1067                ),
1068            }
1069            .into(),
1070        }
1071    }
1072}
1073
1074// Only implement From<Command> for the WithClause state
1075impl From<ExplodeCommandBuilder<WithClause>> for Command {
1076    fn from(value: ExplodeCommandBuilder<WithClause>) -> Self {
1077        value.build()
1078    }
1079}
1080
1081/// Builder for UNNEST command
1082#[derive(Debug)]
1083pub struct UnnestCommandBuilder {
1084    expression: Expression,
1085}
1086
1087impl UnnestCommandBuilder {
1088    pub fn new(expression: impl IntoExpressionBuilder) -> Self {
1089        Self {
1090            expression: expression.into_expression_builder().build(),
1091        }
1092    }
1093
1094    pub fn build(&self) -> Command {
1095        Command {
1096            span: Span::NONE,
1097            kind: UnnestCommand {
1098                expression: Rc::new(self.expression.clone()),
1099            }
1100            .into(),
1101        }
1102    }
1103}
1104
1105/// Builder for ROWS command
1106#[derive(Debug)]
1107pub struct RowsCommandBuilder {
1108    expression: Expression,
1109}
1110
1111impl RowsCommandBuilder {
1112    pub fn new(expression: impl IntoExpressionBuilder) -> Self {
1113        Self {
1114            expression: expression.into_expression_builder().build(),
1115        }
1116    }
1117
1118    pub fn build(&self) -> Command {
1119        Command {
1120            span: Span::NONE,
1121            kind: RowsCommand {
1122                expression: Rc::new(self.expression.clone()),
1123            }
1124            .into(),
1125        }
1126    }
1127}
1128
1129/// Builder for NEST command
1130#[derive(Debug)]
1131pub struct NestCommandBuilder {
1132    identifier: ParsedIdentifier,
1133}
1134
1135impl NestCommandBuilder {
1136    pub fn new(identifier: impl Into<Identifier>) -> Self {
1137        Self {
1138            identifier: ParsedIdentifier::Valid(identifier.into()),
1139        }
1140    }
1141
1142    pub fn build(&self) -> Command {
1143        Command {
1144            span: Span::NONE,
1145            kind: NestCommand {
1146                identifier: Rc::new(self.identifier.clone()),
1147            }
1148            .into(),
1149        }
1150    }
1151}
1152
1153/// Builder for MATCH command
1154#[derive(Debug)]
1155pub struct MatchCommandBuilder {
1156    pattern: Vec<Pattern>,
1157    agg: Vec<AssignmentClause>,
1158    group_by: Vec<AssignmentClause>,
1159    sort: Vec<SortExpression>,
1160    within: Option<Expression>,
1161}
1162
1163impl MatchCommandBuilder {
1164    pub fn new() -> Self {
1165        Self {
1166            pattern: Vec::new(),
1167            agg: Vec::new(),
1168            group_by: Vec::new(),
1169            sort: Vec::new(),
1170            within: None,
1171        }
1172    }
1173
1174    /// Add a pattern
1175    pub fn pattern(mut self, pattern: impl Into<Pattern>) -> Self {
1176        self.pattern.push(pattern.into());
1177        self
1178    }
1179
1180    /// Add a pattern with a table alias (e.g., e=events)
1181    pub fn named_pattern(
1182        mut self,
1183        alias: impl Into<SimpleIdentifier>,
1184        table: impl Into<Identifier>,
1185    ) -> Self {
1186        self.pattern.push(pattern_with_alias(alias, table));
1187        self
1188    }
1189
1190    /// Add a pattern with a table alias and quantifier (e.g., e=events+)
1191    pub fn named_quantified_pattern(
1192        mut self,
1193        alias: impl Into<SimpleIdentifier>,
1194        table: impl Into<Identifier>,
1195        quantifier: Quantifier,
1196    ) -> Self {
1197        self.pattern
1198            .push(pattern_with_alias_and_quantifier(alias, table, quantifier));
1199        self
1200    }
1201
1202    /// Add an agg clause (aggregation over matched rows)
1203    pub fn agg(
1204        mut self,
1205        identifier: impl Into<Identifier>,
1206        expression: impl IntoExpressionBuilder,
1207    ) -> Self {
1208        let expr = expression.into_expression_builder().build();
1209        self.agg.push(
1210            Assignment {
1211                span: Span::NONE,
1212                identifier: ParsedIdentifier::Valid(identifier.into()),
1213                expression: Rc::new(expr),
1214            }
1215            .into(),
1216        );
1217        self
1218    }
1219
1220    /// Add a named group by field
1221    pub fn named_group(
1222        mut self,
1223        identifier: impl Into<Identifier>,
1224        expression: impl IntoExpressionBuilder,
1225    ) -> Self {
1226        let expr = expression.into_expression_builder().build();
1227        self.group_by.push(
1228            Assignment {
1229                span: Span::NONE,
1230                identifier: ParsedIdentifier::Valid(identifier.into()),
1231                expression: Rc::new(expr),
1232            }
1233            .into(),
1234        );
1235        self
1236    }
1237
1238    /// Add a column reference to group by (identifier inferred from column name)
1239    pub fn group_by(mut self, column: impl Into<ColumnReference>) -> Self {
1240        let col_ref = column.into();
1241        let identifier = col_ref.column_name.clone().into();
1242        let expr = Expression::from_kind(col_ref);
1243        self.group_by.push(
1244            Assignment {
1245                span: Span::NONE,
1246                identifier,
1247                expression: Rc::new(expr),
1248            }
1249            .into(),
1250        );
1251        self
1252    }
1253
1254    /// Set sort expressions using a SortCommandBuilder
1255    pub fn sort(mut self, sort_builder: SortCommandBuilder) -> Self {
1256        self.sort = sort_builder.expressions;
1257        self
1258    }
1259
1260    /// Set the within expression
1261    pub fn within(mut self, expr: impl IntoExpressionBuilder) -> Self {
1262        self.within = Some(expr.into_expression_builder().build());
1263        self
1264    }
1265
1266    pub fn build(&self) -> Command {
1267        Command {
1268            span: Span::NONE,
1269            kind: MatchCommand {
1270                pattern: self
1271                    .pattern
1272                    .iter()
1273                    .cloned()
1274                    .map(|pattern| Rc::new(pattern))
1275                    .collect(),
1276                agg: self.agg.iter().cloned().map(|s| Rc::new(s)).collect(),
1277                group_by: self
1278                    .group_by
1279                    .iter()
1280                    .cloned()
1281                    .map(|group_by| Rc::new(group_by))
1282                    .collect(),
1283                sort: self.sort.iter().map(|sort| Rc::new(sort.clone())).collect(),
1284                within: self.within.clone().map(Rc::new),
1285            }
1286            .into(),
1287        }
1288    }
1289}
1290
1291impl Default for MatchCommandBuilder {
1292    fn default() -> Self {
1293        Self::new()
1294    }
1295}
1296
1297// Convenience functions for creating command builders
1298
1299/// Create a LET command builder
1300pub fn let_command() -> LetCommandBuilder {
1301    LetCommandBuilder::new()
1302}
1303
1304/// Create a WHERE command builder
1305pub fn where_command(condition: impl IntoExpressionBuilder) -> WhereCommandBuilder {
1306    WhereCommandBuilder::new(condition)
1307}
1308
1309/// Create a SELECT command builder
1310pub fn select_command() -> SelectCommandBuilder {
1311    SelectCommandBuilder::new()
1312}
1313
1314/// Create a DROP command builder
1315pub fn drop_command() -> DropCommandBuilder {
1316    DropCommandBuilder::new()
1317}
1318
1319/// Create a FROM command builder
1320pub fn from_command() -> FromCommandBuilder {
1321    FromCommandBuilder::new()
1322}
1323
1324/// Create a UNION command builder
1325pub fn union_command() -> UnionCommandBuilder {
1326    UnionCommandBuilder::new()
1327}
1328
1329/// Create a LIMIT command builder
1330pub fn limit_command(count: impl IntoExpressionBuilder) -> LimitCommandBuilder {
1331    LimitCommandBuilder::new(count)
1332}
1333
1334/// Create a WITHIN command builder
1335pub fn within_command(duration: impl IntoExpressionBuilder) -> WithinCommandBuilder {
1336    WithinCommandBuilder::new(duration)
1337}
1338
1339/// Create a SORT command builder
1340pub fn sort_command() -> SortCommandBuilder {
1341    SortCommandBuilder::new()
1342}
1343
1344/// Create a PARSE command builder
1345pub fn parse_command() -> ParseCommandBuilder<NoPattern> {
1346    ParseCommandBuilder::new()
1347}
1348
1349/// Create an AGG command builder
1350pub fn agg_command() -> AggCommandBuilder {
1351    AggCommandBuilder::new()
1352}
1353
1354/// Create a WINDOW command builder
1355pub fn window_command() -> WindowCommandBuilder {
1356    WindowCommandBuilder::new()
1357}
1358
1359/// Create an APPEND command builder
1360pub fn append_command(table: impl Into<TableReference>) -> AppendCommandBuilder {
1361    AppendCommandBuilder::new(table)
1362}
1363
1364/// Create a JOIN command builder with table alias
1365pub fn join_table_alias(
1366    alias: impl Into<SimpleIdentifier>,
1367    table_reference: impl Into<Identifier>,
1368) -> JoinCommandBuilder {
1369    JoinCommandBuilder::table_alias(alias, table_reference)
1370}
1371
1372/// Create a JOIN command builder with table reference
1373pub fn join_table_reference(table_reference: impl Into<Identifier>) -> JoinCommandBuilder {
1374    JoinCommandBuilder::table_reference(table_reference)
1375}
1376
1377/// Create a LOOKUP command builder with table alias
1378pub fn lookup_table_alias(
1379    alias: impl Into<SimpleIdentifier>,
1380    table_reference: impl Into<Identifier>,
1381) -> LookupCommandBuilder {
1382    LookupCommandBuilder::table_alias(alias, table_reference)
1383}
1384
1385/// Create a LOOKUP command builder with table reference
1386pub fn lookup_table_reference(table_reference: impl Into<Identifier>) -> LookupCommandBuilder {
1387    LookupCommandBuilder::table_reference(table_reference)
1388}
1389
1390/// Create an EXPLODE command builder
1391pub fn explode_command() -> ExplodeCommandBuilder<NoClause> {
1392    ExplodeCommandBuilder::new()
1393}
1394
1395/// Create an UNNEST command builder
1396pub fn unnest_command(expression: impl IntoExpressionBuilder) -> UnnestCommandBuilder {
1397    UnnestCommandBuilder::new(expression)
1398}
1399
1400/// Create a ROWS command builder
1401pub fn rows_command(expression: impl IntoExpressionBuilder) -> RowsCommandBuilder {
1402    RowsCommandBuilder::new(expression)
1403}
1404
1405/// Create a NEST command builder
1406pub fn nest_command(identifier: impl Into<Identifier>) -> NestCommandBuilder {
1407    NestCommandBuilder::new(identifier)
1408}
1409
1410/// Create a MATCH command builder
1411pub fn match_command() -> MatchCommandBuilder {
1412    MatchCommandBuilder::new()
1413}