pub struct Select<D, Scope, Sel, Outer = Nil> { /* private fields */ }Expand description
A SELECT. Outer is the scope this query was built against: Nil
for a query of its own, and the outer query’s scope for one started by
.correlated(..), which is what lets EXISTS report the outer tables it
references. Defaulted, so a query that isn’t a subquery never spells it.
Implementations§
Source§impl<D, Scope, Sel> Select<D, Scope, Sel>
impl<D, Scope, Sel> Select<D, Scope, Sel>
Sourcepub fn prepare<Params, Idx>(
&self,
_dialect: D,
) -> Prepared<D, Params, Sel::Output>
pub fn prepare<Params, Idx>( &self, _dialect: D, ) -> Prepared<D, Params, Sel::Output>
Renders this query once, leaving its Value::Placeholder slots
unresolved. Output is captured here, as .erase() does for
DynSelect, so the execution layer can decode rows without Sel
(and therefore Scope) still being around.
Sourcepub fn prepare_count<Params, Idx>(
&self,
_dialect: D,
) -> Prepared<D, Params, Total>
pub fn prepare_count<Params, Idx>( &self, _dialect: D, ) -> Prepared<D, Params, Total>
The same query prepared as its own total, meaning count_sql with
the placeholders still unresolved, so a paginated endpoint reuses one
rendering for the page and one for the count. Total rather than
i64: what a statement produces is what decides how it is run, and a
total is a number, not a row.
Source§impl<D: Dialect, Scope, Sel> Select<D, Scope, Sel>
impl<D: Dialect, Scope, Sel> Select<D, Scope, Sel>
Sourcepub fn union<ScopeB, SelB, IdxA, IdxB>(
&self,
other: &Select<D, ScopeB, SelB>,
) -> SetOp<D, Sel::Output>
pub fn union<ScopeB, SelB, IdxA, IdxB>( &self, other: &Select<D, ScopeB, SelB>, ) -> SetOp<D, Sel::Output>
Starts a UNION chain. See SetOp’s doc comment for why the two
branches only need matching Selection::Output, not matching
Scope.
pub fn union_all<ScopeB, SelB, IdxA, IdxB>( &self, other: &Select<D, ScopeB, SelB>, ) -> SetOp<D, Sel::Output>
pub fn intersect<ScopeB, SelB, IdxA, IdxB>( &self, other: &Select<D, ScopeB, SelB>, ) -> SetOp<D, Sel::Output>
pub fn except<ScopeB, SelB, IdxA, IdxB>( &self, other: &Select<D, ScopeB, SelB>, ) -> SetOp<D, Sel::Output>
Source§impl<D, Scope, Sel, Outer> Select<D, Scope, Sel, Outer>
impl<D, Scope, Sel, Outer> Select<D, Scope, Sel, Outer>
Sourcepub fn reselect<NewSel>(
self,
selection: NewSel,
) -> Select<D, Scope, NewSel, Outer>
pub fn reselect<NewSel>( self, selection: NewSel, ) -> Select<D, Scope, NewSel, Outer>
Swaps the selection list, keeping every clause. With Clone, this is
how one built-up query serves both a count and a page.
Sourcepub fn filter<C: Condition<D, Scope, Idxs>, Idxs>(self, cond: C) -> Self
pub fn filter<C: Condition<D, Scope, Idxs>, Idxs>(self, cond: C) -> Self
AND-folded, and callable any number of times (conditionally, in a
loop, from a helper) without changing Self’s type, so the most
common kind of dynamic query needs no escape hatch.
Sourcepub fn filter_all(
self,
conds: impl IntoIterator<Item = Predicate<D, Scope>>,
) -> Self
pub fn filter_all( self, conds: impl IntoIterator<Item = Predicate<D, Scope>>, ) -> Self
AND-folds a runtime-length collection of already-discharged
conditions, the shape a search form has, where the conditions come
from different tables and so can’t share one Expr type.
pub fn order_by<K: SortBy<Scope, Idxs>, Idxs>(self, key: K) -> Self
Sourcepub fn order_by_all(
self,
keys: impl IntoIterator<Item = SortKey<Scope>>,
) -> Self
pub fn order_by_all( self, keys: impl IntoIterator<Item = SortKey<Scope>>, ) -> Self
Appends a runtime-length collection of already-discharged sort keys,
the shape a ?sort= parameter has, where the keys name different
tables and so can’t share one OrderKey type.
Sourcepub fn order_by_selected<K, SelIdx, Idx, L>(self, _key: K, dir: SortDir) -> Self
pub fn order_by_selected<K, SelIdx, Idx, L>(self, _key: K, dir: SortDir) -> Self
.order_by(..), but the key also has to be in this query’s
selection. Sel::Output has to hold it, through the same row::Field
lookup Row::get and SetOp::order_by_column take, rather than the
key only being in scope. This is the exact rule SELECT DISTINCT
puts on a sort key (Postgres rejects one that isn’t selected), so
pairing this with .distinct() leaves that rejected SQL unwritable.
What gets rendered is the selected item the lookup landed on, for
the reason SetOp::order_by_column renders the ordinal rather than
the key it was handed: a key names a field, not an expression, and
two window functions over different frames share one. The index that
proves the lookup is the position that reads the item, so the check
and the rendered clause are one fact.
Known limitation: .reselect(..) afterwards keeps the clause and
drops the guarantee. Swap the selection before sorting by it.
Sourcepub fn order_by_selection<SelIdx>(self, dir: SortDir) -> Self
pub fn order_by_selection<SelIdx>(self, dir: SortDir) -> Self
.order_by_selected(..) for a single un-tupled selection
(select(users::email), not select((users::email,))): there is
exactly one selected column, so there is nothing to name. It has the
same shape SetOp’s single-column .order_by(dir) has, and the same
.reselect(..) caveat.
Sourcepub fn distinct(self) -> Self
pub fn distinct(self) -> Self
SELECT DISTINCT: one row per distinct selected tuple. The natural
answer to a one-to-many join that repeats its left side, and unlike a
GROUP BY of the whole selection it doesn’t have to be restated when
the selection changes. Idempotent: a query is distinct or it isn’t.
Known limitation: Postgres requires a SELECT DISTINCT’s sort
keys to be in its selection, and nothing here enforces that for
plain .order_by(..). Use .order_by_selected(..)/
.order_by_selection(..) instead, which check exactly this. GROUP BY has a related but different gap: every non-aggregated selected
column has to appear in it, which is the selection-into-GROUP BY
direction rather than the GROUP BY-into-selection one
row::Field can check, so it stays unchecked. count_sql won’t
show either problem, since a total drops the ORDER BY.
Sourcepub fn group_by<K: GroupBy<Scope, Idxs>, Idxs>(self, key: K) -> Self
pub fn group_by<K: GroupBy<Scope, Idxs>, Idxs>(self, key: K) -> Self
Appends one grouping key; callable multiple times like .filter()
(each call adds a column to the GROUP BY list, it doesn’t replace
it), for the same “dynamic composition without a type change” reason.
Sourcepub fn group_by_all(
self,
keys: impl IntoIterator<Item = Grouping<Scope>>,
) -> Self
pub fn group_by_all( self, keys: impl IntoIterator<Item = Grouping<Scope>>, ) -> Self
The same for a runtime-length collection of discharged grouping
keys, as order_by_all is to order_by.
Sourcepub fn having<C: Condition<D, Scope, Idxs>, Idxs>(self, cond: C) -> Self
pub fn having<C: Condition<D, Scope, Idxs>, Idxs>(self, cond: C) -> Self
A WHERE-shaped filter applied after grouping (aggregate
conditions), AND-folded across calls exactly like .filter().
Sourcepub fn having_all(
self,
conds: impl IntoIterator<Item = Predicate<D, Scope>>,
) -> Self
pub fn having_all( self, conds: impl IntoIterator<Item = Predicate<D, Scope>>, ) -> Self
The same for a runtime-length collection of discharged conditions,
as filter_all is to filter.
pub fn limit(self, n: impl IntoRowCount) -> Self
pub fn offset(self, n: impl IntoRowCount) -> Self
Sourcepub fn inner_join<S: JoinSource<D>, C, Idxs>(
self,
source: S,
on: C,
) -> Select<D, Cons<TableSlot<S::Table, NotNull>, Scope>, Sel, Outer>
pub fn inner_join<S: JoinSource<D>, C, Idxs>( self, source: S, on: C, ) -> Select<D, Cons<TableSlot<S::Table, NotNull>, Scope>, Sel, Outer>
The joined table is in scope for the ON condition, and so is
everything already joined. The scope the condition is discharged
against is the one the join produces, not the one it started from.
pub fn left_join<S: JoinSource<D>, C, Idxs>( self, source: S, on: C, ) -> Select<D, Cons<TableSlot<S::Table, MaybeNull>, Scope>, Sel, Outer>
Sourcepub fn right_join<S: JoinSource<D>, C, Idxs>(
self,
source: S,
on: C,
) -> Select<D, Cons<TableSlot<S::Table, NotNull>, Scope::Output>, Sel, Outer>where
D: SupportsRightJoin,
Scope: MapNullable,
C: Condition<D, Cons<TableSlot<S::Table, NotNull>, Scope::Output>, Idxs>,
pub fn right_join<S: JoinSource<D>, C, Idxs>(
self,
source: S,
on: C,
) -> Select<D, Cons<TableSlot<S::Table, NotNull>, Scope::Output>, Sel, Outer>where
D: SupportsRightJoin,
Scope: MapNullable,
C: Condition<D, Cons<TableSlot<S::Table, NotNull>, Scope::Output>, Idxs>,
RIGHT JOIN retroactively flips every already-joined table to
nullable (MapNullable) before adding the new, guaranteed-present
table, mirroring Drizzle’s AppendToNullabilityMap rule.
pub fn full_join<S: JoinSource<D>, C, Idxs>(
self,
source: S,
on: C,
) -> Select<D, Cons<TableSlot<S::Table, MaybeNull>, Scope::Output>, Sel, Outer>where
D: SupportsFullOuterJoin,
Scope: MapNullable,
C: Condition<D, Cons<TableSlot<S::Table, MaybeNull>, Scope::Output>, Idxs>,
Source§impl<D: Dialect, Scope, Sel> Select<D, Scope, Sel>
The terminal methods, and so only for a query of its own: a subquery
(Outer != Nil) references its outer query’s tables, and rendering one
on its own would name tables that aren’t in its FROM. It reaches SQL
through exists/not_exists instead.
impl<D: Dialect, Scope, Sel> Select<D, Scope, Sel>
The terminal methods, and so only for a query of its own: a subquery
(Outer != Nil) references its outer query’s tables, and rendering one
on its own would name tables that aren’t in its FROM. It reaches SQL
through exists/not_exists instead.
Sourcepub fn to_sql<Idx>(&self, _dialect: D) -> (String, Vec<Value>)where
Sel: Selection<Scope, Idx>,
pub fn to_sql<Idx>(&self, _dialect: D) -> (String, Vec<Value>)where
Sel: Selection<Scope, Idx>,
The terminal step, and the only point each selected column’s
scope-membership is checked. Membership is proven as a side effect of
Sel: Selection<Scope, Idx> type-checking at all.
The dialect is an argument rather than a turbofish, so a query that is rendered instead of executed says which SQL it wants in the one place that decides. Everything before it infers, the way a table or a column does.
Sourcepub fn count_sql<Idx>(&self, _dialect: D) -> (String, Vec<Value>)where
Sel: Selection<Scope, Idx>,
pub fn count_sql<Idx>(&self, _dialect: D) -> (String, Vec<Value>)where
Sel: Selection<Scope, Idx>,
How many rows this query would return, ignoring its
ORDER BY/LIMIT/OFFSET. A total is about what matches, not about
the page being shown. reselect(count()) keeps them, which is what
makes it the wrong tool for a paginated total.
A grouped query counts its groups, since that is what a page of it
would show, so the body becomes a subquery rather than having its
GROUP BY dropped or kept.
Source§impl<D, Scope, Sel, Outer> Select<D, Scope, Sel, Outer>
impl<D, Scope, Sel, Outer> Select<D, Scope, Sel, Outer>
Starts a correlated subquery: a fresh SELECT whose scope is
Cons<TableSlot<T, NotNull>, Scope>: the new table, prepended onto
this (outer) query’s entire scope. Because Find/Superset walk
the whole flat cons-list regardless of where it came from, the
subquery’s .filter() can reference both its own new table’s
columns and any outer column already in Scope, with no special
casing: growing the scope works the same whether the new table came
from a join or from a subquery’s FROM.
The result is an ordinary Select, carrying this query’s scope as
its Outer, which is what exists reports. Every clause it takes is
the one Select already has.
Source§impl<D: Dialect, Scope, Sel, Outer: ScopeTables> Select<D, Scope, Sel, Outer>
impl<D: Dialect, Scope, Sel, Outer: ScopeTables> Select<D, Scope, Sel, Outer>
Sourcepub fn exists<Idx>(&self) -> Exists<D, Outer::Tables>where
Sel: Selection<Scope, Idx>,
pub fn exists<Idx>(&self) -> Exists<D, Outer::Tables>where
Sel: Selection<Scope, Idx>,
EXISTS (<this query>), tagged with the outer tables it references
so it can only be filtered onto a query that has them in scope. Its
own column references were already checked against Scope when it
was built. On a query that isn’t a subquery, Outer is Nil and
this is an uncorrelated EXISTS.
pub fn not_exists<Idx>(&self) -> Exists<D, Outer::Tables>where
Sel: Selection<Scope, Idx>,
Sourcepub fn contains<Lhs, Idx>(
&self,
lhs: Lhs,
) -> InSubquery<D, <Outer::Tables as Concat<Lhs::Req>>::Output>
pub fn contains<Lhs, Idx>( &self, lhs: Lhs, ) -> InSubquery<D, <Outer::Tables as Concat<Lhs::Req>>::Output>
lhs IN (<this query>). This query selects exactly one column
(Sel: RowField, so a bare column, aggregate, or labelled one of
those, never a tuple), so its SQL type can be checked against lhs
the same way .eq(..) checks two columns: RowField::Sql carries
the marker a decoded Selection::Output has already resolved away.
Tagged with the outer tables lhs and this query’s own Outer
reference, so it can only be filtered onto a query that has both in
scope.
Known limitation: membership only. A scalar subquery
(col = (SELECT max(x) ..)) stays deferred. It would have to be an
Expr, which carries no dialect to pin the subquery’s capability
check to.