pub struct CounterCacheSpec<M: 'static> {Show 16 fields
pub child_table: &'static str,
pub child_pk: &'static str,
pub child_soft_delete: bool,
pub fk_column: &'static str,
pub parent_table: &'static str,
pub parent_pk: &'static str,
pub counter_column: &'static str,
pub fk_of: fn(&M) -> Option<i64>,
pub pk_of: fn(&M) -> i64,
pub live_of: fn(&M) -> bool,
pub tenant_column: Option<&'static str>,
pub tenant_of: Option<fn(&M) -> Option<String>>,
pub contrib_of: fn(&M) -> i64,
pub contrib_sql: &'static str,
pub filter_sql: &'static str,
pub derivation: Option<&'static DerivationDef>,
}Expand description
One counter-cached belongs_to leg, produced at compile time by #[model]
and consulted at run time by the child’s generated repository.
Framework plumbing; not constructed by hand.
Fields§
§child_table: &'static strThe child’s table, e.g. comments.
child_pk: &'static strThe child’s primary-key column, e.g. id.
child_soft_delete: boolWhether the child model carries a deleted_at column. When true the
count reflects live rows only: the decrement is scoped to a live
child (so a second soft delete moves nothing) and the recompute filters
soft-deleted rows out.
fk_column: &'static strThe child’s foreign-key column pointing at the parent, e.g. post_id.
parent_table: &'static strThe parent’s table, e.g. posts.
parent_pk: &'static strThe parent’s primary-key column, e.g. id.
counter_column: &'static strThe maintained column on the parent, e.g. comment_count.
fk_of: fn(&M) -> Option<i64>Reads this leg’s foreign key off a child record. None for a nullable
foreign key that is unset — an unparented child moves no counter.
pk_of: fn(&M) -> i64Reads the child’s own primary key off a record. Used by the bulk paths to match a post-update record back to the foreign keys captured for it before the update, and to scope the tenant predicate below.
live_of: fn(&M) -> boolWhether a record is live (not soft-deleted). Always true for a child
with no deleted_at column.
The generated update does not filter soft-deleted rows, so an
already-deleted child can be re-parented. It is counted by nobody, so
neither its old nor its new parent may move — without this the update
would decrement a parent that had already dropped it and increment one
for a dead row.
tenant_column: Option<&'static str>The tenant-discriminator column, from
#[belongs_to(…, counter_cache, counter_cache_tenant = "<column>")].
A counter update is a write to a row the caller only had to name the id
of, so on a shared multi-tenant table it has to be confined to the
caller’s own tenant — the same hazard #[votable]’s aggregate UPDATE
is scoped for. The predicate spells the invariant “the parent sits in the
same tenant as the child whose foreign key named it”, so both tables
must carry a column of this name. That is why it is explicit: #[model]
on the child cannot see the parent’s fields, and guessing would turn
every tenant-scoped child hanging off a global parent into a hard
column does not exist.
None (the default) emits no predicate anywhere, so a single-tenant
app’s SQL is byte-for-byte what it would be without this field.
tenant_of: Option<fn(&M) -> Option<String>>Reads the child’s tenant discriminator off a record, as text, the way
the database spells CAST(<tenant> AS TEXT).
Some only for a leg with a Self::tenant_column whose child model
carries that field as an integer or string. Then the pre-update capture
reads the old tenant too, and a child moved to another tenant takes its
contribution off the old parent under the old tenant: the live
predicate would look for the parent under the new one and miss it.
None keeps the leg’s SQL exactly as it was.
contrib_of: fn(&M) -> i64This row’s weight in the maintained aggregate. 0 excludes the row.
A plain counter cache returns 1 for every row; a #[derivation]
returns 0 when its filter rejects the row, and otherwise 1 (a count)
or the summed field’s value (a sum).
contrib_sql: &'static strThe SQL half of Self::contrib_of, for the set-based paths.
"1" for a counter cache, else a child column reference such as
{c}."score". {c} is the placeholder for whichever alias the statement
gives the child table.
filter_sql: &'static strThe derivation’s row filter, lowered to SQL and already prefixed with
AND so any builder can concatenate it.
"" for a counter cache, which is what keeps a counter cache’s
generated SQL byte-identical. Else AND (<pred>), using the same {c}
child-alias placeholder as Self::contrib_sql.
derivation: Option<&'static DerivationDef>The #[derivation] this spec maintains, or None for a plain counter
cache. It carries the metadata the backfill and status surfaces read.
Trait Implementations§
Source§impl<M: 'static> Clone for CounterCacheSpec<M>
impl<M: 'static> Clone for CounterCacheSpec<M>
impl<M: 'static> Copy for CounterCacheSpec<M>
Auto Trait Implementations§
impl<M> Freeze for CounterCacheSpec<M>
impl<M> RefUnwindSafe for CounterCacheSpec<M>where
fn(&M) -> Option<i64>: RefUnwindSafe,
fn(&M) -> i64: RefUnwindSafe,
fn(&M) -> bool: RefUnwindSafe,
Option<fn(&M) -> Option<String>>: RefUnwindSafe,
impl<M> Send for CounterCacheSpec<M>
impl<M> Sync for CounterCacheSpec<M>
impl<M> Unpin for CounterCacheSpec<M>
impl<M> UnsafeUnpin for CounterCacheSpec<M>where
fn(&M) -> Option<i64>: UnsafeUnpin,
fn(&M) -> i64: UnsafeUnpin,
fn(&M) -> bool: UnsafeUnpin,
Option<fn(&M) -> Option<String>>: UnsafeUnpin,
impl<M> UnwindSafe for CounterCacheSpec<M>where
fn(&M) -> Option<i64>: UnwindSafe,
fn(&M) -> i64: UnwindSafe,
fn(&M) -> bool: UnwindSafe,
Option<fn(&M) -> Option<String>>: UnwindSafe,
Blanket Implementations§
Source§impl<T> AggregateExpressionMethods for T
impl<T> AggregateExpressionMethods for T
Source§fn aggregate_distinct(self) -> Self::Outputwhere
Self: DistinctDsl,
fn aggregate_distinct(self) -> Self::Outputwhere
Self: DistinctDsl,
DISTINCT modifier for aggregate functions Read moreSource§fn aggregate_all(self) -> Self::Outputwhere
Self: AllDsl,
fn aggregate_all(self) -> Self::Outputwhere
Self: AllDsl,
ALL modifier for aggregate functions Read moreSource§fn aggregate_filter<P>(self, f: P) -> Self::Output
fn aggregate_filter<P>(self, f: P) -> Self::Output
Source§fn aggregate_order<O>(self, o: O) -> Self::Outputwhere
Self: OrderAggregateDsl<O>,
fn aggregate_order<O>(self, o: O) -> Self::Outputwhere
Self: OrderAggregateDsl<O>,
Source§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
Source§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
Source§impl<T> AutumnCounterCaches for Twhere
T: 'static,
impl<T> AutumnCounterCaches for Twhere
T: 'static,
Source§const HAS_COUNTER_CACHES: bool = false
const HAS_COUNTER_CACHES: bool = false
Source§fn counter_caches() -> &'static [CounterCacheSpec<Self>]
fn counter_caches() -> &'static [CounterCacheSpec<Self>]
Source§impl<T> AutumnDependents for Twhere
T: ?Sized,
impl<T> AutumnDependents for Twhere
T: ?Sized,
Source§fn dependents() -> &'static [RuntimeDependentSpec]
fn dependents() -> &'static [RuntimeDependentSpec]
#[model] overrides via an inherent shadow when dependents exist.Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be
downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further
downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSend for T
impl<T> DowncastSend for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoSql for T
impl<T> IntoSql for T
Source§fn into_sql<T>(self) -> Self::Expression
fn into_sql<T>(self) -> Self::Expression
self to an expression for Diesel’s query builder. Read moreSource§fn as_sql<'a, T>(&'a self) -> <&'a Self as AsExpression<T>>::Expression
fn as_sql<'a, T>(&'a self) -> <&'a Self as AsExpression<T>>::Expression
&self to an expression for Diesel’s query builder. Read moreSource§impl<T> Pointable for T
impl<T> Pointable for T
Source§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<T> RepositoryHooksClone for Twhere
T: Clone,
impl<T> RepositoryHooksClone for Twhere
T: Clone,
Source§fn autumn_clone(&self) -> T
fn autumn_clone(&self) -> T
Source§impl<T, Conn> RunQueryDsl<Conn> for T
impl<T, Conn> RunQueryDsl<Conn> for T
Source§fn execute<'conn, 'query>(
self,
conn: &'conn mut Conn,
) -> <Conn as AsyncConnectionCore>::ExecuteFuture<'conn, 'query>
fn execute<'conn, 'query>( self, conn: &'conn mut Conn, ) -> <Conn as AsyncConnectionCore>::ExecuteFuture<'conn, 'query>
Source§fn load<'query, 'conn, U>(
self,
conn: &'conn mut Conn,
) -> AndThen<Self::LoadFuture<'conn>, TryCollect<Self::Stream<'conn>, Vec<U>>>
fn load<'query, 'conn, U>( self, conn: &'conn mut Conn, ) -> AndThen<Self::LoadFuture<'conn>, TryCollect<Self::Stream<'conn>, Vec<U>>>
Source§fn load_stream<'conn, 'query, U>(
self,
conn: &'conn mut Conn,
) -> Self::LoadFuture<'conn>where
Conn: AsyncConnectionCore,
U: 'conn,
Self: LoadQuery<'query, Conn, U> + 'query,
fn load_stream<'conn, 'query, U>(
self,
conn: &'conn mut Conn,
) -> Self::LoadFuture<'conn>where
Conn: AsyncConnectionCore,
U: 'conn,
Self: LoadQuery<'query, Conn, U> + 'query,
Stream] with the returned rows. Read moreSource§fn get_result<'query, 'conn, U>(
self,
conn: &'conn mut Conn,
) -> AndThen<Self::LoadFuture<'conn>, LoadNext<Pin<Box<Self::Stream<'conn>>>>>
fn get_result<'query, 'conn, U>( self, conn: &'conn mut Conn, ) -> AndThen<Self::LoadFuture<'conn>, LoadNext<Pin<Box<Self::Stream<'conn>>>>>
Source§fn get_results<'query, 'conn, U>(
self,
conn: &'conn mut Conn,
) -> AndThen<Self::LoadFuture<'conn>, TryCollect<Self::Stream<'conn>, Vec<U>>>
fn get_results<'query, 'conn, U>( self, conn: &'conn mut Conn, ) -> AndThen<Self::LoadFuture<'conn>, TryCollect<Self::Stream<'conn>, Vec<U>>>
Vec with the affected rows. Read moreSource§impl<T> Scoped for T
impl<T> Scoped for T
Source§fn scope(ctx: &PolicyContext) -> ScopeQuery<'_, Self>
fn scope(ctx: &PolicyContext) -> ScopeQuery<'_, Self>
ScopeQuery for this type. Resolves the
registered scope at .load() time, not here.