1#![allow(
2 clippy::module_inception,
3 clippy::type_complexity,
4 clippy::wrong_self_convention
5)]
6
7pub mod alias;
11pub mod compat;
13pub use compat::{Compatible, DefaultMeta, LowerCompatible};
14pub use quex;
15pub mod cte;
17pub use cte::{Cte, CteDefinition, IntoCtes, WithClause, with, with_recursive};
18pub mod expression;
20mod ty;
21
22pub use builder::delete_from;
23pub use builder::insert_into;
25pub use builder::update::update;
27pub use query::Query;
29pub use query::QueryOf;
31pub use ty::*;
32
33mod emitter;
34mod instr;
35pub(crate) mod lower;
36pub(crate) mod param;
37pub mod raw;
39pub mod relation;
41pub(crate) mod span;
42pub use instr::RpnInstr;
43mod dialect;
44pub use dialect::{Dialect, HasDialect, MySql, Postgres, Sqlite};
45mod precedence;
46pub mod aggregate;
48pub mod builder;
50pub mod macros;
52#[path = "select/mod.rs"]
54pub mod query;
55mod quex_exec;
56
57use builder::{Insert, Insertable, VisitParam};
58
59use crate::{alias::Aliased, expression::In as _, query::ColumnOf};
60
61mod from_row;
62pub use from_row::{FromPivotRow, FromPrefixedRow};
63pub use quex::FromRow;
64
65#[cfg(feature = "hash")]
66mod hashed;
67#[cfg(feature = "hash")]
68pub use hashed::*;
69
70mod value;
71pub(crate) use value::{DbValue, ValueKind};
72pub use raw::{Raw, RawQuery, RawScalar, raw};
73pub use ty::{
74 AsCast, BigInt, Blob, Bool, Boolean, Comparable, Date, Double, Float, Int, Likeable,
75 Logical, MathType, NotNull, Null, NullOf, Nullability, Nullable, Numeric, Orderable,
76 PredicateType, Required, Text, Time, Timestamp, TypeCast, TypeMeta, UBigInt, UInt, Untyped,
77};
78
79#[derive(Debug, Clone, Copy, PartialEq, Eq)]
81pub enum QueryVisibility {
82 Default,
83 WithDeleted,
84 OnlyDeleted,
85}
86
87pub trait ModelQueryPolicy<M>
88where
89 M: Qrafting,
90{
91 fn base_query(visibility: QueryVisibility) -> Query {
92 Self::apply_visibility(Query::from(M::TABLE), visibility)
93 }
94
95 fn apply_visibility(query: Query, _visibility: QueryVisibility) -> Query {
96 query
97 }
98
99 fn soft_delete(_query: Query) -> Option<builder::Update<M>> {
100 None
101 }
102
103 fn restore(_query: Query) -> Option<builder::Update<M>> {
104 None
105 }
106}
107
108pub struct DefaultQueryPolicy<M>(std::marker::PhantomData<fn() -> M>);
109
110impl<M> ModelQueryPolicy<M> for DefaultQueryPolicy<M> where M: Qrafting {}
111
112pub trait Qrafting: Sized {
113 type Schema;
114 type QueryPolicy: ModelQueryPolicy<Self>;
115 const FIELD_COUNT: usize;
116 const TABLE: &'static str;
117
118 #[doc(hidden)]
119 fn __qraft_query() -> QueryOf<Self>
120 where
121 Self: Sized + FromRow,
122 {
123 <Self::QueryPolicy as ModelQueryPolicy<Self>>::base_query(QueryVisibility::Default)
124 .typed::<Self>()
125 }
126}
127
128pub trait Pivot<const N: usize>: Sized {
130 const FIELDS: [Aliased<ColumnOf>; N];
131}
132
133pub trait RelationQuery<T> {
135 fn into_query(self) -> Option<QueryOf<T>>;
136}
137
138pub trait AttachInput<'a, Related, Key> {
140 fn into_related_keys(self, related_key: fn(&Related) -> Key) -> Vec<Key>;
141}
142
143pub enum SaveResult {
145 Clean,
146 Saved(quex::ExecResult),
147}
148
149pub struct DraftField<Model> {
151 name: &'static str,
152 index: usize,
153 _marker: std::marker::PhantomData<fn() -> Model>,
154}
155
156impl<Model> DraftField<Model> {
157 pub const fn new(name: &'static str, index: usize) -> Self {
158 Self {
159 name,
160 index,
161 _marker: std::marker::PhantomData,
162 }
163 }
164
165 pub const fn name(self) -> &'static str {
166 self.name
167 }
168
169 pub const fn index(self) -> usize {
170 self.index
171 }
172}
173
174impl<Model> Clone for DraftField<Model> {
175 fn clone(&self) -> Self {
176 *self
177 }
178}
179
180impl<Model> Copy for DraftField<Model> {}
181
182#[derive(Debug, Clone, Copy, PartialEq, Eq)]
183pub struct SyncResult {
184 pub attached: u64,
185 pub detached: u64,
186}
187
188#[derive(Debug, Clone, Copy, PartialEq, Eq)]
189pub struct ToggleResult {
190 pub attached: u64,
191 pub detached: u64,
192}
193
194#[derive(Debug, Clone, Copy, PartialEq, Eq)]
195pub struct SyncWithoutDetachingResult {
196 pub attached: u64,
197}
198
199pub trait SaveDraft {
201 type Model: Qrafting;
202
203 fn is_dirty(&self) -> bool;
204
205 fn save_update(&self) -> Option<builder::Update<Self::Model>>;
206
207 fn save<E>(self, exec: E) -> impl std::future::Future<Output = quex::Result<SaveResult>>
208 where
209 Self: Sized,
210 E: quex::Executor,
211 {
212 async move {
213 match self.save_update() {
214 Some(update) => update.execute(exec).await.map(SaveResult::Saved),
215 None => Ok(SaveResult::Clean),
216 }
217 }
218 }
219}
220
221pub trait Draftable: Sized {
223 type Draft<'a>: SaveDraft<Model = Self>
224 where
225 Self: 'a;
226
227 fn draft(&mut self) -> Self::Draft<'_>;
228
229 fn draft_mark(&mut self, field: DraftField<Self>) -> Self::Draft<'_>;
230
231 fn draft_mark_many(&mut self, fields: &[DraftField<Self>]) -> Self::Draft<'_>;
232
233 #[doc(hidden)]
234 fn __qraft_draft_with(&mut self, field: usize) -> Self::Draft<'_>;
235
236 #[doc(hidden)]
237 fn __qraft_draft_for_field(&mut self, field: &'static str) -> Self::Draft<'_>;
238
239 #[doc(hidden)]
240 fn __qraft_draft_for_fields(&mut self, fields: &[&'static str]) -> Self::Draft<'_>;
241}
242
243pub trait ModelKey {
245 type Key: Clone;
246
247 #[doc(hidden)]
248 fn __qraft_key(&self) -> &Self::Key;
249
250 #[doc(hidden)]
251 fn __qraft_key_column() -> &'static str;
252}
253
254pub trait FindsByKey: Sized {
256 type Key;
257
258 fn find(id: &Self::Key) -> QueryOf<Self>;
259}
260
261pub trait MorphName {
263 fn morph_name() -> &'static str;
264}
265
266pub trait RelationForeignKey<Key> {
268 fn from_relation_key(key: Key) -> Self;
269}
270
271pub trait RelationForeignKeyRef<Key: ?Sized> {
273 fn from_relation_key_ref(key: &Key) -> Self;
274}
275
276impl<Key> RelationForeignKey<Key> for Key {
277 fn from_relation_key(key: Key) -> Self {
278 key
279 }
280}
281
282impl<Key> RelationForeignKey<Key> for Option<Key> {
283 fn from_relation_key(key: Key) -> Self {
284 Some(key)
285 }
286}
287
288impl<Key: Clone, T> RelationForeignKeyRef<Key> for T
289where
290 T: RelationForeignKey<Key>,
291{
292 fn from_relation_key_ref(key: &Key) -> Self {
293 T::from_relation_key(key.clone())
294 }
295}
296
297pub trait RelationMorphType {
299 fn from_relation_morph_type(value: &'static str) -> Self;
300}
301
302impl RelationMorphType for String {
303 fn from_relation_morph_type(value: &'static str) -> Self {
304 value.to_owned()
305 }
306}
307
308impl RelationMorphType for Option<String> {
309 fn from_relation_morph_type(value: &'static str) -> Self {
310 Some(value.to_owned())
311 }
312}
313
314pub struct InjectMorphValues<V, Key> {
316 values: V,
317 id_field: &'static str,
318 type_field: &'static str,
319 key: Key,
320 morph_type: &'static str,
321}
322
323struct SkipFieldVisitor<'a, V> {
324 inner: &'a mut V,
325 fields: &'a [&'static str],
326}
327
328impl<'a, 'v, V> VisitParam<'v> for SkipFieldVisitor<'a, V>
329where
330 V: VisitParam<'v>,
331{
332 fn param(&mut self, field: &'static str, param: impl quex::Encode) {
333 if self.fields.contains(&field) {
334 return;
335 }
336 self.inner.param(field, param)
337 }
338
339 fn param_typed<T>(&mut self, field: &'static str, value: &'v (impl Compatible<T> + ?Sized))
340 where
341 T: TypeMeta,
342 {
343 if self.fields.contains(&field) {
344 return;
345 }
346 self.inner.param_typed::<T>(field, value)
347 }
348}
349
350impl<M, V, Key> Insertable<M> for InjectMorphValues<V, Key>
351where
352 M: Qrafting,
353 V: Insertable<M>,
354 Key: DefaultMeta + Compatible<<Key as DefaultMeta>::Meta>,
355{
356 fn values<'v>(&'v self, visitor: &mut impl VisitParam<'v>) {
357 visitor.param_typed::<<Key as DefaultMeta>::Meta>(self.id_field, &self.key);
358 visitor.param(self.type_field, self.morph_type);
359 let mut visitor = SkipFieldVisitor {
360 inner: visitor,
361 fields: &[self.id_field, self.type_field],
362 };
363 self.values.values(&mut visitor)
364 }
365}
366
367impl<'a, Related, Key> AttachInput<'a, Related, Key> for &'a Related {
368 fn into_related_keys(self, related_key: fn(&Related) -> Key) -> Vec<Key> {
369 vec![related_key(self)]
370 }
371}
372
373impl<'a, Related, Key> AttachInput<'a, Related, Key> for Vec<&'a Related> {
374 fn into_related_keys(self, related_key: fn(&Related) -> Key) -> Vec<Key> {
375 self.into_iter().map(related_key).collect()
376 }
377}
378
379impl<'a, Related, Key> AttachInput<'a, Related, Key> for &'a [&'a Related] {
380 fn into_related_keys(self, related_key: fn(&Related) -> Key) -> Vec<Key> {
381 self.iter().copied().map(related_key).collect()
382 }
383}
384
385impl<'a, Related, Key, const N: usize> AttachInput<'a, Related, Key> for [&'a Related; N] {
386 fn into_related_keys(self, related_key: fn(&Related) -> Key) -> Vec<Key> {
387 self.into_iter().map(related_key).collect()
388 }
389}
390
391macro_rules! impl_attach_input_tuple {
392 ($($T:ident),+) => {
393 impl<'a, Related, Key, $($T),+> AttachInput<'a, Related, Key> for ($($T,)+)
394 where
395 Related: 'a,
396 $($T: ::std::borrow::Borrow<Related>,)+
397 {
398 fn into_related_keys(self, related_key: fn(&Related) -> Key) -> Vec<Key> {
399 #[allow(non_snake_case)]
400 let ($($T,)+) = self;
401 vec![$(related_key($T.borrow()),)+]
402 }
403 }
404 };
405}
406
407impl_for_all_tuples!(impl_attach_input_tuple);
408
409pub type ManyToManyValues<Pivot, ParentMeta, RelatedMeta, ParentKey, RelatedKey> = (
410 expression::Binary<expression::op::Eq, expression::Column<Pivot, ParentMeta>, ParentKey>,
411 expression::Binary<expression::op::Eq, expression::Column<Pivot, RelatedMeta>, RelatedKey>,
412);
413
414pub type MorphToManyValues<Pivot, ParentMeta, RelatedMeta, ParentKey, RelatedKey> = (
415 expression::Binary<expression::op::Eq, expression::Column<Pivot, ParentMeta>, ParentKey>,
416 expression::Binary<expression::op::Eq, expression::Column<Pivot, Text>, &'static str>,
417 expression::Binary<expression::op::Eq, expression::Column<Pivot, RelatedMeta>, RelatedKey>,
418);
419
420pub(crate) fn build_many_to_many_values<
421 Pivot: Qrafting,
422 ParentMeta: TypeMeta + Comparable + Nullability,
423 RelatedMeta: TypeMeta + Comparable + Nullability,
424 ParentKey,
425 RelatedKey,
426>(
427 parent_column: expression::Column<Pivot, ParentMeta>,
428 related_column: expression::Column<Pivot, RelatedMeta>,
429 parent_key: &ParentKey,
430 related_keys: Vec<RelatedKey>,
431) -> Vec<ManyToManyValues<Pivot, ParentMeta, RelatedMeta, ParentKey, RelatedKey>>
432where
433 ParentKey: Clone + Compatible<ParentMeta>,
434 RelatedKey: Compatible<RelatedMeta>,
435 BinaryType<NullOf<ParentMeta>, NullOf<ParentMeta>>: PredicateType,
436 BinaryType<NullOf<RelatedMeta>, NullOf<RelatedMeta>>: PredicateType,
437{
438 let mut values = Vec::with_capacity(related_keys.len());
439 for related_key in related_keys {
440 values.push((
441 parent_column.eq(parent_key.clone()),
442 related_column.eq(related_key),
443 ));
444 }
445 values
446}
447
448pub(crate) fn build_morph_to_many_values<
449 Pivot: Qrafting,
450 ParentMeta: TypeMeta + Comparable + Nullability,
451 RelatedMeta: TypeMeta + Comparable + Nullability,
452 ParentKey,
453 RelatedKey,
454>(
455 spec: MorphToManyValueSpec<Pivot, ParentMeta, RelatedMeta, ParentKey, RelatedKey>,
456) -> Vec<MorphToManyValues<Pivot, ParentMeta, RelatedMeta, ParentKey, RelatedKey>>
457where
458 ParentKey: Clone + Compatible<ParentMeta>,
459 RelatedKey: Compatible<RelatedMeta>,
460 BinaryType<NullOf<ParentMeta>, NullOf<ParentMeta>>: PredicateType,
461 BinaryType<NullOf<RelatedMeta>, NullOf<RelatedMeta>>: PredicateType,
462{
463 let MorphToManyValueSpec {
464 parent_column,
465 type_column,
466 related_column,
467 parent_key,
468 morph_type,
469 related_keys,
470 } = spec;
471 let mut values = Vec::with_capacity(related_keys.len());
472 for related_key in related_keys {
473 values.push((
474 parent_column.eq(parent_key.clone()),
475 type_column.eq(morph_type),
476 related_column.eq(related_key),
477 ));
478 }
479 values
480}
481
482pub(crate) struct MorphToManyValueSpec<
483 Pivot: Qrafting,
484 ParentMeta: TypeMeta + Comparable + Nullability,
485 RelatedMeta: TypeMeta + Comparable + Nullability,
486 ParentKey,
487 RelatedKey,
488> {
489 pub(crate) parent_column: expression::Column<Pivot, ParentMeta>,
490 pub(crate) type_column: expression::Column<Pivot, Text>,
491 pub(crate) related_column: expression::Column<Pivot, RelatedMeta>,
492 pub(crate) parent_key: ParentKey,
493 pub(crate) morph_type: &'static str,
494 pub(crate) related_keys: Vec<RelatedKey>,
495}
496
497pub struct AttachBelongsToMany<
498 Pivot,
499 ParentMeta: TypeMeta,
500 RelatedMeta: TypeMeta,
501 ParentKey,
502 RelatedKey,
503> {
504 pivot_table: query::Table<Pivot>,
505 parent_column: expression::Column<Pivot, ParentMeta>,
506 related_column: expression::Column<Pivot, RelatedMeta>,
507 parent_key: ParentKey,
508 related_keys: Vec<RelatedKey>,
509}
510
511pub struct AttachMorphToMany<
512 Pivot,
513 ParentMeta: TypeMeta,
514 RelatedMeta: TypeMeta,
515 ParentKey,
516 RelatedKey,
517> {
518 pivot_table: query::Table<Pivot>,
519 parent_column: expression::Column<Pivot, ParentMeta>,
520 type_column: expression::Column<Pivot, Text>,
521 related_column: expression::Column<Pivot, RelatedMeta>,
522 parent_key: ParentKey,
523 morph_type: &'static str,
524 related_keys: Vec<RelatedKey>,
525}
526
527pub struct SyncBelongsToMany<
529 Pivot,
530 ParentMeta: TypeMeta,
531 RelatedMeta: TypeMeta,
532 ParentKey,
533 RelatedKey,
534> {
535 pivot_table: query::Table<Pivot>,
536 parent_column: expression::Column<Pivot, ParentMeta>,
537 related_column: expression::Column<Pivot, RelatedMeta>,
538 parent_key: ParentKey,
539 related_keys: Vec<RelatedKey>,
540}
541
542pub struct SyncMorphToMany<
543 Pivot,
544 ParentMeta: TypeMeta,
545 RelatedMeta: TypeMeta,
546 ParentKey,
547 RelatedKey,
548> {
549 pivot_table: query::Table<Pivot>,
550 parent_column: expression::Column<Pivot, ParentMeta>,
551 type_column: expression::Column<Pivot, Text>,
552 related_column: expression::Column<Pivot, RelatedMeta>,
553 parent_key: ParentKey,
554 morph_type: &'static str,
555 related_keys: Vec<RelatedKey>,
556}
557
558pub struct ToggleBelongsToMany<
560 Pivot,
561 ParentMeta: TypeMeta,
562 RelatedMeta: TypeMeta,
563 ParentKey,
564 RelatedKey,
565> {
566 pivot_table: query::Table<Pivot>,
567 parent_column: expression::Column<Pivot, ParentMeta>,
568 related_column: expression::Column<Pivot, RelatedMeta>,
569 parent_key: ParentKey,
570 related_keys: Vec<RelatedKey>,
571}
572
573pub struct ToggleMorphToMany<
574 Pivot,
575 ParentMeta: TypeMeta,
576 RelatedMeta: TypeMeta,
577 ParentKey,
578 RelatedKey,
579> {
580 pivot_table: query::Table<Pivot>,
581 parent_column: expression::Column<Pivot, ParentMeta>,
582 type_column: expression::Column<Pivot, Text>,
583 related_column: expression::Column<Pivot, RelatedMeta>,
584 parent_key: ParentKey,
585 morph_type: &'static str,
586 related_keys: Vec<RelatedKey>,
587}
588
589pub struct SyncWithoutDetachingBelongsToMany<
591 Pivot,
592 ParentMeta: TypeMeta,
593 RelatedMeta: TypeMeta,
594 ParentKey,
595 RelatedKey,
596> {
597 pivot_table: query::Table<Pivot>,
598 parent_column: expression::Column<Pivot, ParentMeta>,
599 related_column: expression::Column<Pivot, RelatedMeta>,
600 parent_key: ParentKey,
601 related_keys: Vec<RelatedKey>,
602}
603
604pub struct SyncWithoutDetachingMorphToMany<
605 Pivot,
606 ParentMeta: TypeMeta,
607 RelatedMeta: TypeMeta,
608 ParentKey,
609 RelatedKey,
610> {
611 pivot_table: query::Table<Pivot>,
612 parent_column: expression::Column<Pivot, ParentMeta>,
613 type_column: expression::Column<Pivot, Text>,
614 related_column: expression::Column<Pivot, RelatedMeta>,
615 parent_key: ParentKey,
616 morph_type: &'static str,
617 related_keys: Vec<RelatedKey>,
618}
619
620impl<
621 Pivot,
622 ParentMeta: TypeMeta + Comparable + Nullability,
623 RelatedMeta: TypeMeta + Comparable + Nullability,
624 ParentKey,
625 RelatedKey,
626> AttachBelongsToMany<Pivot, ParentMeta, RelatedMeta, ParentKey, RelatedKey>
627{
628 pub fn related_keys(&self) -> &[RelatedKey] {
629 &self.related_keys
630 }
631
632 pub fn insert_for(&self, related_key: &RelatedKey) -> builder::Insert<Pivot>
633 where
634 Pivot: Qrafting,
635 ParentKey: Clone + Compatible<ParentMeta>,
636 RelatedKey: Clone + Compatible<RelatedMeta>,
637 BinaryType<NullOf<ParentMeta>, NullOf<ParentMeta>>: PredicateType,
638 BinaryType<NullOf<RelatedMeta>, NullOf<RelatedMeta>>: PredicateType,
639 {
640 insert_into(self.pivot_table)
641 .values((
642 self.parent_column.eq(self.parent_key.clone()),
643 self.related_column.eq(related_key.clone()),
644 ))
645 .no_returning()
646 }
647
648 pub fn insert_many(&self, related_keys: Vec<RelatedKey>) -> builder::Insert<Pivot>
649 where
650 Pivot: Qrafting,
651 ParentKey: Clone + Compatible<ParentMeta>,
652 RelatedKey: Clone + Compatible<RelatedMeta>,
653 BinaryType<NullOf<ParentMeta>, NullOf<ParentMeta>>: PredicateType,
654 BinaryType<NullOf<RelatedMeta>, NullOf<RelatedMeta>>: PredicateType,
655 {
656 let values = build_many_to_many_values(
657 self.parent_column,
658 self.related_column,
659 &self.parent_key,
660 related_keys,
661 );
662
663 insert_into(self.pivot_table).values(values).no_returning()
664 }
665}
666
667impl<
668 Pivot,
669 ParentMeta: TypeMeta + Comparable + Nullability,
670 RelatedMeta: TypeMeta + Comparable + Nullability,
671 ParentKey,
672 RelatedKey,
673> AttachMorphToMany<Pivot, ParentMeta, RelatedMeta, ParentKey, RelatedKey>
674{
675 pub fn related_keys(&self) -> &[RelatedKey] {
676 &self.related_keys
677 }
678
679 pub fn insert_for(&self, related_key: &RelatedKey) -> builder::Insert<Pivot>
680 where
681 Pivot: Qrafting,
682 ParentKey: Clone + Compatible<ParentMeta>,
683 RelatedKey: Clone + Compatible<RelatedMeta>,
684 BinaryType<NullOf<ParentMeta>, NullOf<ParentMeta>>: PredicateType,
685 BinaryType<NullOf<RelatedMeta>, NullOf<RelatedMeta>>: PredicateType,
686 {
687 insert_into(self.pivot_table)
688 .values((
689 self.parent_column.eq(self.parent_key.clone()),
690 self.type_column.eq(self.morph_type),
691 self.related_column.eq(related_key.clone()),
692 ))
693 .no_returning()
694 }
695
696 pub fn insert_many(&self, related_keys: Vec<RelatedKey>) -> builder::Insert<Pivot>
697 where
698 Pivot: Qrafting,
699 ParentKey: Clone + Compatible<ParentMeta>,
700 RelatedKey: Clone + Compatible<RelatedMeta>,
701 BinaryType<NullOf<ParentMeta>, NullOf<ParentMeta>>: PredicateType,
702 BinaryType<NullOf<RelatedMeta>, NullOf<RelatedMeta>>: PredicateType,
703 {
704 let values = build_morph_to_many_values(MorphToManyValueSpec {
705 parent_column: self.parent_column,
706 type_column: self.type_column,
707 related_column: self.related_column,
708 parent_key: self.parent_key.clone(),
709 morph_type: self.morph_type,
710 related_keys,
711 });
712
713 insert_into(self.pivot_table).values(values).no_returning()
714 }
715}
716
717impl<
718 Pivot: Qrafting,
719 ParentMeta: Comparable + Nullability,
720 RelatedMeta: Comparable + Nullability,
721 ParentKey,
722 RelatedKey,
723> SyncBelongsToMany<Pivot, ParentMeta, RelatedMeta, ParentKey, RelatedKey>
724where
725 BinaryType<NullOf<ParentMeta>, NullOf<ParentMeta>>: PredicateType,
726 BinaryType<NullOf<RelatedMeta>, NullOf<RelatedMeta>>: PredicateType,
727{
728 pub fn existing_query(&self) -> QueryOf<RelatedKey>
729 where
730 Pivot: Qrafting,
731 RelatedKey: FromRow + LowerCompatible<RelatedMeta>,
732 ParentKey: Clone + LowerCompatible<ParentMeta>,
733 {
734 Query::from(self.pivot_table)
735 .select(self.related_column)
736 .filter(self.parent_column.eq(self.parent_key.clone()))
737 .typed::<RelatedKey>()
738 }
739
740 pub fn desired_keys(&self) -> &[RelatedKey] {
741 &self.related_keys
742 }
743
744 pub fn attach_insert(&self, related_key: &RelatedKey) -> builder::Insert<Pivot>
745 where
746 ParentKey: Clone + Compatible<ParentMeta>,
747 RelatedKey: Clone + Compatible<RelatedMeta>,
748 {
749 insert_into(self.pivot_table)
750 .values((
751 self.parent_column.eq(self.parent_key.clone()),
752 self.related_column.eq(related_key.clone()),
753 ))
754 .no_returning()
755 }
756
757 pub fn attach_insert_many(&self, related_keys: Vec<RelatedKey>) -> builder::Insert<Pivot>
758 where
759 ParentKey: Clone + Compatible<ParentMeta>,
760 RelatedKey: Clone + Compatible<RelatedMeta>,
761 {
762 let values = build_many_to_many_values(
763 self.parent_column,
764 self.related_column,
765 &self.parent_key,
766 related_keys,
767 );
768
769 insert_into(self.pivot_table).values(values).no_returning()
770 }
771
772 pub fn detach_query(&self, related_key: &RelatedKey) -> builder::Delete<Pivot>
773 where
774 ParentKey: Clone + LowerCompatible<ParentMeta>,
775 RelatedKey: Clone + LowerCompatible<RelatedMeta>,
776 {
777 builder::delete::delete_from(self.pivot_table)
778 .filter(self.parent_column.eq(self.parent_key.clone()))
779 .filter(self.related_column.eq(related_key.clone()))
780 }
781
782 pub fn detach_query_many(&self, related_keys: Vec<RelatedKey>) -> builder::Delete<Pivot>
783 where
784 ParentKey: Clone + LowerCompatible<ParentMeta>,
785 RelatedKey: Clone + LowerCompatible<RelatedMeta>,
786 UnaryType<NullOf<RelatedMeta>>: PredicateType,
787 {
788 builder::delete::delete_from(self.pivot_table)
789 .filter(self.parent_column.eq(self.parent_key.clone()))
790 .filter(self.related_column.in_(related_keys))
791 }
792}
793
794impl<
795 Pivot: Qrafting,
796 ParentMeta: Comparable + Nullability,
797 RelatedMeta: Comparable + Nullability,
798 ParentKey,
799 RelatedKey,
800> SyncMorphToMany<Pivot, ParentMeta, RelatedMeta, ParentKey, RelatedKey>
801where
802 BinaryType<NullOf<ParentMeta>, NullOf<ParentMeta>>: PredicateType,
803 BinaryType<NullOf<RelatedMeta>, NullOf<RelatedMeta>>: PredicateType,
804{
805 pub fn existing_query(&self) -> QueryOf<RelatedKey>
806 where
807 Pivot: Qrafting,
808 RelatedKey: FromRow + LowerCompatible<RelatedMeta>,
809 ParentKey: Clone + LowerCompatible<ParentMeta>,
810 {
811 Query::from(self.pivot_table)
812 .select(self.related_column)
813 .filter(self.parent_column.eq(self.parent_key.clone()))
814 .filter(self.type_column.eq(self.morph_type))
815 .typed::<RelatedKey>()
816 }
817
818 pub fn desired_keys(&self) -> &[RelatedKey] {
819 &self.related_keys
820 }
821
822 pub fn attach_insert(&self, related_key: &RelatedKey) -> builder::Insert<Pivot>
823 where
824 ParentKey: Clone + Compatible<ParentMeta>,
825 RelatedKey: Clone + Compatible<RelatedMeta>,
826 {
827 insert_into(self.pivot_table)
828 .values((
829 self.parent_column.eq(self.parent_key.clone()),
830 self.type_column.eq(self.morph_type),
831 self.related_column.eq(related_key.clone()),
832 ))
833 .no_returning()
834 }
835
836 pub fn attach_insert_many(&self, related_keys: Vec<RelatedKey>) -> builder::Insert<Pivot>
837 where
838 ParentKey: Clone + Compatible<ParentMeta>,
839 RelatedKey: Clone + Compatible<RelatedMeta>,
840 {
841 let values = build_morph_to_many_values(MorphToManyValueSpec {
842 parent_column: self.parent_column,
843 type_column: self.type_column,
844 related_column: self.related_column,
845 parent_key: self.parent_key.clone(),
846 morph_type: self.morph_type,
847 related_keys,
848 });
849
850 insert_into(self.pivot_table).values(values).no_returning()
851 }
852
853 pub fn detach_query(&self, related_key: &RelatedKey) -> builder::Delete<Pivot>
854 where
855 ParentKey: Clone + LowerCompatible<ParentMeta>,
856 RelatedKey: Clone + LowerCompatible<RelatedMeta>,
857 {
858 builder::delete::delete_from(self.pivot_table)
859 .filter(self.parent_column.eq(self.parent_key.clone()))
860 .filter(self.type_column.eq(self.morph_type))
861 .filter(self.related_column.eq(related_key.clone()))
862 }
863
864 pub fn detach_query_many(&self, related_keys: Vec<RelatedKey>) -> builder::Delete<Pivot>
865 where
866 ParentKey: Clone + LowerCompatible<ParentMeta>,
867 RelatedKey: Clone + LowerCompatible<RelatedMeta>,
868 UnaryType<NullOf<RelatedMeta>>: PredicateType,
869 {
870 builder::delete::delete_from(self.pivot_table)
871 .filter(self.parent_column.eq(self.parent_key.clone()))
872 .filter(self.type_column.eq(self.morph_type))
873 .filter(self.related_column.in_(related_keys))
874 }
875}
876
877macro_rules! impl_many_to_many_action_helpers {
878 ($name:ident) => {
879 impl<
880 Pivot: Qrafting,
881 ParentMeta: Comparable + Nullability,
882 RelatedMeta: Comparable + Nullability,
883 ParentKey,
884 RelatedKey,
885 > $name<Pivot, ParentMeta, RelatedMeta, ParentKey, RelatedKey>
886 where
887 BinaryType<NullOf<ParentMeta>, NullOf<ParentMeta>>: PredicateType,
888 BinaryType<NullOf<RelatedMeta>, NullOf<RelatedMeta>>: PredicateType,
889 {
890 pub fn existing_query(&self) -> QueryOf<RelatedKey>
891 where
892 Pivot: Qrafting,
893 RelatedKey: FromRow + LowerCompatible<RelatedMeta>,
894 ParentKey: Clone + LowerCompatible<ParentMeta>,
895 {
896 Query::from(self.pivot_table)
897 .select(self.related_column)
898 .filter(self.parent_column.eq(self.parent_key.clone()))
899 .typed::<RelatedKey>()
900 }
901
902 pub fn desired_keys(&self) -> &[RelatedKey] {
903 &self.related_keys
904 }
905
906 pub fn attach_insert(&self, related_key: &RelatedKey) -> builder::Insert<Pivot>
907 where
908 ParentKey: Clone + Compatible<ParentMeta>,
909 RelatedKey: Clone + Compatible<RelatedMeta>,
910 {
911 insert_into(self.pivot_table)
912 .values((
913 self.parent_column.eq(self.parent_key.clone()),
914 self.related_column.eq(related_key.clone()),
915 ))
916 .no_returning()
917 }
918
919 pub fn detach_query(&self, related_key: &RelatedKey) -> builder::Delete<Pivot>
920 where
921 ParentKey: Clone + LowerCompatible<ParentMeta>,
922 RelatedKey: Clone + LowerCompatible<RelatedMeta>,
923 {
924 builder::delete::delete_from(self.pivot_table)
925 .filter(self.parent_column.eq(self.parent_key.clone()))
926 .filter(self.related_column.eq(related_key.clone()))
927 }
928
929 pub fn attach_insert_many(
930 &self,
931 related_keys: Vec<RelatedKey>,
932 ) -> builder::Insert<Pivot>
933 where
934 ParentKey: Clone + Compatible<ParentMeta>,
935 RelatedKey: Clone + Compatible<RelatedMeta>,
936 {
937 let values = build_many_to_many_values(
938 self.parent_column,
939 self.related_column,
940 &self.parent_key,
941 related_keys,
942 );
943
944 insert_into(self.pivot_table).values(values).no_returning()
945 }
946
947 pub fn detach_query_many(&self, related_keys: Vec<RelatedKey>) -> builder::Delete<Pivot>
948 where
949 ParentKey: Clone + LowerCompatible<ParentMeta>,
950 RelatedKey: Clone + LowerCompatible<RelatedMeta>,
951 UnaryType<NullOf<RelatedMeta>>: PredicateType,
952 {
953 builder::delete::delete_from(self.pivot_table)
954 .filter(self.parent_column.eq(self.parent_key.clone()))
955 .filter(self.related_column.in_(related_keys))
956 }
957 }
958 };
959}
960
961impl_many_to_many_action_helpers!(ToggleBelongsToMany);
962impl_many_to_many_action_helpers!(SyncWithoutDetachingBelongsToMany);
963
964macro_rules! impl_morph_to_many_action_helpers {
965 ($name:ident) => {
966 impl<
967 Pivot: Qrafting,
968 ParentMeta: Comparable + Nullability,
969 RelatedMeta: Comparable + Nullability,
970 ParentKey,
971 RelatedKey,
972 > $name<Pivot, ParentMeta, RelatedMeta, ParentKey, RelatedKey>
973 where
974 BinaryType<NullOf<ParentMeta>, NullOf<ParentMeta>>: PredicateType,
975 BinaryType<NullOf<RelatedMeta>, NullOf<RelatedMeta>>: PredicateType,
976 {
977 pub fn existing_query(&self) -> QueryOf<RelatedKey>
978 where
979 Pivot: Qrafting,
980 RelatedKey: FromRow + LowerCompatible<RelatedMeta>,
981 ParentKey: Clone + LowerCompatible<ParentMeta>,
982 {
983 Query::from(self.pivot_table)
984 .select(self.related_column)
985 .filter(self.parent_column.eq(self.parent_key.clone()))
986 .filter(self.type_column.eq(self.morph_type))
987 .typed::<RelatedKey>()
988 }
989
990 pub fn desired_keys(&self) -> &[RelatedKey] {
991 &self.related_keys
992 }
993
994 pub fn attach_insert(&self, related_key: &RelatedKey) -> builder::Insert<Pivot>
995 where
996 ParentKey: Clone + Compatible<ParentMeta>,
997 RelatedKey: Clone + Compatible<RelatedMeta>,
998 {
999 insert_into(self.pivot_table)
1000 .values((
1001 self.parent_column.eq(self.parent_key.clone()),
1002 self.type_column.eq(self.morph_type),
1003 self.related_column.eq(related_key.clone()),
1004 ))
1005 .no_returning()
1006 }
1007
1008 pub fn detach_query(&self, related_key: &RelatedKey) -> builder::Delete<Pivot>
1009 where
1010 ParentKey: Clone + LowerCompatible<ParentMeta>,
1011 RelatedKey: Clone + LowerCompatible<RelatedMeta>,
1012 {
1013 builder::delete::delete_from(self.pivot_table)
1014 .filter(self.parent_column.eq(self.parent_key.clone()))
1015 .filter(self.type_column.eq(self.morph_type))
1016 .filter(self.related_column.eq(related_key.clone()))
1017 }
1018
1019 pub fn attach_insert_many(
1020 &self,
1021 related_keys: Vec<RelatedKey>,
1022 ) -> builder::Insert<Pivot>
1023 where
1024 ParentKey: Clone + Compatible<ParentMeta>,
1025 RelatedKey: Clone + Compatible<RelatedMeta>,
1026 {
1027 let values = build_morph_to_many_values(MorphToManyValueSpec {
1028 parent_column: self.parent_column,
1029 type_column: self.type_column,
1030 related_column: self.related_column,
1031 parent_key: self.parent_key.clone(),
1032 morph_type: self.morph_type,
1033 related_keys,
1034 });
1035
1036 insert_into(self.pivot_table).values(values).no_returning()
1037 }
1038
1039 pub fn detach_query_many(&self, related_keys: Vec<RelatedKey>) -> builder::Delete<Pivot>
1040 where
1041 ParentKey: Clone + LowerCompatible<ParentMeta>,
1042 RelatedKey: Clone + LowerCompatible<RelatedMeta>,
1043 UnaryType<NullOf<RelatedMeta>>: PredicateType,
1044 {
1045 builder::delete::delete_from(self.pivot_table)
1046 .filter(self.parent_column.eq(self.parent_key.clone()))
1047 .filter(self.type_column.eq(self.morph_type))
1048 .filter(self.related_column.in_(related_keys))
1049 }
1050 }
1051 };
1052}
1053
1054impl_morph_to_many_action_helpers!(ToggleMorphToMany);
1055impl_morph_to_many_action_helpers!(SyncWithoutDetachingMorphToMany);
1056
1057pub type BoxDynError = Box<dyn ::std::error::Error + 'static + Send + Sync>;
1059
1060pub struct Unset;
1062pub struct Set;
1064
1065#[cfg(test)]
1066mod tests {
1067 use crate::{BigInt, FromRow, Nullable, Qrafting, Text, expression::Column, query::Table};
1068
1069 #[allow(dead_code)]
1070 #[derive(Debug)]
1071 pub struct User {
1072 pub id: i64,
1073 pub name: Option<String>,
1074 pub username: String,
1075 }
1076
1077 impl FromRow for User {
1078 fn from_row(row: &crate::quex::Row) -> crate::quex::Result<Self> {
1079 Ok(Self {
1080 id: row.get("id")?,
1081 name: row.get("name")?,
1082 username: row.get("username")?,
1083 })
1084 }
1085 }
1086
1087 impl Qrafting for User {
1088 type Schema = ();
1089 type QueryPolicy = crate::DefaultQueryPolicy<Self>;
1090 const FIELD_COUNT: usize = 3;
1091 const TABLE: &'static str = "users";
1092 }
1093
1094 #[allow(non_upper_case_globals)]
1095 pub const table: Table<User> = Table::new("users");
1096 #[allow(non_upper_case_globals)]
1097 pub const id: Column<User, BigInt> = Column::new("id");
1098 #[allow(non_upper_case_globals)]
1099 pub const name: Column<User, Nullable<Text>> = Column::new("name");
1100 #[allow(non_upper_case_globals)]
1101 pub const username: Column<User, Text> = Column::new("username");
1102}