fraiseql_cli/config/toml_schema/caching.rs
1//! Caching and analytics configuration for TOML schema.
2
3use serde::{Deserialize, Serialize};
4
5/// Declarative result-cache rules (#623).
6///
7/// Rules are **lowered at compile time** onto the two compiled fields the
8/// runtime's result cache already consumes: the named query's
9/// `cache_ttl_seconds` (the per-view TTL map) and each trigger mutation's
10/// `invalidates_views` (mutation-driven invalidation). Runtime enablement
11/// remains the server's `cache_enabled`.
12#[derive(Debug, Clone, Deserialize, Serialize)]
13#[serde(default, deny_unknown_fields)]
14pub struct CachingConfig {
15 /// Gate for the rules below: `true` with rules lowers them; `false` with
16 /// rules — or `true` without rules — is refused at compile time.
17 #[serde(default)]
18 pub enabled: bool,
19 /// Cache backend. Only `"memory"` exists — the runtime result cache is
20 /// in-process; any other value is refused at compile time.
21 pub backend: String,
22 /// Refused at compile time: there is no Redis-backed result cache.
23 pub redis_url: Option<String>,
24 /// Per-query cache rules.
25 pub rules: Vec<CacheRule>,
26}
27
28impl Default for CachingConfig {
29 fn default() -> Self {
30 Self {
31 enabled: false,
32 backend: "memory".to_string(),
33 redis_url: None,
34 rules: vec![],
35 }
36 }
37}
38
39/// One declarative cache rule (#623).
40#[derive(Debug, Clone, Deserialize, Serialize)]
41#[serde(deny_unknown_fields)]
42pub struct CacheRule {
43 /// Name of an existing query (compile error otherwise).
44 pub query: String,
45 /// TTL lowered onto the query's `cache_ttl_seconds`. A query that already
46 /// declares one (SDK/JSON-authored) is a compile error — two authoring
47 /// sources must not silently last-write-win.
48 pub ttl_seconds: u32,
49 /// Names of existing mutations (compile error otherwise) whose success
50 /// must invalidate this query's cached results; each gains the query's
51 /// view in its `invalidates_views`.
52 pub invalidation_triggers: Vec<String>,
53}
54
55/// Analytics query definitions (#624).
56///
57/// Each entry is **lowered at compile time into an ordinary compiled query**:
58/// an operator-authored, compile-validated `sql_source` (a view, typically an
59/// aggregate/materialized one) served with the SELECT list of its declared
60/// `return_type`. No client-supplied identifier can reach `FROM` or the
61/// SELECT list because neither exists on this path at request time.
62#[derive(Debug, Clone, Default, Deserialize, Serialize)]
63#[serde(default, deny_unknown_fields)]
64pub struct AnalyticsConfig {
65 /// Gate for the queries below: `true` with queries lowers them; `false`
66 /// with queries — or `true` without queries — is refused at compile time.
67 #[serde(default)]
68 pub enabled: bool,
69 /// Analytics query definitions.
70 pub queries: Vec<AnalyticsQuery>,
71}
72
73/// One analytics query (#624), compiled into a list-returning view query.
74#[derive(Debug, Clone, Deserialize, Serialize)]
75#[serde(deny_unknown_fields)]
76pub struct AnalyticsQuery {
77 /// GraphQL field name. Must not collide with an existing query and must
78 /// not end in `_aggregate` / `_window` (the executor classifies those
79 /// suffixes before query resolution, so such a query would be
80 /// unreachable).
81 pub name: String,
82 /// Declared type whose fields form the SELECT list (compile error if the
83 /// type does not exist).
84 pub return_type: String,
85 /// The view to serve — validated as a SQL identifier at compile time
86 /// (reject, never escape).
87 pub sql_source: String,
88 /// Query description.
89 pub description: Option<String>,
90}