1use std::borrow::Cow;
25use std::marker::PhantomData;
26
27use keelson_core::clause::{
28 Combine, ConflictClause, ConflictTarget, Cte, CteCycle, CteSearch, Fetch, HasCombines,
29 HasConflict, HasFetch, HasGroupBy, HasHaving, HasJoins, HasLimit, HasLocks, HasOffset,
30 HasOrderBy, HasReturning, HasSelectList, HasSet, HasTableRef, HasValues, HasWhere, HasWindows,
31 HasWith, Join, JoinKind, Lock, LockStrength, LockWait, NamedWindow, NullsPosition, OrderBy,
32 OrderDef, OrderDirection, SearchOrder, SetOp, TableFunctions, TableRef, Values, Window,
33};
34use keelson_core::expr::{Expr, IntoExpr, IntoExprList, IntoIdent};
35use keelson_core::{Mod, mod_fn};
36
37use crate::extras::{Incomplete, LateralBareName, Sample, SampledTable};
38use crate::function::TableFunction;
39use crate::statement::{HasExtraTables, HasTargetTable};
40
41#[derive(Debug, Clone)]
50pub struct CteChain {
51 cte: Cte,
52}
53
54pub fn with(name: impl Into<Cow<'static, str>>, body: impl IntoExpr) -> CteChain {
61 CteChain {
62 cte: Cte::new(name, body),
63 }
64}
65
66impl CteChain {
67 #[must_use]
69 pub fn columns(
70 mut self,
71 columns: impl IntoIterator<Item = impl Into<Cow<'static, str>>>,
72 ) -> CteChain {
73 self.cte.columns = columns.into_iter().map(Into::into).collect();
74 self
75 }
76
77 #[must_use]
79 pub fn materialized(mut self) -> CteChain {
80 self.cte.materialized = Some(true);
81 self
82 }
83
84 #[must_use]
86 pub fn not_materialized(mut self) -> CteChain {
87 self.cte.materialized = Some(false);
88 self
89 }
90
91 #[must_use]
93 pub fn search_breadth(
94 mut self,
95 set: impl Into<Cow<'static, str>>,
96 columns: impl IntoIterator<Item = impl Into<Cow<'static, str>>>,
97 ) -> CteChain {
98 self.cte.search = CteSearch::new(SearchOrder::Breadth, columns, set);
99 self
100 }
101
102 #[must_use]
107 pub fn search_depth(
108 mut self,
109 set: impl Into<Cow<'static, str>>,
110 columns: impl IntoIterator<Item = impl Into<Cow<'static, str>>>,
111 ) -> CteChain {
112 self.cte.search = CteSearch::new(SearchOrder::Depth, columns, set);
113 self
114 }
115
116 #[must_use]
118 pub fn cycle(
119 mut self,
120 set: impl Into<Cow<'static, str>>,
121 using: impl Into<Cow<'static, str>>,
122 columns: impl IntoIterator<Item = impl Into<Cow<'static, str>>>,
123 ) -> CteChain {
124 let cycle = CteCycle::new(columns, set, using);
125 self.cte.cycle = CteCycle {
126 to: self.cte.cycle.to,
127 default_val: self.cte.cycle.default_val,
128 ..cycle
129 };
130 self
131 }
132
133 #[must_use]
139 pub fn cycle_value(mut self, to: impl IntoExpr, default: impl IntoExpr) -> CteChain {
140 self.cte.cycle.to = Some(to.into_expr());
141 self.cte.cycle.default_val = Some(default.into_expr());
142 self
143 }
144}
145
146impl<Q: HasWith> Mod<Q> for CteChain {
147 fn apply(self, q: &mut Q) {
148 q.with_mut().append_cte(self.cte);
149 }
150}
151
152pub fn recursive<Q: HasWith>(recursive: bool) -> impl Mod<Q> {
157 mod_fn(move |q: &mut Q| q.with_mut().set_recursive(recursive))
158}
159
160pub fn columns<Q: HasSelectList>(columns: impl IntoExprList) -> impl Mod<Q> {
166 let columns = columns.into_expr_list();
167 mod_fn(move |q: &mut Q| q.select_list_mut().append_select(columns))
168}
169
170pub fn preload_columns<Q: HasSelectList>(columns: impl IntoExprList) -> impl Mod<Q> {
177 let columns = columns.into_expr_list();
178 mod_fn(move |q: &mut Q| q.select_list_mut().append_preload_select(columns))
179}
180
181pub trait TableSlot<Q> {
191 fn place(q: &mut Q, table: TableRef);
193}
194
195#[derive(Debug, Clone, Copy, Default)]
198pub struct FromSlot;
199
200#[derive(Debug, Clone, Copy, Default)]
202pub struct TargetSlot;
203
204#[derive(Debug, Clone, Copy, Default)]
207pub struct ExtraSlot;
208
209impl<Q: HasTableRef> TableSlot<Q> for FromSlot {
210 fn place(q: &mut Q, mut table: TableRef) {
211 table.joins.append(&mut q.table_ref_mut().joins);
215 *q.table_ref_mut() = table;
216 }
217}
218
219impl<Q: HasTargetTable> TableSlot<Q> for TargetSlot {
220 fn place(q: &mut Q, table: TableRef) {
221 *q.target_table_mut() = table;
222 }
223}
224
225impl<Q: HasExtraTables> TableSlot<Q> for ExtraSlot {
226 fn place(q: &mut Q, table: TableRef) {
227 q.extra_tables_mut().push(table);
228 }
229}
230
231#[derive(Debug, Clone)]
240pub struct TableChain<S> {
241 table: TableRef,
242 sample: Option<Sample>,
243 slot: PhantomData<S>,
244}
245
246fn table_chain<S>(table: impl IntoExpr) -> TableChain<S> {
247 TableChain {
248 table: TableRef::new(table),
249 sample: None,
250 slot: PhantomData,
251 }
252}
253
254pub fn from_item(table: impl IntoExpr) -> TableChain<FromSlot> {
256 table_chain(table)
257}
258
259pub fn extra_from_item(table: impl IntoExpr) -> TableChain<ExtraSlot> {
261 table_chain(table)
262}
263
264pub fn target_table(table: impl IntoExpr) -> TableChain<TargetSlot> {
266 table_chain(table)
267}
268
269pub fn from_functions<F>(functions: impl IntoIterator<Item = F>) -> TableChain<FromSlot>
286where
287 F: Into<TableFunction>,
288{
289 let list: Vec<Expr> = functions
290 .into_iter()
291 .map(|f| f.into().into_expr())
292 .collect();
293 if list.is_empty() {
294 return table_chain(Expr::custom(Incomplete("the functions of a from-item")));
295 }
296 table_chain(Expr::custom(TableFunctions::new(list)))
297}
298
299impl<S> TableChain<S> {
300 #[must_use]
302 pub fn as_(mut self, alias: impl Into<Cow<'static, str>>) -> TableChain<S> {
303 self.table.set_alias(alias);
304 self
305 }
306
307 #[must_use]
310 pub fn columns(
311 mut self,
312 columns: impl IntoIterator<Item = impl Into<Cow<'static, str>>>,
313 ) -> TableChain<S> {
314 self.table.set_columns(columns);
315 self
316 }
317
318 #[must_use]
320 pub fn only(mut self) -> TableChain<S> {
321 self.table.only = true;
322 self
323 }
324
325 #[must_use]
331 pub fn lateral(mut self) -> TableChain<S> {
332 self.table = lateral_table(self.table);
333 self
334 }
335
336 #[must_use]
338 pub fn with_ordinality(mut self) -> TableChain<S> {
339 self.table.with_ordinality = true;
340 self
341 }
342
343 #[must_use]
345 pub fn tablesample(
346 mut self,
347 method: impl Into<Cow<'static, str>>,
348 args: impl IntoExprList,
349 ) -> TableChain<S> {
350 self.sample = Some(Sample {
351 method: method.into(),
352 args: args.into_expr_list(),
353 repeatable: None,
354 });
355 self
356 }
357
358 #[must_use]
363 pub fn repeatable(mut self, seed: impl IntoExpr) -> TableChain<S> {
364 if let Some(sample) = &mut self.sample {
365 sample.repeatable = Some(seed.into_expr());
366 }
367 self
368 }
369}
370
371fn lateral_table(mut table: TableRef) -> TableRef {
377 table.lateral = true;
378 if matches!(table.expression, Some(Expr::Ident(_))) {
379 let name = table.expression.take().expect("just matched Some");
380 table.expression = Some(Expr::custom(LateralBareName(name)));
381 }
382 table
383}
384
385fn finish_table(mut table: TableRef, sample: Option<Sample>) -> TableRef {
390 let Some(sample) = sample else {
394 return table;
395 };
396 let Some(expression) = table.expression.take() else {
397 return table;
398 };
399 table.expression = Some(Expr::custom(SampledTable {
400 table: expression,
401 alias: table.alias.take(),
402 columns: std::mem::take(&mut table.columns),
403 sample,
404 }));
405 table
406}
407
408impl<Q, S: TableSlot<Q>> Mod<Q> for TableChain<S> {
409 fn apply(self, q: &mut Q) {
410 S::place(q, finish_table(self.table, self.sample));
411 }
412}
413
414#[derive(Debug, Clone)]
423pub struct JoinChain {
424 join: Join,
425 sample: Option<Sample>,
426}
427
428fn join_chain(kind: JoinKind, to: impl IntoExpr) -> JoinChain {
429 JoinChain {
430 join: Join::new(kind, TableRef::new(to)),
431 sample: None,
432 }
433}
434
435pub fn inner_join(table: impl IntoExpr) -> JoinChain {
437 join_chain(JoinKind::Inner, table)
438}
439
440pub fn left_join(table: impl IntoExpr) -> JoinChain {
442 join_chain(JoinKind::Left, table)
443}
444
445pub fn right_join(table: impl IntoExpr) -> JoinChain {
447 join_chain(JoinKind::Right, table)
448}
449
450pub fn full_join(table: impl IntoExpr) -> JoinChain {
452 join_chain(JoinKind::Full, table)
453}
454
455pub fn cross_join(table: impl IntoExpr) -> CrossJoinChain {
460 CrossJoinChain(join_chain(JoinKind::Cross, table))
461}
462
463impl JoinChain {
464 #[must_use]
466 pub fn as_(mut self, alias: impl Into<Cow<'static, str>>) -> JoinChain {
467 self.join.to.set_alias(alias);
468 self
469 }
470
471 #[must_use]
473 pub fn columns(
474 mut self,
475 columns: impl IntoIterator<Item = impl Into<Cow<'static, str>>>,
476 ) -> JoinChain {
477 self.join.to.set_columns(columns);
478 self
479 }
480
481 #[must_use]
483 pub fn only(mut self) -> JoinChain {
484 self.join.to.only = true;
485 self
486 }
487
488 #[must_use]
495 pub fn lateral(mut self) -> JoinChain {
496 self.join.to = lateral_table(self.join.to);
497 self
498 }
499
500 #[must_use]
502 pub fn with_ordinality(mut self) -> JoinChain {
503 self.join.to.with_ordinality = true;
504 self
505 }
506
507 #[must_use]
509 pub fn tablesample(
510 mut self,
511 method: impl Into<Cow<'static, str>>,
512 args: impl IntoExprList,
513 ) -> JoinChain {
514 self.sample = Some(Sample {
515 method: method.into(),
516 args: args.into_expr_list(),
517 repeatable: None,
518 });
519 self
520 }
521
522 #[must_use]
524 pub fn repeatable(mut self, seed: impl IntoExpr) -> JoinChain {
525 if let Some(sample) = &mut self.sample {
526 sample.repeatable = Some(seed.into_expr());
527 }
528 self
529 }
530
531 #[must_use]
533 pub fn natural(mut self) -> JoinChain {
534 self.join.natural = true;
535 self
536 }
537
538 #[must_use]
540 pub fn on(mut self, condition: impl IntoExpr) -> JoinChain {
541 self.join.append_on(condition);
542 self
543 }
544
545 #[must_use]
547 pub fn on_eq(self, a: impl IntoExpr, b: impl IntoExpr) -> JoinChain {
548 self.on(Expr::binary(a, "=", b).grouped())
549 }
550
551 #[must_use]
553 pub fn using(
554 mut self,
555 columns: impl IntoIterator<Item = impl Into<Cow<'static, str>>>,
556 ) -> JoinChain {
557 self.join.append_using(columns);
558 self
559 }
560
561 #[must_use]
568 pub fn using_alias(mut self, alias: impl Into<Cow<'static, str>>) -> JoinChain {
569 self.join.using_alias = Some(alias.into());
570 self
571 }
572}
573
574impl From<JoinChain> for Join {
575 fn from(chain: JoinChain) -> Join {
576 let JoinChain { mut join, sample } = chain;
577 join.to = finish_table(join.to, sample);
578 join
579 }
580}
581
582impl<Q: HasJoins> Mod<Q> for JoinChain {
583 fn apply(self, q: &mut Q) {
584 q.joins_mut().push(self.into());
585 }
586}
587
588#[derive(Debug, Clone)]
591pub struct CrossJoinChain(JoinChain);
592
593impl CrossJoinChain {
594 #[must_use]
596 pub fn as_(self, alias: impl Into<Cow<'static, str>>) -> CrossJoinChain {
597 CrossJoinChain(self.0.as_(alias))
598 }
599
600 #[must_use]
602 pub fn columns(
603 self,
604 columns: impl IntoIterator<Item = impl Into<Cow<'static, str>>>,
605 ) -> CrossJoinChain {
606 CrossJoinChain(self.0.columns(columns))
607 }
608
609 #[must_use]
611 pub fn only(self) -> CrossJoinChain {
612 CrossJoinChain(self.0.only())
613 }
614
615 #[must_use]
617 pub fn lateral(self) -> CrossJoinChain {
618 CrossJoinChain(self.0.lateral())
619 }
620
621 #[must_use]
623 pub fn with_ordinality(self) -> CrossJoinChain {
624 CrossJoinChain(self.0.with_ordinality())
625 }
626
627 #[must_use]
633 pub fn tablesample(
634 self,
635 method: impl Into<Cow<'static, str>>,
636 args: impl IntoExprList,
637 ) -> CrossJoinChain {
638 CrossJoinChain(self.0.tablesample(method, args))
639 }
640
641 #[must_use]
646 pub fn repeatable(self, seed: impl IntoExpr) -> CrossJoinChain {
647 CrossJoinChain(self.0.repeatable(seed))
648 }
649}
650
651impl From<CrossJoinChain> for Join {
652 fn from(chain: CrossJoinChain) -> Join {
653 chain.0.into()
654 }
655}
656
657impl<Q: HasJoins> Mod<Q> for CrossJoinChain {
658 fn apply(self, q: &mut Q) {
659 self.0.apply(q);
660 }
661}
662
663impl TableChain<ExtraSlot> {
664 #[must_use]
676 pub fn join(mut self, join: impl Into<Join>) -> TableChain<ExtraSlot> {
677 self.table.joins.push(join.into());
678 self
679 }
680}
681
682pub fn where_<Q: HasWhere>(condition: impl IntoExpr) -> impl Mod<Q> {
689 let condition = condition.into_expr();
690 mod_fn(move |q: &mut Q| q.where_mut().append_where(condition))
691}
692
693pub fn where_current_of<Q: HasWhere>(cursor: impl Into<Cow<'static, str>>) -> impl Mod<Q> {
698 let cursor = Expr::join((Expr::raw("CURRENT OF"), Expr::ident(cursor.into())));
699 mod_fn(move |q: &mut Q| q.where_mut().append_where(cursor))
700}
701
702pub fn having<Q: HasHaving>(condition: impl IntoExpr) -> impl Mod<Q> {
704 let condition = condition.into_expr();
705 mod_fn(move |q: &mut Q| q.having_mut().append_having(condition))
706}
707
708pub fn group_by<Q: HasGroupBy>(group: impl IntoExpr) -> impl Mod<Q> {
711 let group = group.into_expr();
712 mod_fn(move |q: &mut Q| q.group_by_mut().append_group(group))
713}
714
715pub fn group_by_distinct<Q: HasGroupBy>(distinct: bool) -> impl Mod<Q> {
718 mod_fn(move |q: &mut Q| q.group_by_mut().distinct = distinct)
719}
720
721pub fn window<Q: HasWindows>(
731 name: impl Into<Cow<'static, str>>,
732 definition: impl Mod<Window>,
733) -> impl Mod<Q> {
734 let mut w = Window::default();
735 definition.apply(&mut w);
736 let named = NamedWindow::new(name, w);
737 mod_fn(move |q: &mut Q| q.windows_mut().append_window(named))
738}
739
740pub trait OrderSlot<Q> {
746 fn slot(q: &mut Q) -> &mut OrderBy;
748}
749
750#[derive(Debug, Clone, Copy, Default)]
752pub struct DirectOrder;
753
754#[derive(Debug, Clone, Copy, Default)]
756pub struct CombinedOrder;
757
758impl<Q: HasOrderBy> OrderSlot<Q> for DirectOrder {
759 fn slot(q: &mut Q) -> &mut OrderBy {
760 q.order_by_mut()
761 }
762}
763
764impl<Q: HasCombines> OrderSlot<Q> for CombinedOrder {
765 fn slot(q: &mut Q) -> &mut OrderBy {
766 &mut q.combines_mut().order_by
767 }
768}
769
770#[derive(Debug, Clone)]
772pub struct OrderChain<S> {
773 def: OrderDef,
774 slot: PhantomData<S>,
775}
776
777pub fn order_by(expression: impl IntoExpr) -> OrderChain<DirectOrder> {
779 OrderChain {
780 def: OrderDef::new(expression),
781 slot: PhantomData,
782 }
783}
784
785pub fn order_by_combined(expression: impl IntoExpr) -> OrderChain<CombinedOrder> {
788 OrderChain {
789 def: OrderDef::new(expression),
790 slot: PhantomData,
791 }
792}
793
794impl<S> OrderChain<S> {
795 #[must_use]
797 pub fn asc(mut self) -> OrderChain<S> {
798 self.def.direction = Some(OrderDirection::Asc);
799 self
800 }
801
802 #[must_use]
804 pub fn desc(mut self) -> OrderChain<S> {
805 self.def.direction = Some(OrderDirection::Desc);
806 self
807 }
808
809 #[must_use]
812 pub fn using(mut self, operator: impl Into<Cow<'static, str>>) -> OrderChain<S> {
813 self.def.direction = Some(OrderDirection::Using(operator.into()));
814 self
815 }
816
817 #[must_use]
819 pub fn nulls_first(mut self) -> OrderChain<S> {
820 self.def.nulls = Some(NullsPosition::First);
821 self
822 }
823
824 #[must_use]
826 pub fn nulls_last(mut self) -> OrderChain<S> {
827 self.def.nulls = Some(NullsPosition::Last);
828 self
829 }
830
831 #[must_use]
833 pub fn collate(mut self, name: impl Into<Cow<'static, str>>) -> OrderChain<S> {
834 self.def.collation = Some(name.into());
835 self
836 }
837}
838
839impl<Q, S: OrderSlot<Q>> Mod<Q> for OrderChain<S> {
840 fn apply(self, q: &mut Q) {
841 S::slot(q).append_order(Expr::custom(self.def));
845 }
846}
847
848pub fn limit<Q: HasLimit>(count: impl IntoExpr) -> impl Mod<Q> {
858 let count = count.into_expr();
859 mod_fn(move |q: &mut Q| q.limit_mut().set_limit(count))
860}
861
862pub fn limit_all<Q: HasLimit>() -> impl Mod<Q> {
865 mod_fn(move |q: &mut Q| q.limit_mut().set_limit(Expr::raw("ALL")))
866}
867
868pub fn offset<Q: HasOffset>(start: impl IntoExpr) -> impl Mod<Q> {
870 let start = start.into_expr();
871 mod_fn(move |q: &mut Q| q.offset_mut().set_offset(start))
872}
873
874pub fn limit_combined<Q: HasCombines>(count: impl IntoExpr) -> impl Mod<Q> {
876 let count = count.into_expr();
877 mod_fn(move |q: &mut Q| q.combines_mut().limit.set_limit(count))
878}
879
880pub fn offset_combined<Q: HasCombines>(start: impl IntoExpr) -> impl Mod<Q> {
882 let start = start.into_expr();
883 mod_fn(move |q: &mut Q| q.combines_mut().offset.set_offset(start))
884}
885
886pub trait FetchSlot<Q> {
888 fn slot(q: &mut Q) -> &mut Fetch;
890}
891
892#[derive(Debug, Clone, Copy, Default)]
894pub struct DirectFetch;
895
896#[derive(Debug, Clone, Copy, Default)]
898pub struct CombinedFetch;
899
900impl<Q: HasFetch> FetchSlot<Q> for DirectFetch {
901 fn slot(q: &mut Q) -> &mut Fetch {
902 q.fetch_mut()
903 }
904}
905
906impl<Q: HasCombines> FetchSlot<Q> for CombinedFetch {
907 fn slot(q: &mut Q) -> &mut Fetch {
908 &mut q.combines_mut().fetch
909 }
910}
911
912#[derive(Debug, Clone)]
914pub struct FetchChain<S> {
915 fetch: Fetch,
916 slot: PhantomData<S>,
917}
918
919pub fn fetch(count: impl IntoExpr) -> FetchChain<DirectFetch> {
922 FetchChain {
923 fetch: Fetch::new(count),
924 slot: PhantomData,
925 }
926}
927
928pub fn fetch_combined(count: impl IntoExpr) -> FetchChain<CombinedFetch> {
930 FetchChain {
931 fetch: Fetch::new(count),
932 slot: PhantomData,
933 }
934}
935
936impl<S> FetchChain<S> {
937 #[must_use]
940 pub fn with_ties(mut self) -> FetchChain<S> {
941 self.fetch.with_ties = true;
942 self
943 }
944}
945
946impl<Q, S: FetchSlot<Q>> Mod<Q> for FetchChain<S> {
947 fn apply(self, q: &mut Q) {
948 *S::slot(q) = self.fetch;
949 }
950}
951
952#[derive(Debug, Clone)]
958pub struct LockChain {
959 lock: Lock,
960}
961
962pub fn for_update() -> LockChain {
964 LockChain {
965 lock: Lock::new(LockStrength::Update),
966 }
967}
968
969pub fn for_no_key_update() -> LockChain {
972 LockChain {
973 lock: Lock::new(LockStrength::NoKeyUpdate),
974 }
975}
976
977pub fn for_share() -> LockChain {
979 LockChain {
980 lock: Lock::new(LockStrength::Share),
981 }
982}
983
984pub fn for_key_share() -> LockChain {
986 LockChain {
987 lock: Lock::new(LockStrength::KeyShare),
988 }
989}
990
991impl LockChain {
992 #[must_use]
995 pub fn of(
996 mut self,
997 tables: impl IntoIterator<Item = impl Into<Cow<'static, str>>>,
998 ) -> LockChain {
999 self.lock.append_table(tables);
1000 self
1001 }
1002
1003 #[must_use]
1005 pub fn no_wait(mut self) -> LockChain {
1006 self.lock.wait = Some(LockWait::NoWait);
1007 self
1008 }
1009
1010 #[must_use]
1012 pub fn skip_locked(mut self) -> LockChain {
1013 self.lock.wait = Some(LockWait::SkipLocked);
1014 self
1015 }
1016}
1017
1018impl<Q: HasLocks> Mod<Q> for LockChain {
1019 fn apply(self, q: &mut Q) {
1020 q.locks_mut().append_lock(self.lock);
1021 }
1022}
1023
1024fn combine<Q: HasCombines>(op: SetOp, all: bool, query: impl IntoExpr) -> impl Mod<Q> {
1029 let mut c = Combine::new(op, query);
1030 c.all = all;
1031 mod_fn(move |q: &mut Q| q.combines_mut().append_combine(c))
1032}
1033
1034pub fn union<Q: HasCombines>(query: impl IntoExpr) -> impl Mod<Q> {
1036 combine(SetOp::Union, false, query)
1037}
1038
1039pub fn union_all<Q: HasCombines>(query: impl IntoExpr) -> impl Mod<Q> {
1041 combine(SetOp::Union, true, query)
1042}
1043
1044pub fn intersect<Q: HasCombines>(query: impl IntoExpr) -> impl Mod<Q> {
1046 combine(SetOp::Intersect, false, query)
1047}
1048
1049pub fn intersect_all<Q: HasCombines>(query: impl IntoExpr) -> impl Mod<Q> {
1051 combine(SetOp::Intersect, true, query)
1052}
1053
1054pub fn except<Q: HasCombines>(query: impl IntoExpr) -> impl Mod<Q> {
1056 combine(SetOp::Except, false, query)
1057}
1058
1059pub fn except_all<Q: HasCombines>(query: impl IntoExpr) -> impl Mod<Q> {
1061 combine(SetOp::Except, true, query)
1062}
1063
1064pub fn returning<Q: HasReturning>(expressions: impl IntoExprList) -> impl Mod<Q> {
1073 let expressions = expressions.into_expr_list();
1074 mod_fn(move |q: &mut Q| q.returning_mut().append_returnings(expressions))
1075}
1076
1077pub fn set<Q: HasSet>(assignment: impl IntoExpr) -> impl Mod<Q> {
1087 let assignment = assignment.into_expr();
1088 mod_fn(move |q: &mut Q| q.set_mut().append_set(assignment))
1089}
1090
1091#[derive(Debug, Clone)]
1096pub struct SetChain {
1097 column: Expr,
1098}
1099
1100pub fn set_col(column: impl IntoIdent) -> SetChain {
1109 SetChain {
1110 column: Expr::ident(column),
1111 }
1112}
1113
1114impl SetChain {
1115 pub fn to<Q: HasSet>(self, value: impl IntoExpr) -> impl Mod<Q> {
1117 set(Expr::binary(self.column, "=", value))
1118 }
1119
1120 pub fn to_arg<Q: HasSet>(self, value: impl keelson_core::ToValue) -> impl Mod<Q> {
1122 set(Expr::binary(self.column, "=", Expr::arg(value)))
1123 }
1124}
1125
1126pub fn set_excluded<Q: HasSet>(
1128 columns: impl IntoIterator<Item = impl Into<Cow<'static, str>>>,
1129) -> impl Mod<Q> {
1130 let assignments: Vec<Expr> = columns
1131 .into_iter()
1132 .map(Into::into)
1133 .filter(|c: &Cow<'static, str>| !c.is_empty())
1134 .map(|c| {
1135 Expr::join_with(
1136 "",
1137 (
1138 Expr::ident(c.clone()),
1139 Expr::raw(" = EXCLUDED."),
1140 Expr::ident(c),
1141 ),
1142 )
1143 })
1144 .collect();
1145 mod_fn(move |q: &mut Q| q.set_mut().append_sets(assignments))
1146}
1147
1148pub fn values<Q: HasValues>(row: impl IntoExprList) -> impl Mod<Q> {
1156 let row = row.into_expr_list();
1157 mod_fn(move |q: &mut Q| q.values_mut().append_values(row))
1158}
1159
1160pub fn rows<Q: HasValues, R: IntoExprList>(rows: impl IntoIterator<Item = R>) -> impl Mod<Q> {
1162 let rows: Vec<Vec<Expr>> = rows.into_iter().map(IntoExprList::into_expr_list).collect();
1163 mod_fn(move |q: &mut Q| {
1164 let values = q.values_mut();
1165 for row in rows {
1166 values.append_values(row);
1167 }
1168 })
1169}
1170
1171pub fn values_from_query<Q: HasValues>(query: impl IntoExpr) -> impl Mod<Q> {
1176 let query = query.into_expr();
1177 mod_fn(move |q: &mut Q| *q.values_mut() = Values::from_query(query))
1178}
1179
1180#[derive(Debug, Clone)]
1190pub struct ConflictChain {
1191 target: ConflictTarget,
1192}
1193
1194pub fn on_conflict(columns: impl IntoExprList) -> ConflictChain {
1198 ConflictChain {
1199 target: ConflictTarget::on_columns(columns),
1200 }
1201}
1202
1203pub fn on_conflict_on_constraint(name: impl Into<Cow<'static, str>>) -> ConflictChain {
1206 ConflictChain {
1207 target: ConflictTarget::on_constraint(name),
1208 }
1209}
1210
1211impl ConflictChain {
1212 #[must_use]
1219 pub fn where_(mut self, predicate: impl IntoExpr) -> ConflictChain {
1220 self.target.where_mut().append_where(predicate);
1221 self
1222 }
1223
1224 pub fn do_nothing(self) -> ConflictMod {
1226 let mut clause = ConflictClause::do_nothing();
1227 clause.target = self.target;
1228 ConflictMod { clause }
1229 }
1230
1231 pub fn do_update(self, body: impl Mod<ConflictClause>) -> ConflictMod {
1238 let mut clause = ConflictClause::do_update();
1239 clause.target = self.target;
1240 body.apply(&mut clause);
1241 ConflictMod { clause }
1242 }
1243}
1244
1245#[derive(Debug, Clone)]
1247pub struct ConflictMod {
1248 clause: ConflictClause,
1249}
1250
1251impl<Q: HasConflict> Mod<Q> for ConflictMod {
1252 fn apply(self, q: &mut Q) {
1253 q.conflict_mut().set_conflict(Expr::custom(self.clause));
1254 }
1255}