drizzle_core/builder.rs
1pub mod conflict;
2pub mod insert_select;
3pub mod states;
4
5pub use conflict::*;
6pub use insert_select::*;
7pub use states::*;
8
9/// Builder states whose query is complete and can be executed.
10///
11/// Dialect crates implement this for their builder state markers to allow
12/// execution, set operations, or prepared statements in those states.
13#[diagnostic::on_unimplemented(
14 message = "this query is not complete yet: `{Self}` cannot run",
15 label = "the query is still missing a clause",
16 note = "a DELETE or UPDATE must say which rows it changes with `.r#where(...)`; write \
17 `.r#where(true)` to change every row on purpose",
18 note = "a SELECT needs `.from(...)`, an INSERT needs `.values(...)`, and an UPDATE \
19 needs `.set(...)`"
20)]
21pub trait ExecutableState {}
22
23/// The state of a query builder before any statement has been started.
24#[derive(Debug, Clone)]
25pub struct BuilderInit;
26
27impl ExecutableState for BuilderInit {}
28
29// =============================================================================
30// Capability marker traits for typestate method gating
31// =============================================================================
32// These allow a single generic impl block per method instead of duplicating
33// across every state that supports it.
34//
35// Used directly by the inner `SelectBuilder` impls in driver crates.
36// Wrapper builders (`DrizzleBuilder`, `TransactionBuilder`) use a declarative
37// macro to stamp out per-state impls instead, because Rust's inherent impl
38// overlap rules prevent trait-gated generics when other builder types
39// (insert/update/delete) define methods with the same name.
40
41/// Clause markers for [`ClauseAllowed`].
42///
43/// Each marker names a builder method (or a use of a whole query). A builder
44/// state implements `ClauseAllowed<clause::X>` when that method may be called
45/// next.
46pub mod clause {
47 /// `.r#where()`.
48 #[derive(Debug, Clone, Copy, Default)]
49 pub struct Where;
50 /// `.group_by()`.
51 #[derive(Debug, Clone, Copy, Default)]
52 pub struct GroupBy;
53 /// `.having()` (requires GROUP BY).
54 #[derive(Debug, Clone, Copy, Default)]
55 pub struct Having;
56 /// `.order_by()`.
57 #[derive(Debug, Clone, Copy, Default)]
58 pub struct OrderBy;
59 /// `.limit()`.
60 #[derive(Debug, Clone, Copy, Default)]
61 pub struct Limit;
62 /// `.offset()`.
63 #[derive(Debug, Clone, Copy, Default)]
64 pub struct Offset;
65 /// `.join()` and its variants.
66 #[derive(Debug, Clone, Copy, Default)]
67 pub struct Join;
68 /// Use as a CTE or with a locking clause: a single SELECT that is not a
69 /// `UNION`/`INTERSECT`/`EXCEPT`.
70 #[derive(Debug, Clone, Copy, Default)]
71 pub struct Simple;
72 /// Operand of `UNION`/`INTERSECT`/`EXCEPT`: a SELECT, possibly compound,
73 /// without a locking clause.
74 #[derive(Debug, Clone, Copy, Default)]
75 pub struct Compound;
76 /// Row source for a derived table or `INSERT ... SELECT`: any completed
77 /// SELECT. Never an INSERT/UPDATE/DELETE, even with `RETURNING`.
78 #[derive(Debug, Clone, Copy, Default)]
79 pub struct Source;
80}
81
82/// The builder state `Self` allows the clause `Clause` next.
83///
84/// SELECT builders track their progress in a state type parameter. Clause
85/// methods require `State: ClauseAllowed<clause::X>`, so calling a clause
86/// out of order (`.group_by(...)` after `.limit(...)`, `.having(...)`
87/// without `.group_by(...)`) is a compile error:
88///
89/// ```text
90/// error[E0277]: builder state `SelectLimitSet` does not allow `drizzle_core::builder::clause::GroupBy`
91/// = note: SELECT clauses go in order: FROM, JOIN, WHERE, GROUP BY, HAVING, ORDER BY, LIMIT, OFFSET
92/// ```
93///
94/// The same check stops a statement that is not a SELECT (a
95/// `DELETE ... RETURNING`, say) from being used as a subquery, set operand,
96/// derived table, or `INSERT ... SELECT` source. Dialect crates implement
97/// this for their states and may add their own clause markers for
98/// dialect-only clauses. A few methods whose names clash with INSERT /
99/// UPDATE / DELETE methods (`.r#where`, `.order_by`) use a dialect-local
100/// trait with the same error message instead.
101///
102/// # Examples
103///
104/// ```
105/// use drizzle_core::{ClauseAllowed, clause};
106///
107/// struct AfterFrom;
108/// impl ClauseAllowed<clause::Where> for AfterFrom {}
109///
110/// fn where_<S: ClauseAllowed<clause::Where>>(_state: S) {}
111///
112/// where_(AfterFrom);
113/// ```
114///
115/// ```compile_fail
116/// # use drizzle_core::{ClauseAllowed, clause};
117/// # struct AfterLimit;
118/// fn where_<S: ClauseAllowed<clause::Where>>(_state: S) {}
119///
120/// // error: builder state `AfterLimit` does not allow `Where`
121/// where_(AfterLimit);
122/// ```
123#[diagnostic::on_unimplemented(
124 message = "builder state `{Self}` does not allow `{Clause}`",
125 label = "not available at this point of the query",
126 note = "SELECT clauses go in order: FROM, JOIN, WHERE, GROUP BY, HAVING, ORDER BY, LIMIT, OFFSET",
127 note = "only a SELECT can be a set operand, a subquery, a derived table, or an INSERT source"
128)]
129pub trait ClauseAllowed<Clause> {}