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 — 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 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 relates the two — the
same gap GROUP BY has. Sorting a distinct query by a column it
doesn’t select renders SQL the database rejects, and count_sql
won’t show it, since a total drops the ORDER BY. Relating them
would mean carrying “is distinct” in Select’s type and taking sort
keys by identity (SetOp::order_by_column’s shape) — a type
parameter through every builder signature for one clause.
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 — 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 — and 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 — every clause it takes is the
one Select already has — carrying this query’s scope as its
Outer, which is what exists reports.
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.