Skip to main content

CachedDatabaseAdapter

Struct CachedDatabaseAdapter 

Source
pub struct CachedDatabaseAdapter<A: DatabaseAdapter> { /* private fields */ }
Expand description

Cached database adapter wrapper.

Wraps any DatabaseAdapter implementation with transparent query result caching. Cache keys include query, variables, WHERE clause, and schema version for security and correctness.

§Cache Behavior

  • Cache Hit: Returns cached result in ~0.1ms (50-200x faster than database)
  • Cache Miss: Executes query via underlying adapter, stores result in cache
  • Invalidation: Call invalidate_views() after mutations to clear affected caches

§Thread Safety

This adapter is Send + Sync and can be safely shared across async tasks. The underlying cache uses Arc<Mutex<>> for thread-safe access.

§Example

use fraiseql_core::cache::{CachedDatabaseAdapter, QueryResultCache, CacheConfig, InvalidationContext};
use fraiseql_core::db::{postgres::PostgresAdapter, DatabaseAdapter};
use fraiseql_db::ViewName;

let db = PostgresAdapter::new("postgresql://localhost/db").await?;
let cache = QueryResultCache::new(CacheConfig::default());
let adapter = CachedDatabaseAdapter::new(db, cache, "1.0.0".to_string());

// First query - cache miss (slower)
let users1 = adapter.execute_where_query("v_user", None, None, None, None).await?;

// Second query - cache hit (fast!)
let users2 = adapter.execute_where_query("v_user", None, None, None, None).await?;

// After mutation, invalidate. `InvalidationContext` keeps its `Vec<String>`
// shape for compatibility with the audit-logging facade; callers convert at
// the adapter boundary.
let invalidation = InvalidationContext::for_mutation(
    "createUser",
    vec!["v_user".to_string()],
);
let views: Vec<ViewName> = invalidation
    .modified_views
    .iter()
    .map(ViewName::from)
    .collect();
adapter.invalidate_views(&views)?;

Implementations§

Source§

impl<A: DatabaseAdapter> CachedDatabaseAdapter<A>

Source

pub fn new(adapter: A, cache: QueryResultCache, schema_version: String) -> Self

Create new cached database adapter.

§Arguments
  • adapter - Underlying database adapter to wrap
  • cache - Query result cache instance
  • schema_version - Uniquely identifies the compiled schema. Use schema.content_hash() (NOT env!("CARGO_PKG_VERSION")) so that any schema content change automatically invalidates cached entries across deploys.
§Example
use fraiseql_core::cache::{CachedDatabaseAdapter, QueryResultCache, CacheConfig};
use fraiseql_core::db::postgres::PostgresAdapter;
use fraiseql_core::schema::CompiledSchema;

let db = PostgresAdapter::new("postgresql://localhost/db").await?;
let cache = QueryResultCache::new(CacheConfig::default());
let adapter = CachedDatabaseAdapter::new(
    db,
    cache,
    schema.content_hash()  // Use content hash for automatic invalidation
);
Source

pub fn with_view_ttl_overrides(self, overrides: HashMap<String, u64>) -> Self

Set per-view TTL overrides.

Maps sql_source (view name) → TTL in seconds. Built at server startup from compiled QueryDefinition::cache_ttl_seconds entries.

§Example
let overrides = std::collections::HashMap::from([
    ("v_country".to_string(), 3600_u64),      // 1 h for reference data
    ("v_live_price".to_string(), 0_u64),      // no TTL — mutation-invalidated only
]);
let adapter = CachedDatabaseAdapter::new(db, cache, "1.0.0".to_string())
    .with_view_ttl_overrides(overrides);

⚠ A 0 TTL means the entry lives until a mutation invalidates it, so its correctness rests entirely on invalidation being unmissable. That is what the generation fence guarantees (#1079): a read whose database round trip straddled an invalidation refuses to cache, instead of storing pre-mutation rows that — at TTL 0 — nothing would ever expire.

Source

pub const fn with_rls(self, has_rls: bool) -> Self

Enable or disable the RLS unauthenticated-request cache bypass.

When true, any request without a SecurityContext will bypass both cache read and write, preventing unauthenticated requests from being served stale data that belongs to an authenticated tenant.

Set this to schema.has_rls_configured() at server startup.

Source

pub fn with_cascade_invalidator(self, invalidator: CascadeInvalidator) -> Self

Set a cascade invalidator for transitive view dependency expansion.

When set, invalidate_views() uses BFS to expand the initial view list to include all views that transitively depend on the invalidated views.

§Example
let mut cascade = CascadeInvalidator::new();
cascade.add_dependency("v_user_stats", "v_user")?;
cascade.add_dependency("v_dashboard", "v_user_stats")?;
let adapter = CachedDatabaseAdapter::new(db, cache, "1.0.0".to_string())
    .with_cascade_invalidator(cascade);
Source

pub fn with_cache_metadata_from_schema(self, schema: &CompiledSchema) -> Self

Read every per-query cache declaration out of a compiled schema.

This is the single seam between the compiled schema and the row cache. Both things it reads are per-query annotations that the runtime otherwise has no way to see, because the DatabaseAdapter boundary carries only a view name:

  • cache_ttl_seconds → the view’s TTL override, and its membership of cacheable_views (opt-in mode).
  • additional_views → the secondary views a query also reads, so a mutation on one of them evicts the joined query’s cached rows (#761).

Add any further per-query cache annotation here, not at a call site: rebuilt_for_schema (hot reload) delegates to the same code, so an annotation wired in one place and not the other silently stops working after the first schema reload.

§Example
let adapter = CachedDatabaseAdapter::new(db, cache, "1.0.0".to_string())
    .with_cache_metadata_from_schema(&schema);
Source

pub fn rebuilt_for_schema(self, schema: &CompiledSchema) -> Self

Rebuild this adapter for a new compiled schema.

Returns a new CachedDatabaseAdapter that:

  • Shares the same underlying QueryResultCache (via Arc)
  • Uses the new schema’s content hash as schema version
  • Has per-view TTL overrides from the new schema
  • Clears the shared cache (stale entries from old schema)

The underlying database adapter (connection pool) is reused — no connections are closed or reopened.

This is the hot-reload counterpart to the startup path (new() + with_cache_metadata_from_schema()).

Source

pub fn with_fact_table_config( adapter: A, cache: QueryResultCache, schema_version: String, fact_table_config: FactTableCacheConfig, ) -> Self

Create new cached database adapter with fact table caching configuration.

§Arguments
  • adapter - Underlying database adapter to wrap
  • cache - Query result cache instance
  • schema_version - Current schema version (e.g., git hash, semver)
  • fact_table_config - Configuration for fact table aggregation caching
§Example
use fraiseql_core::cache::{
    CachedDatabaseAdapter, QueryResultCache, CacheConfig,
    FactTableCacheConfig, FactTableVersionStrategy,
};
use fraiseql_core::db::postgres::PostgresAdapter;

let db = PostgresAdapter::new("postgresql://localhost/db").await?;
let cache = QueryResultCache::new(CacheConfig::default());

// Configure fact table caching strategies
let mut ft_config = FactTableCacheConfig::default();
ft_config.set_strategy("tf_sales", FactTableVersionStrategy::VersionTable);
ft_config.set_strategy("tf_events", FactTableVersionStrategy::time_based(300));

let adapter = CachedDatabaseAdapter::with_fact_table_config(
    db,
    cache,
    "1.0.0".to_string(),
    ft_config,
);
Source

pub const fn inner(&self) -> &A

Get reference to underlying adapter.

Useful for accessing adapter-specific methods not in the DatabaseAdapter trait.

§Example
// Access PostgreSQL-specific functionality
let pg_adapter = adapter.inner();
Source

pub fn cache(&self) -> &QueryResultCache

Get reference to cache.

Useful for metrics and monitoring.

§Example
let metrics = adapter.cache().metrics()?;
println!("Cache hit rate: {:.1}%", metrics.hit_rate() * 100.0);
Source

pub fn schema_version(&self) -> &str

Get schema version.

§Example
println!("Schema version: {}", adapter.schema_version());
Source

pub const fn fact_table_config(&self) -> &FactTableCacheConfig

Get fact table cache configuration.

Source

pub fn version_provider(&self) -> &FactTableVersionProvider

Get the version provider for fact tables.

Source

pub async fn validate_rls_active(&self, schema: &CompiledSchema) -> Result<()>

Verify that Row-Level Security is genuinely enforceable on the relations this schema reads.

Call this during server initialization when a multi-tenant schema declares [security.rls] enabled = true. Without real RLS, users sharing the same query parameters receive the same cached response regardless of tenant.

§What this checks

Every relation named by a query’s sql_source, resolved through to_regclass, must be one of:

  • a table with relrowsecurity set and at least one pg_policy row, or
  • a security_invoker view — a default view executes with its owner’s privileges and bypasses the caller’s RLS entirely, so a non-invoker view over an RLS-protected table provides no isolation at all.

A relation that does not exist fails the check: an absent relation cannot be protected.

§What it used to check, and why that was worthless

It ran SELECT current_setting('row_security', true) and passed on 'on' or 'force'. row_security governs whether existing policies are applied; it defaults to on and says nothing about whether any policy exists. So the documented “refuse startup if RLS appears inactive” gate returned Ok(()) on a stock PostgreSQL with no RLS anywhere — reporting success for a guarantee it never checked (#762).

§Errors

Returns FraiseQLError::Configuration naming every relation that is not RLS-protected, or FraiseQLError::Database if the catalog cannot be read (including on non-PostgreSQL adapters, which have no equivalent mechanism and therefore fail closed).

Source

pub async fn enforce_rls( &self, schema: &CompiledSchema, enforcement: RlsEnforcement, ) -> Result<()>

Apply the RLS enforcement policy from CacheConfig.

Runs validate_rls_active and handles the result according to enforcement:

§Errors

Returns the error from validate_rls_active when enforcement is Error.

Source§

impl<A: DatabaseAdapter> CachedDatabaseAdapter<A>

Source

pub async fn execute_aggregation_query( &self, sql: &str, ) -> Result<Vec<HashMap<String, Value>>>

Execute aggregation query with caching based on fact table versioning strategy.

This method provides transparent caching for aggregation queries on fact tables. The caching behavior depends on the configured strategy for the fact table.

§Arguments
  • sql - The aggregation SQL query
§Returns

Query results (from cache or database)

§Example

// This query will be cached according to tf_sales strategy
let results = adapter.execute_aggregation_query(
    "SELECT SUM(revenue) FROM tf_sales WHERE year = 2024"
).await?;
§Errors

Returns FraiseQLError if the underlying database query fails.

Source§

impl<A: DatabaseAdapter> CachedDatabaseAdapter<A>

Source

pub fn invalidate_views(&self, views: &[ViewName]) -> Result<u64>

Invalidate cache entries that read from specified views.

Call this after mutations to ensure cache consistency. All cache entries that accessed any of the modified views will be removed.

§Arguments
  • views - List of views/tables that were modified
§Returns

Number of cache entries invalidated

§Errors

Returns error if cache mutex is poisoned (very rare).

§Example
// After creating a user
let count = adapter.invalidate_views(&[ViewName::from("v_user")])?;
println!("Invalidated {} cache entries", count);
Source

pub fn invalidate_by_entity( &self, entity_type: &str, entity_id: &str, ) -> Result<u64>

Evict cache entries that contain the given entity UUID.

Delegates to QueryResultCache::invalidate_by_entity. Only entries whose entity-ID index (built at put() time) contains the given UUID are removed; all other entries remain warm.

§Returns

Number of cache entries evicted.

§Errors

Returns error if the cache mutex is poisoned.

Trait Implementations§

Source§

impl<A: DatabaseAdapter + Clone> Clone for CachedDatabaseAdapter<A>

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<A: DatabaseAdapter> DatabaseAdapter for CachedDatabaseAdapter<A>

Source§

fn stream_with_projection<'life0, 'life1, 'life2, 'life3, 'life4, 'life5, 'async_trait>( &'life0 self, request: &'life1 ProjectionRequest<'life2>, session_vars: &'life3 [(&'life4 str, &'life5 str)], routing: ReadRouting, ) -> Pin<Box<dyn Future<Output = Result<JsonbRowStream>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, 'life4: 'async_trait, 'life5: 'async_trait,

Forwarded to the inner adapter, and deliberately uncached (#958).

Forwarding at all is the load-bearing part. The trait’s default would satisfy this method by calling the cached read above and replaying the buffer, which returns exactly the right rows — and silently converts every streaming caller in the process back into one that materialises the whole result set. A wrapper that inherits the default is how a memory bound disappears without a single test failing.

Uncached because the two are incompatible by construction: populating a result-cache entry means holding every row, which is the cost this call exists to avoid, and serving one means the caller never streams. A read that wants the cache asks for the buffered method.

Source§

fn execute_composed_with_session<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>( &'life0 self, read: &'life1 ComposedLevel, session_vars: &'life2 [(&'life3 str, &'life4 str)], routing: ReadRouting, ) -> Pin<Box<dyn Future<Output = Result<Arc<Vec<JsonbValue>>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, 'life4: 'async_trait,

Forwarded to the inner adapter, uncached.

A composed read spans every view its embedded levels name, and this cache invalidates by the view a read targets. A cached tree would therefore survive a write to any view but the root’s — serving related rows that no longer exist. Caching it correctly needs invalidation by every view in the tree, which is a change to the cache, not to this forwarder.

Source§

fn stream_row_query<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>( &'life0 self, view_name: &'life1 str, columns: &'life2 [ColumnSpec], where_sql: Option<&'life3 str>, order_by: Option<&'life4 str>, limit: Option<u32>, offset: Option<u32>, ) -> Pin<Box<dyn Future<Output = Result<ColumnRowStream>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, 'life4: 'async_trait,

Forwarded to the inner adapter — see stream_with_projection. The row-shaped read was never cached in the first place.

Source§

fn execute_row_query_with_session<'life0, 'life1, 'life2, 'life3, 'life4, 'life5, 'life6, 'life7, 'async_trait>( &'life0 self, view_name: &'life1 str, columns: &'life2 [ColumnSpec], where_sql: Option<&'life3 str>, order_by: Option<&'life4 str>, limit: Option<u32>, offset: Option<u32>, session_vars: &'life5 [(&'life6 str, &'life7 str)], ) -> Pin<Box<dyn Future<Output = Result<Vec<Vec<ColumnValue>>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, 'life4: 'async_trait, 'life5: 'async_trait, 'life6: 'async_trait, 'life7: 'async_trait,

Forwarded to the inner adapter — see stream_row_query.

Forwarding is load-bearing: the trait default drops the session variables, so a wrapper that inherited it would leave every row read behind this cache running without the set_config an RLS policy reads (#329). The shipped binary always wraps its adapter in this one, so “the default is fine” is never true here.

Source§

fn stream_row_query_with_session<'life0, 'life1, 'life2, 'life3, 'life4, 'life5, 'life6, 'life7, 'async_trait>( &'life0 self, view_name: &'life1 str, columns: &'life2 [ColumnSpec], where_sql: Option<&'life3 str>, order_by: Option<&'life4 str>, limit: Option<u32>, offset: Option<u32>, session_vars: &'life5 [(&'life6 str, &'life7 str)], ) -> Pin<Box<dyn Future<Output = Result<ColumnRowStream>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, 'life4: 'async_trait, 'life5: 'async_trait, 'life6: 'async_trait, 'life7: 'async_trait,

Forwarded to the inner adapter — the streaming twin of execute_row_query_with_session, load-bearing for the same reason.

Source§

fn execute_admin_sql<'life0, 'life1, 'async_trait>( &'life0 self, request: &'life1 AdminSqlRequest, ) -> Pin<Box<dyn Future<Output = Result<AdminSqlOutcome>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Forwarded to the inner adapter, and deliberately uncached (#962).

Forwarding is load-bearing for the same reason as stream_with_projection, in the other direction: the trait’s default here refuses, so a wrapper that inherited it would turn every PostgreSQL deployment — which is every deployment, since the shipped binary always wraps its adapter in this one — into a server whose SQL console answers “unsupported”.

Uncached because the statement is not a query FraiseQL knows anything about: it has no cache key, its result is a preview of a moment, and a committed one changes rows other entries describe. Invalidation is deliberately not attempted either — see the endpoint’s documentation for why a committed console write is an operator action that should be followed by cache/clear.

Source§

fn result_cache_stats(&self) -> Option<ResultCacheStats>

The operator-visible snapshot of the cache that actually serves queries (#941).

None when the cache is disabled: an operator asking “what is cached?” of a server running cache_enabled = false must be told there is no cache, not handed a zero-entry snapshot of one.

Source§

fn execute_with_projection<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>( &'life0 self, view: &'life1 str, projection: Option<&'life2 SqlProjectionHint>, where_clause: Option<&'life3 WhereClause>, limit: Option<u32>, offset: Option<u32>, order_by: Option<&'life4 [OrderByClause]>, ) -> Pin<Box<dyn Future<Output = Result<Vec<JsonbValue>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, 'life4: 'async_trait,

Execute a WHERE query with SQL field projection optimization. Read more
Source§

fn execute_where_query<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, view: &'life1 str, where_clause: Option<&'life2 WhereClause>, limit: Option<u32>, offset: Option<u32>, order_by: Option<&'life3 [OrderByClause]>, ) -> Pin<Box<dyn Future<Output = Result<Vec<JsonbValue>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait,

Execute a WHERE query against a view and return JSONB rows. Read more
Source§

fn execute_with_projection_arc<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, request: &'life1 ProjectionRequest<'life2>, ) -> Pin<Box<dyn Future<Output = Result<Arc<Vec<JsonbValue>>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Like execute_with_projection but returns the result wrapped in an Arc. Read more
Source§

fn execute_where_query_arc<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, view: &'life1 str, where_clause: Option<&'life2 WhereClause>, limit: Option<u32>, offset: Option<u32>, order_by: Option<&'life3 [OrderByClause]>, ) -> Pin<Box<dyn Future<Output = Result<Arc<Vec<JsonbValue>>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait,

Like execute_where_query but returns the result wrapped in an Arc. Read more
Source§

fn database_type(&self) -> DatabaseType

Get database type (for logging/metrics). Read more
Source§

fn serves_reads_from_standbys(&self) -> bool

Whether reads may be served by a hot standby — read replicas are configured (#1390). Read more
Source§

fn health_check<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Health check - verify database connectivity. Read more
Source§

fn pool_metrics(&self) -> PoolMetrics

Get connection pool metrics. Read more
Source§

fn execute_raw_query<'life0, 'life1, 'async_trait>( &'life0 self, sql: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<Vec<HashMap<String, Value>>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Execute raw SQL query and return rows as JSON objects. Read more
Source§

fn execute_parameterized_aggregate<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, sql: &'life1 str, params: &'life2 [Value], ) -> Pin<Box<dyn Future<Output = Result<Vec<HashMap<String, Value>>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Execute a parameterized aggregate SQL query (GROUP BY / HAVING / window). Read more
Source§

fn execute_parameterized_aggregate_with_session<'life0, 'life1, 'life2, 'life3, 'life4, 'life5, 'async_trait>( &'life0 self, sql: &'life1 str, params: &'life2 [Value], session_vars: &'life3 [(&'life4 str, &'life5 str)], routing: ReadRouting, ) -> Pin<Box<dyn Future<Output = Result<Vec<HashMap<String, Value>>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, 'life4: 'async_trait, 'life5: 'async_trait,

Connection-affine variant of execute_parameterized_aggregate. Read more
Source§

fn supports_composed_reads(&self) -> bool

Whether this adapter implements execute_composed_with_session — whether a read can have related resources composed into it (the REST ?select= embed). Read more
Source§

fn count_where_query<'life0, 'life1, 'life2, 'life3, 'life4, 'life5, 'async_trait>( &'life0 self, view: &'life1 str, where_clause: Option<&'life2 WhereClause>, session_vars: &'life3 [(&'life4 str, &'life5 str)], routing: ReadRouting, ) -> Pin<Box<dyn Future<Output = Result<u64>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, 'life4: 'async_trait, 'life5: 'async_trait,

Count the rows of view matching where_clause, without materialising them. Read more
Source§

fn execute_where_query_arc_with_session<'life0, 'life1, 'life2, 'life3, 'life4, 'life5, 'life6, 'async_trait>( &'life0 self, view: &'life1 str, where_clause: Option<&'life2 WhereClause>, limit: Option<u32>, offset: Option<u32>, order_by: Option<&'life3 [OrderByClause]>, session_vars: &'life4 [(&'life5 str, &'life6 str)], routing: ReadRouting, ) -> Pin<Box<dyn Future<Output = Result<Arc<Vec<JsonbValue>>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, 'life4: 'async_trait, 'life5: 'async_trait, 'life6: 'async_trait,

Connection-affine variant of execute_where_query_arc. Read more
Source§

fn execute_with_projection_arc_with_session<'life0, 'life1, 'life2, 'life3, 'life4, 'life5, 'async_trait>( &'life0 self, request: &'life1 ProjectionRequest<'life2>, session_vars: &'life3 [(&'life4 str, &'life5 str)], routing: ReadRouting, ) -> Pin<Box<dyn Future<Output = Result<Arc<Vec<JsonbValue>>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, 'life4: 'async_trait, 'life5: 'async_trait,

Connection-affine variant of execute_with_projection_arc. Read more
Source§

fn invalidate_views<'life0, 'life1, 'async_trait>( &'life0 self, views: &'life1 [ViewName], ) -> Pin<Box<dyn Future<Output = Result<u64>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Invalidate cached query results for the specified views. Read more
Source§

fn invalidate_by_entity<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, entity_type: &'life1 str, entity_id: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<u64>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Evict cache entries that contain the given entity UUID. Read more
Source§

fn clear_result_cache<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<Option<usize>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Drop every entry in this adapter’s query-result cache. Read more
Source§

fn query_stats<'life0, 'async_trait>( &'life0 self, limit: u32, ) -> Pin<Box<dyn Future<Output = Result<Vec<QueryStatEntry>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Retrieve query performance statistics from the database. Read more
Source§

fn query_stats_by_id<'life0, 'life1, 'async_trait>( &'life0 self, id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<Option<QueryStatEntry>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Retrieve statistics for a single query by its ID. Read more
Source§

fn reset_query_stats<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Reset query performance statistics. Read more
Source§

fn on_schema_reload(&self)

Notify the adapter that the schema has changed. Read more
Source§

fn execute_row_query<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>( &'life0 self, view_name: &'life1 str, columns: &'life2 [ColumnSpec], where_sql: Option<&'life3 str>, order_by: Option<&'life4 str>, limit: Option<u32>, offset: Option<u32>, ) -> Pin<Box<dyn Future<Output = Result<Vec<Vec<ColumnValue>>, FraiseQLError>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, 'life4: 'async_trait, Self: 'async_trait,

Execute a row-shaped query against a view, returning typed column values. Read more
Source§

fn explain_query<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _sql: &'life1 str, _params: &'life2 [Value], ) -> Pin<Box<dyn Future<Output = Result<Value, FraiseQLError>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: 'async_trait,

Run the database’s EXPLAIN on a SQL statement without executing it. Read more
Source§

fn explain_where_query<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _view: &'life1 str, _where_clause: Option<&'life2 WhereClause>, _limit: Option<u32>, _offset: Option<u32>, ) -> Pin<Box<dyn Future<Output = Result<Value, FraiseQLError>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: 'async_trait,

Run EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON) against a view with the same parameterized WHERE clause that execute_where_query would use. Read more
Source§

impl<A: RelayDatabaseAdapter + DatabaseAdapter> RelayDatabaseAdapter for CachedDatabaseAdapter<A>

Source§

async fn execute_relay_page( &self, view: &str, cursor_column: &str, after: Option<CursorValue>, before: Option<CursorValue>, limit: u32, forward: bool, where_clause: Option<&WhereClause>, order_by: Option<&[OrderByClause]>, include_total_count: bool, ) -> Result<RelayPageResult>

Execute keyset (cursor-based) pagination against a JSONB view. Read more
Source§

async fn execute_relay_page_with_session( &self, view: &str, cursor_column: &str, after: Option<CursorValue>, before: Option<CursorValue>, limit: u32, forward: bool, where_clause: Option<&WhereClause>, order_by: Option<&[OrderByClause]>, include_total_count: bool, session_vars: &[(&str, &str)], routing: ReadRouting, ) -> Result<RelayPageResult>

Connection-affine variant of execute_relay_page. Read more
Source§

impl<A: Writer> Writer for CachedDatabaseAdapter<A>

A cache-wrapped adapter writes exactly when the adapter it wraps does. Writes are never cached: every one passes through, in either mode (ruling AA 6).

Source§

fn execute_write<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, request: &'life1 WriteRequest<'life2>, gate: MutationRowGate<'life3>, ) -> Pin<Box<dyn Future<Output = Result<Vec<HashMap<String, Value>>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait,

Run request under gate (see the trait’s contract). Read more
Source§

fn bump_fact_table_versions<'life0, 'life1, 'async_trait>( &'life0 self, tables: &'life1 [String], ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Bump the version counters of tables after a committed write that changed them, so cached aggregates over them are invalidated by version key. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more