Skip to main content

queryweave_sql/
target.rs

1//! The queries a model's data is written into.
2//!
3//! [`Columns`]' methods check, at compile time, that every field of a model
4//! has a column on the entity, then hand the data and the entity's column
5//! mapping to the query being built: a *target*, implementing one trait per
6//! clause it can take. The derives' generated code is generic over these
7//! traits, so it names no query builder, and a target decides how the clause
8//! is written (sqlx's `QueryBuilder`, with the `sqlx` feature, appends SQL
9//! text and binds the values; sea-query's statements, with the `sea-query`
10//! feature, add expressions; the public helpers of this crate, such as
11//! `like_pattern` and `page_offset`, write it for a target of your own).
12//!
13//! The `write_*` methods do not check the columns themselves: call them
14//! through the entity's `Columns` methods (or the wrappers'
15//! `append_to_query`), which do.
16
17use crate::Columns;
18#[cfg(feature = "merge-patch")]
19use queryweave::FieldValues;
20use queryweave::{Conditions, SortKeys};
21
22/// How conditions are joined: every one must hold (`AND`), or any (`OR`).
23#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
24pub enum Junction {
25    /// Every condition must hold: `… AND …`.
26    And,
27    /// Any condition may hold: `… OR …`.
28    Or,
29}
30
31/// A query that filter conditions can be written into: a `WHERE` clause.
32#[diagnostic::on_unimplemented(
33    message = "`{Self}` is not a query `queryweave-sql` can write conditions into",
34    label = "not a `ConditionsTarget`",
35    note = "enable the `queryweave-sql` feature of your query builder: `sqlx` (on by default) for sqlx's `QueryBuilder`, `sea-query` for sea-query's (and SeaORM's) statements"
36)]
37pub trait ConditionsTarget {
38    /// Start a `WHERE` clause, before its conditions.
39    fn write_where(&mut self);
40
41    /// Write the conditions of the model `M`, joined by `junction`, each
42    /// comparing the column `C` stores its domain field in.
43    ///
44    /// Values are bound with their own SQL type; the `LIKE` operators bind an
45    /// escaped pattern (`… LIKE ? ESCAPE '!'`), so user input matches
46    /// literally.
47    fn write_conditions<C: Columns + ?Sized, M>(
48        &mut self,
49        conditions: Conditions<M>,
50        junction: Junction,
51    );
52}
53
54/// A query that sort keys can be written into: an `ORDER BY` clause.
55#[diagnostic::on_unimplemented(
56    message = "`{Self}` is not a query `queryweave-sql` can write an `ORDER BY` into",
57    label = "not an `OrderByTarget`",
58    note = "enable the `queryweave-sql` feature of your query builder: `sqlx` (on by default) for sqlx's `QueryBuilder`, `sea-query` for sea-query's (and SeaORM's) statements"
59)]
60pub trait OrderByTarget {
61    /// Write an `ORDER BY column direction, …` clause for the sort keys of the
62    /// model `M`, in order, each by the column `C` stores its domain field
63    /// in; nothing when there are none.
64    fn write_order_by<C: Columns + ?Sized, M>(&mut self, sort_keys: SortKeys<M>);
65}
66
67/// A query that a page can be written into: `LIMIT` and `OFFSET`.
68#[diagnostic::on_unimplemented(
69    message = "`{Self}` is not a query `queryweave-sql` can write a page into",
70    label = "not a `PageTarget`",
71    note = "enable the `queryweave-sql` feature of your query builder: `sqlx` (on by default) for sqlx's `QueryBuilder`, `sea-query` for sea-query's (and SeaORM's) statements"
72)]
73pub trait PageTarget {
74    /// Write a `LIMIT page_size OFFSET page * page_size` clause (`page` 0
75    /// based) when both a page and a page size are requested; nothing
76    /// otherwise.
77    fn write_page(&mut self, page: Option<u32>, page_size: Option<u32>);
78}
79
80/// A query that merge-patch writes can be written into: the assignments of an
81/// `UPDATE … SET`.
82#[cfg(feature = "merge-patch")]
83#[diagnostic::on_unimplemented(
84    message = "`{Self}` is not a query `queryweave-sql` can write assignments into",
85    label = "not an `AssignmentsTarget`",
86    note = "enable the `queryweave-sql` feature of your query builder: `sqlx` (on by default) for sqlx's `QueryBuilder`, `sea-query` for sea-query's (and SeaORM's) statements"
87)]
88pub trait AssignmentsTarget {
89    /// What writing the assignments returns, to add more of them (for sqlx,
90    /// the comma-separated builder).
91    type Assignments<'target>
92    where
93        Self: 'target;
94
95    /// Write `column = value` assignments of the model `M`, each to the column
96    /// `C` stores its domain field in.
97    fn write_assignments<C: Columns + ?Sized, M>(
98        &mut self,
99        assignments: FieldValues<M>,
100    ) -> Self::Assignments<'_>;
101}