1use core::fmt;
19use std::ops::ControlFlow;
20
21use sqlparser::ast::helpers::attached_token::AttachedToken;
22use sqlparser::ast::{
23 self, LimitClause, OrderByKind, SelectFlavor, visit_expressions_mut,
24};
25
26#[derive(Clone)]
27pub struct QueryBuilder {
28 with: Option<ast::With>,
29 body: Option<Box<ast::SetExpr>>,
30 order_by_kind: Option<OrderByKind>,
31 limit: Option<ast::Expr>,
32 limit_by: Vec<ast::Expr>,
33 offset: Option<ast::Offset>,
34 fetch: Option<ast::Fetch>,
35 locks: Vec<ast::LockClause>,
36 for_clause: Option<ast::ForClause>,
37 distinct_union: bool,
39}
40
41impl QueryBuilder {
42 pub fn with(&mut self, value: Option<ast::With>) -> &mut Self {
43 self.with = value;
44 self
45 }
46 pub fn body(&mut self, value: Box<ast::SetExpr>) -> &mut Self {
47 self.body = Some(value);
48 self
49 }
50 pub fn take_body(&mut self) -> Option<Box<ast::SetExpr>> {
51 self.body.take()
52 }
53 pub fn order_by(&mut self, value: OrderByKind) -> &mut Self {
54 self.order_by_kind = Some(value);
55 self
56 }
57 pub fn limit(&mut self, value: Option<ast::Expr>) -> &mut Self {
58 self.limit = value;
59 self
60 }
61 pub fn limit_by(&mut self, value: Vec<ast::Expr>) -> &mut Self {
62 self.limit_by = value;
63 self
64 }
65 pub fn offset(&mut self, value: Option<ast::Offset>) -> &mut Self {
66 self.offset = value;
67 self
68 }
69 pub fn fetch(&mut self, value: Option<ast::Fetch>) -> &mut Self {
70 self.fetch = value;
71 self
72 }
73 pub fn locks(&mut self, value: Vec<ast::LockClause>) -> &mut Self {
74 self.locks = value;
75 self
76 }
77 pub fn for_clause(&mut self, value: Option<ast::ForClause>) -> &mut Self {
78 self.for_clause = value;
79 self
80 }
81 pub fn distinct_union(&mut self) -> &mut Self {
82 self.distinct_union = true;
83 self
84 }
85 pub fn is_distinct_union(&self) -> bool {
86 self.distinct_union
87 }
88 pub fn build(&self) -> Result<ast::Query, BuilderError> {
89 let order_by = self
90 .order_by_kind
91 .as_ref()
92 .map(|order_by_kind| ast::OrderBy {
93 kind: order_by_kind.clone(),
94 interpolate: None,
95 });
96
97 Ok(ast::Query {
98 with: self.with.clone(),
99 body: match self.body {
100 Some(ref value) => value.clone(),
101 None => return Err(Into::into(UninitializedFieldError::from("body"))),
102 },
103 order_by,
104 limit_clause: Some(LimitClause::LimitOffset {
105 limit: self.limit.clone(),
106 offset: self.offset.clone(),
107 limit_by: self.limit_by.clone(),
108 }),
109 fetch: self.fetch.clone(),
110 locks: self.locks.clone(),
111 for_clause: self.for_clause.clone(),
112 settings: None,
113 format_clause: None,
114 pipe_operators: vec![],
115 })
116 }
117 fn create_empty() -> Self {
118 Self {
119 with: Default::default(),
120 body: Default::default(),
121 order_by_kind: Default::default(),
122 limit: Default::default(),
123 limit_by: Default::default(),
124 offset: Default::default(),
125 fetch: Default::default(),
126 locks: Default::default(),
127 for_clause: Default::default(),
128 distinct_union: false,
129 }
130 }
131}
132impl Default for QueryBuilder {
133 fn default() -> Self {
134 Self::create_empty()
135 }
136}
137
138#[derive(Clone)]
139pub struct SelectBuilder {
140 distinct: Option<ast::Distinct>,
141 top: Option<ast::Top>,
142 projection: Option<Vec<ast::SelectItem>>,
152 into: Option<ast::SelectInto>,
153 from: Vec<TableWithJoinsBuilder>,
154 lateral_views: Vec<ast::LateralView>,
155 selection: Option<ast::Expr>,
156 group_by: Option<ast::GroupByExpr>,
157 cluster_by: Vec<ast::Expr>,
158 distribute_by: Vec<ast::Expr>,
159 sort_by: Vec<ast::OrderByExpr>,
160 having: Option<ast::Expr>,
161 named_window: Vec<ast::NamedWindowDefinition>,
162 qualify: Option<ast::Expr>,
163 value_table_mode: Option<ast::ValueTableMode>,
164 flavor: Option<SelectFlavor>,
165 flatten_alias_counter: usize,
167 flatten_table_aliases: Vec<String>,
170}
171
172const FLATTEN_ALIAS_PREFIX: &str = "_unnest";
174
175impl SelectBuilder {
176 pub fn next_flatten_alias(&mut self) -> String {
179 self.flatten_alias_counter += 1;
180 format!("{FLATTEN_ALIAS_PREFIX}_{}", self.flatten_alias_counter)
181 }
182
183 pub fn add_flatten_table_alias(&mut self, alias: String) {
185 self.flatten_table_aliases.push(alias);
186 }
187
188 pub fn flatten_table_aliases_empty(&self) -> bool {
190 self.flatten_table_aliases.is_empty()
191 }
192
193 pub fn is_flatten_table_alias(&self, alias: &str) -> bool {
195 self.flatten_table_aliases.iter().any(|a| a == alias)
196 }
197
198 pub fn current_flatten_alias(&self) -> Option<String> {
201 if self.flatten_alias_counter > 0 {
202 Some(format!(
203 "{FLATTEN_ALIAS_PREFIX}_{}",
204 self.flatten_alias_counter
205 ))
206 } else {
207 None
208 }
209 }
210
211 pub fn distinct(&mut self, value: Option<ast::Distinct>) -> &mut Self {
212 self.distinct = value;
213 self
214 }
215 pub fn top(&mut self, value: Option<ast::Top>) -> &mut Self {
216 self.top = value;
217 self
218 }
219 pub fn projection(&mut self, value: Vec<ast::SelectItem>) -> &mut Self {
220 self.projection = Some(value);
221 self
222 }
223 pub fn pop_projections(&mut self) -> Vec<ast::SelectItem> {
224 self.projection.take().unwrap_or_default()
225 }
226 pub fn already_projected(&self) -> bool {
250 self.projection.is_some()
251 }
252 pub fn into(&mut self, value: Option<ast::SelectInto>) -> &mut Self {
253 self.into = value;
254 self
255 }
256 pub fn from(&mut self, value: Vec<TableWithJoinsBuilder>) -> &mut Self {
257 self.from = value;
258 self
259 }
260 pub fn push_from(&mut self, value: TableWithJoinsBuilder) -> &mut Self {
261 self.from.push(value);
262 self
263 }
264 pub fn pop_from(&mut self) -> Option<TableWithJoinsBuilder> {
265 self.from.pop()
266 }
267 pub fn has_selection(&self) -> bool {
268 self.selection.is_some()
269 }
270 pub fn lateral_views(&mut self, value: Vec<ast::LateralView>) -> &mut Self {
271 self.lateral_views = value;
272 self
273 }
274
275 pub fn replace_mark(
290 &mut self,
291 existing_expr: &ast::Expr,
292 value: &ast::Expr,
293 ) -> &mut Self {
294 if let Some(selection) = &mut self.selection {
295 let _ = visit_expressions_mut(selection, |expr| {
296 if expr == existing_expr {
297 *expr = value.clone();
298 }
299 ControlFlow::<()>::Continue(())
300 });
301 }
302 self
303 }
304
305 pub fn selection(&mut self, value: Option<ast::Expr>) -> &mut Self {
306 match (&self.selection, value) {
315 (Some(existing_selection), Some(new_selection)) => {
316 self.selection = Some(ast::Expr::BinaryOp {
317 left: Box::new(existing_selection.clone()),
318 op: ast::BinaryOperator::And,
319 right: Box::new(new_selection),
320 });
321 }
322 (None, Some(new_selection)) => {
323 self.selection = Some(new_selection);
324 }
325 (_, None) => (),
326 }
327
328 self
329 }
330 pub fn group_by(&mut self, value: ast::GroupByExpr) -> &mut Self {
331 self.group_by = Some(value);
332 self
333 }
334 pub fn cluster_by(&mut self, value: Vec<ast::Expr>) -> &mut Self {
335 self.cluster_by = value;
336 self
337 }
338 pub fn distribute_by(&mut self, value: Vec<ast::Expr>) -> &mut Self {
339 self.distribute_by = value;
340 self
341 }
342 pub fn sort_by(&mut self, value: Vec<ast::OrderByExpr>) -> &mut Self {
343 self.sort_by = value;
344 self
345 }
346 pub fn having(&mut self, value: Option<ast::Expr>) -> &mut Self {
347 self.having = value;
348 self
349 }
350 pub fn named_window(&mut self, value: Vec<ast::NamedWindowDefinition>) -> &mut Self {
351 self.named_window = value;
352 self
353 }
354 pub fn qualify(&mut self, value: Option<ast::Expr>) -> &mut Self {
355 self.qualify = value;
356 self
357 }
358 pub fn value_table_mode(&mut self, value: Option<ast::ValueTableMode>) -> &mut Self {
359 self.value_table_mode = value;
360 self
361 }
362 pub fn build(&self) -> Result<ast::Select, BuilderError> {
363 Ok(ast::Select {
364 optimizer_hints: vec![],
365 distinct: self.distinct.clone(),
366 select_modifiers: None,
367 top_before_distinct: false,
368 top: self.top.clone(),
369 projection: self.projection.clone().unwrap_or_default(),
370 into: self.into.clone(),
371 from: self
372 .from
373 .iter()
374 .filter_map(|b| b.build().transpose())
375 .collect::<Result<Vec<_>, BuilderError>>()?,
376 lateral_views: self.lateral_views.clone(),
377 selection: self.selection.clone(),
378 group_by: match self.group_by {
379 Some(ref value) => value.clone(),
380 None => {
381 return Err(Into::into(UninitializedFieldError::from("group_by")));
382 }
383 },
384 cluster_by: self.cluster_by.clone(),
385 distribute_by: self.distribute_by.clone(),
386 sort_by: self.sort_by.clone(),
387 having: self.having.clone(),
388 named_window: self.named_window.clone(),
389 qualify: self.qualify.clone(),
390 value_table_mode: self.value_table_mode,
391 connect_by: Vec::new(),
392 window_before_qualify: false,
393 prewhere: None,
394 select_token: AttachedToken::empty(),
395 flavor: match self.flavor {
396 Some(ref value) => *value,
397 None => return Err(Into::into(UninitializedFieldError::from("flavor"))),
398 },
399 exclude: None,
400 })
401 }
402 fn create_empty() -> Self {
403 Self {
404 distinct: Default::default(),
405 top: Default::default(),
406 projection: None,
407 into: Default::default(),
408 from: Default::default(),
409 lateral_views: Default::default(),
410 selection: Default::default(),
411 group_by: Some(ast::GroupByExpr::Expressions(Vec::new(), Vec::new())),
412 cluster_by: Default::default(),
413 distribute_by: Default::default(),
414 sort_by: Default::default(),
415 having: Default::default(),
416 named_window: Default::default(),
417 qualify: Default::default(),
418 value_table_mode: Default::default(),
419 flavor: Some(SelectFlavor::Standard),
420 flatten_alias_counter: 0,
421 flatten_table_aliases: Vec::new(),
422 }
423 }
424}
425impl Default for SelectBuilder {
426 fn default() -> Self {
427 Self::create_empty()
428 }
429}
430
431#[derive(Clone)]
432pub struct TableWithJoinsBuilder {
433 relation: Option<RelationBuilder>,
434 joins: Vec<ast::Join>,
435}
436
437impl TableWithJoinsBuilder {
438 pub fn relation(&mut self, value: RelationBuilder) -> &mut Self {
439 self.relation = Some(value);
440 self
441 }
442
443 pub fn joins(&mut self, value: Vec<ast::Join>) -> &mut Self {
444 self.joins = value;
445 self
446 }
447 pub fn push_join(&mut self, value: ast::Join) -> &mut Self {
448 self.joins.push(value);
449 self
450 }
451
452 pub fn build(&self) -> Result<Option<ast::TableWithJoins>, BuilderError> {
453 match self.relation {
454 Some(ref value) => match value.build()? {
455 Some(relation) => Ok(Some(ast::TableWithJoins {
456 relation,
457 joins: self.joins.clone(),
458 })),
459 None => Ok(None),
460 },
461 None => Err(Into::into(UninitializedFieldError::from("relation"))),
462 }
463 }
464 fn create_empty() -> Self {
465 Self {
466 relation: Default::default(),
467 joins: Default::default(),
468 }
469 }
470}
471impl Default for TableWithJoinsBuilder {
472 fn default() -> Self {
473 Self::create_empty()
474 }
475}
476
477#[derive(Clone)]
478pub struct RelationBuilder {
479 relation: Option<TableFactorBuilder>,
480}
481
482#[derive(Clone)]
483#[expect(clippy::large_enum_variant)]
486enum TableFactorBuilder {
487 Table(TableRelationBuilder),
488 Derived(DerivedRelationBuilder),
489 NestedJoin(ast::TableWithJoins, Option<ast::TableAlias>),
490 Unnest(UnnestRelationBuilder),
491 Flatten(FlattenRelationBuilder),
492 Empty,
493}
494
495impl RelationBuilder {
496 pub fn has_relation(&self) -> bool {
497 self.relation.is_some()
498 }
499 pub fn table(&mut self, value: TableRelationBuilder) -> &mut Self {
500 self.relation = Some(TableFactorBuilder::Table(value));
501 self
502 }
503 pub fn derived(&mut self, value: DerivedRelationBuilder) -> &mut Self {
504 self.relation = Some(TableFactorBuilder::Derived(value));
505 self
506 }
507
508 pub fn nested_join(
509 &mut self,
510 value: ast::TableWithJoins,
511 alias: Option<ast::TableAlias>,
512 ) -> &mut Self {
513 self.relation = Some(TableFactorBuilder::NestedJoin(value, alias));
514 self
515 }
516
517 pub fn unnest(&mut self, value: UnnestRelationBuilder) -> &mut Self {
518 self.relation = Some(TableFactorBuilder::Unnest(value));
519 self
520 }
521
522 pub fn flatten(&mut self, value: FlattenRelationBuilder) -> &mut Self {
523 self.relation = Some(TableFactorBuilder::Flatten(value));
524 self
525 }
526
527 pub fn empty(&mut self) -> &mut Self {
528 self.relation = Some(TableFactorBuilder::Empty);
529 self
530 }
531 pub fn alias(&mut self, value: Option<ast::TableAlias>) -> &mut Self {
532 let new = self;
533 match new.relation {
534 Some(TableFactorBuilder::Table(ref mut rel_builder)) => {
535 rel_builder.alias = value;
536 }
537 Some(TableFactorBuilder::Derived(ref mut rel_builder)) => {
538 rel_builder.alias = value;
539 }
540 Some(TableFactorBuilder::NestedJoin(_, ref mut alias)) => {
541 *alias = value;
542 }
543 Some(TableFactorBuilder::Unnest(ref mut rel_builder)) => {
544 rel_builder.alias = value;
545 }
546 Some(TableFactorBuilder::Flatten(ref mut rel_builder)) => {
547 rel_builder.alias = value;
548 }
549 Some(TableFactorBuilder::Empty) => (),
550 None => (),
551 }
552 new
553 }
554 pub fn build(&self) -> Result<Option<ast::TableFactor>, BuilderError> {
555 Ok(match self.relation {
556 Some(TableFactorBuilder::Table(ref value)) => Some(value.build()?),
557 Some(TableFactorBuilder::Derived(ref value)) => Some(value.build()?),
558 Some(TableFactorBuilder::NestedJoin(ref table_with_joins, ref alias)) => {
559 Some(ast::TableFactor::NestedJoin {
560 table_with_joins: Box::new(table_with_joins.clone()),
561 alias: alias.clone(),
562 })
563 }
564 Some(TableFactorBuilder::Unnest(ref value)) => Some(value.build()?),
565 Some(TableFactorBuilder::Flatten(ref value)) => Some(value.build()?),
566 Some(TableFactorBuilder::Empty) => None,
567 None => return Err(Into::into(UninitializedFieldError::from("relation"))),
568 })
569 }
570 fn create_empty() -> Self {
571 Self {
572 relation: Default::default(),
573 }
574 }
575}
576impl Default for RelationBuilder {
577 fn default() -> Self {
578 Self::create_empty()
579 }
580}
581
582#[derive(Clone)]
583pub struct TableRelationBuilder {
584 name: Option<ast::ObjectName>,
585 alias: Option<ast::TableAlias>,
586 args: Option<Vec<ast::FunctionArg>>,
587 with_hints: Vec<ast::Expr>,
588 version: Option<ast::TableVersion>,
589 partitions: Vec<ast::Ident>,
590 index_hints: Vec<ast::TableIndexHints>,
591}
592
593impl TableRelationBuilder {
594 pub fn name(&mut self, value: ast::ObjectName) -> &mut Self {
595 self.name = Some(value);
596 self
597 }
598 pub fn alias(&mut self, value: Option<ast::TableAlias>) -> &mut Self {
599 self.alias = value;
600 self
601 }
602 pub fn args(&mut self, value: Option<Vec<ast::FunctionArg>>) -> &mut Self {
603 self.args = value;
604 self
605 }
606 pub fn with_hints(&mut self, value: Vec<ast::Expr>) -> &mut Self {
607 self.with_hints = value;
608 self
609 }
610 pub fn version(&mut self, value: Option<ast::TableVersion>) -> &mut Self {
611 self.version = value;
612 self
613 }
614 pub fn partitions(&mut self, value: Vec<ast::Ident>) -> &mut Self {
615 self.partitions = value;
616 self
617 }
618 pub fn index_hints(&mut self, value: Vec<ast::TableIndexHints>) -> &mut Self {
619 self.index_hints = value;
620 self
621 }
622 pub fn build(&self) -> Result<ast::TableFactor, BuilderError> {
623 Ok(ast::TableFactor::Table {
624 name: match self.name {
625 Some(ref value) => value.clone(),
626 None => return Err(Into::into(UninitializedFieldError::from("name"))),
627 },
628 alias: self.alias.clone(),
629 args: self.args.clone().map(|args| ast::TableFunctionArgs {
630 args,
631 settings: None,
632 }),
633 with_hints: self.with_hints.clone(),
634 version: self.version.clone(),
635 partitions: self.partitions.clone(),
636 with_ordinality: false,
637 json_path: None,
638 sample: None,
639 index_hints: self.index_hints.clone(),
640 })
641 }
642 fn create_empty() -> Self {
643 Self {
644 name: Default::default(),
645 alias: Default::default(),
646 args: Default::default(),
647 with_hints: Default::default(),
648 version: Default::default(),
649 partitions: Default::default(),
650 index_hints: Default::default(),
651 }
652 }
653}
654impl Default for TableRelationBuilder {
655 fn default() -> Self {
656 Self::create_empty()
657 }
658}
659#[derive(Clone)]
660pub struct DerivedRelationBuilder {
661 lateral: Option<bool>,
662 subquery: Option<Box<ast::Query>>,
663 alias: Option<ast::TableAlias>,
664}
665
666impl DerivedRelationBuilder {
667 pub fn lateral(&mut self, value: bool) -> &mut Self {
668 self.lateral = Some(value);
669 self
670 }
671 pub fn subquery(&mut self, value: Box<ast::Query>) -> &mut Self {
672 self.subquery = Some(value);
673 self
674 }
675 pub fn alias(&mut self, value: Option<ast::TableAlias>) -> &mut Self {
676 self.alias = value;
677 self
678 }
679 fn build(&self) -> Result<ast::TableFactor, BuilderError> {
680 Ok(ast::TableFactor::Derived {
681 lateral: match self.lateral {
682 Some(ref value) => *value,
683 None => return Err(Into::into(UninitializedFieldError::from("lateral"))),
684 },
685 subquery: match self.subquery {
686 Some(ref value) => value.clone(),
687 None => {
688 return Err(Into::into(UninitializedFieldError::from("subquery")));
689 }
690 },
691 alias: self.alias.clone(),
692 sample: None,
693 })
694 }
695 fn create_empty() -> Self {
696 Self {
697 lateral: Default::default(),
698 subquery: Default::default(),
699 alias: Default::default(),
700 }
701 }
702}
703impl Default for DerivedRelationBuilder {
704 fn default() -> Self {
705 Self::create_empty()
706 }
707}
708
709#[derive(Clone)]
710pub struct UnnestRelationBuilder {
711 pub alias: Option<ast::TableAlias>,
712 pub array_exprs: Vec<ast::Expr>,
713 with_offset: bool,
714 with_offset_alias: Option<ast::Ident>,
715 with_ordinality: bool,
716}
717
718impl UnnestRelationBuilder {
719 pub fn alias(&mut self, value: Option<ast::TableAlias>) -> &mut Self {
720 self.alias = value;
721 self
722 }
723 pub fn array_exprs(&mut self, value: Vec<ast::Expr>) -> &mut Self {
724 self.array_exprs = value;
725 self
726 }
727
728 pub fn with_offset(&mut self, value: bool) -> &mut Self {
729 self.with_offset = value;
730 self
731 }
732
733 pub fn with_offset_alias(&mut self, value: Option<ast::Ident>) -> &mut Self {
734 self.with_offset_alias = value;
735 self
736 }
737
738 pub fn with_ordinality(&mut self, value: bool) -> &mut Self {
739 self.with_ordinality = value;
740 self
741 }
742
743 pub fn build(&self) -> Result<ast::TableFactor, BuilderError> {
744 Ok(ast::TableFactor::UNNEST {
745 alias: self.alias.clone(),
746 array_exprs: self.array_exprs.clone(),
747 with_offset: self.with_offset,
748 with_offset_alias: self.with_offset_alias.clone(),
749 with_ordinality: self.with_ordinality,
750 })
751 }
752
753 fn create_empty() -> Self {
754 Self {
755 alias: Default::default(),
756 array_exprs: Default::default(),
757 with_offset: Default::default(),
758 with_offset_alias: Default::default(),
759 with_ordinality: Default::default(),
760 }
761 }
762}
763
764impl Default for UnnestRelationBuilder {
765 fn default() -> Self {
766 Self::create_empty()
767 }
768}
769
770#[derive(Clone)]
773pub struct FlattenRelationBuilder {
774 pub alias: Option<ast::TableAlias>,
775 pub input_expr: Option<ast::Expr>,
777 pub outer: bool,
779}
780
781impl FlattenRelationBuilder {
782 pub fn alias(&mut self, value: Option<ast::TableAlias>) -> &mut Self {
783 self.alias = value;
784 self
785 }
786
787 pub fn input_expr(&mut self, value: ast::Expr) -> &mut Self {
788 self.input_expr = Some(value);
789 self
790 }
791
792 pub fn outer(&mut self, value: bool) -> &mut Self {
793 self.outer = value;
794 self
795 }
796
797 pub fn build(&self) -> Result<ast::TableFactor, BuilderError> {
798 let input = self.input_expr.clone().ok_or_else(|| {
799 BuilderError::from(UninitializedFieldError::from("input_expr"))
800 })?;
801
802 let mut args = vec![ast::FunctionArg::Named {
803 name: ast::Ident::new("INPUT"),
804 arg: ast::FunctionArgExpr::Expr(input),
805 operator: ast::FunctionArgOperator::RightArrow,
806 }];
807
808 if self.outer {
809 args.push(ast::FunctionArg::Named {
810 name: ast::Ident::new("OUTER"),
811 arg: ast::FunctionArgExpr::Expr(ast::Expr::Value(
812 ast::Value::Boolean(true).into(),
813 )),
814 operator: ast::FunctionArgOperator::RightArrow,
815 });
816 }
817
818 Ok(ast::TableFactor::Function {
819 lateral: true,
820 name: ast::ObjectName::from(vec![ast::Ident::new("FLATTEN")]),
821 args,
822 with_ordinality: false,
823 alias: self.alias.clone(),
824 })
825 }
826
827 fn create_empty() -> Self {
828 Self {
829 alias: None,
830 input_expr: None,
831 outer: false,
832 }
833 }
834}
835
836impl Default for FlattenRelationBuilder {
837 fn default() -> Self {
838 Self::create_empty()
839 }
840}
841
842#[derive(Debug, Clone)]
845pub struct UninitializedFieldError(&'static str);
846
847impl UninitializedFieldError {
848 pub fn new(field_name: &'static str) -> Self {
850 UninitializedFieldError(field_name)
851 }
852
853 pub fn field_name(&self) -> &'static str {
855 self.0
856 }
857}
858
859impl fmt::Display for UninitializedFieldError {
860 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
861 write!(f, "Field not initialized: {}", self.0)
862 }
863}
864
865impl From<&'static str> for UninitializedFieldError {
866 fn from(field_name: &'static str) -> Self {
867 Self::new(field_name)
868 }
869}
870impl std::error::Error for UninitializedFieldError {}
871
872#[derive(Debug)]
873pub enum BuilderError {
874 UninitializedField(&'static str),
875 ValidationError(String),
876}
877impl From<UninitializedFieldError> for BuilderError {
878 fn from(s: UninitializedFieldError) -> Self {
879 Self::UninitializedField(s.field_name())
880 }
881}
882impl From<String> for BuilderError {
883 fn from(s: String) -> Self {
884 Self::ValidationError(s)
885 }
886}
887impl fmt::Display for BuilderError {
888 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
889 match self {
890 Self::UninitializedField(field) => {
891 write!(f, "`{field}` must be initialized")
892 }
893 Self::ValidationError(error) => write!(f, "{error}"),
894 }
895 }
896}
897impl std::error::Error for BuilderError {}