fraiseql_cli/schema/intermediate/mod.rs
1//! Intermediate Schema Format
2//!
3//! Language-agnostic schema representation that all language libraries output.
4//! See `docs/architecture/intermediate-schema.md` for full specification.
5
6pub mod advanced_types;
7pub mod analytics;
8pub mod fragments;
9pub mod operations;
10pub mod subscriptions;
11pub mod types;
12
13pub use advanced_types::{
14 IntermediateInputField, IntermediateInputObject, IntermediateInterface, IntermediateUnion,
15};
16pub use analytics::{
17 IntermediateAggregateQuery, IntermediateDimensionPath, IntermediateDimensions,
18 IntermediateFactTable, IntermediateFilter, IntermediateMeasure,
19};
20pub use fragments::{
21 IntermediateAppliedDirective, IntermediateDirective, IntermediateFragment,
22 IntermediateFragmentField, IntermediateFragmentFieldDef,
23};
24use fraiseql_core::schema::{
25 DebugConfig, McpConfig, NamingConvention, RestConfig, SessionVariablesConfig,
26 SubscriptionsConfig, ValidationConfig,
27};
28pub use operations::{
29 IntermediateArgument, IntermediateAutoParams, IntermediateMutation, IntermediateQuery,
30 IntermediateQueryDefaults,
31};
32use serde::{Deserialize, Serialize};
33pub use subscriptions::{
34 IntermediateFilterCondition, IntermediateObserver, IntermediateObserverAction,
35 IntermediateRetryConfig, IntermediateSubscription, IntermediateSubscriptionFilter,
36};
37pub use types::{
38 IntermediateDeprecation, IntermediateEnum, IntermediateEnumValue, IntermediateField,
39 IntermediateScalar, IntermediateType,
40};
41
42/// Intermediate schema - universal format from all language libraries
43#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
44pub struct IntermediateSchema {
45 /// Schema format version
46 #[serde(default = "default_version")]
47 pub version: String,
48
49 /// GraphQL object types
50 #[serde(default)]
51 pub types: Vec<IntermediateType>,
52
53 /// GraphQL enum types
54 #[serde(default)]
55 pub enums: Vec<IntermediateEnum>,
56
57 /// GraphQL input object types
58 #[serde(default)]
59 pub input_types: Vec<IntermediateInputObject>,
60
61 /// GraphQL interface types (per GraphQL spec §3.7)
62 #[serde(default)]
63 pub interfaces: Vec<IntermediateInterface>,
64
65 /// GraphQL union types (per GraphQL spec §3.10)
66 #[serde(default)]
67 pub unions: Vec<IntermediateUnion>,
68
69 /// GraphQL queries
70 #[serde(default)]
71 pub queries: Vec<IntermediateQuery>,
72
73 /// GraphQL mutations
74 #[serde(default)]
75 pub mutations: Vec<IntermediateMutation>,
76
77 /// GraphQL subscriptions
78 #[serde(default)]
79 pub subscriptions: Vec<IntermediateSubscription>,
80
81 /// GraphQL fragments (reusable field selections)
82 #[serde(default, skip_serializing_if = "Option::is_none")]
83 pub fragments: Option<Vec<IntermediateFragment>>,
84
85 /// GraphQL directive definitions (custom directives)
86 #[serde(default, skip_serializing_if = "Option::is_none")]
87 pub directives: Option<Vec<IntermediateDirective>>,
88
89 /// Analytics fact tables (optional)
90 #[serde(default, skip_serializing_if = "Option::is_none")]
91 pub fact_tables: Option<Vec<IntermediateFactTable>>,
92
93 /// Analytics aggregate queries (optional)
94 #[serde(default, skip_serializing_if = "Option::is_none")]
95 pub aggregate_queries: Option<Vec<IntermediateAggregateQuery>>,
96
97 /// Observer definitions (database change event listeners)
98 #[serde(default, skip_serializing_if = "Option::is_none")]
99 pub observers: Option<Vec<IntermediateObserver>>,
100
101 /// Scheduled ingress source definitions (#573) — the dual of `observers`.
102 /// Reuses the compiled [`SourceDefinition`](fraiseql_core::schema::SourceDefinition)
103 /// shape directly (it already carries serde defaults); the converter copies them
104 /// into the compiled schema.
105 #[serde(default, skip_serializing_if = "Option::is_none")]
106 pub sources: Option<Vec<fraiseql_core::schema::SourceDefinition>>,
107
108 /// Custom scalar type definitions
109 ///
110 /// Defines custom GraphQL scalar types with validation rules.
111 /// Custom scalars can be defined in Python, TypeScript, Java, Go, and Rust SDKs,
112 /// and are compiled into the CompiledSchema's CustomTypeRegistry.
113 #[serde(default, skip_serializing_if = "Option::is_none")]
114 pub custom_scalars: Option<Vec<IntermediateScalar>>,
115
116 /// Security configuration (from fraiseql.toml)
117 /// Compiled from the security section of fraiseql.toml at compile time.
118 /// Optional - if not provided, defaults are used.
119 #[serde(default, skip_serializing_if = "Option::is_none")]
120 pub security: Option<serde_json::Value>,
121
122 /// Observers/event system configuration (from fraiseql.toml).
123 ///
124 /// Contains backend connection settings (redis_url, nats_url, etc.) compiled
125 /// from the `[observers]` TOML section. Embedded verbatim into the compiled schema.
126 #[serde(default, skip_serializing_if = "Option::is_none")]
127 pub observers_config: Option<serde_json::Value>,
128
129 /// Federation configuration.
130 ///
131 /// Two authoring workflows feed this field:
132 /// - The TOML merger embeds the `[federation]` section under `federation_config`.
133 /// - Language SDKs (e.g. the Python SDK's `export_schema(federation=...)`) emit the block
134 /// under the top-level `federation` key in `schema.json`; the `alias` binds it here so the
135 /// legacy JSON workflow does not silently drop it.
136 ///
137 /// Carried verbatim by the converter into `CompiledSchema.federation`.
138 #[serde(default, alias = "federation", skip_serializing_if = "Option::is_none")]
139 pub federation_config: Option<serde_json::Value>,
140
141 /// WebSocket subscription configuration (hooks, limits).
142 ///
143 /// Compiled from the `[subscriptions]` TOML section. Embedded verbatim into
144 /// the compiled schema for server-side consumption.
145 #[serde(default, skip_serializing_if = "Option::is_none")]
146 pub subscriptions_config: Option<SubscriptionsConfig>,
147
148 /// Query validation config (depth/complexity limits).
149 ///
150 /// Compiled from `[validation]` in `fraiseql.toml`. Embedded into the compiled
151 /// schema for server-side consumption.
152 #[serde(default, skip_serializing_if = "Option::is_none")]
153 pub validation_config: Option<ValidationConfig>,
154
155 /// Debug/development configuration.
156 ///
157 /// Compiled from `[debug]` in `fraiseql.toml`. Embedded into the compiled
158 /// schema for server-side consumption.
159 #[serde(default, skip_serializing_if = "Option::is_none")]
160 pub debug_config: Option<DebugConfig>,
161
162 /// MCP (Model Context Protocol) server configuration.
163 ///
164 /// Compiled from `[mcp]` in `fraiseql.toml`. Embedded into the compiled
165 /// schema for server-side consumption.
166 #[serde(default, skip_serializing_if = "Option::is_none")]
167 pub mcp_config: Option<McpConfig>,
168
169 /// REST transport configuration.
170 ///
171 /// Compiled from `[rest]` in `fraiseql.toml`. Embedded into the compiled
172 /// schema for server-side consumption.
173 #[serde(default, skip_serializing_if = "Option::is_none")]
174 pub rest_config: Option<RestConfig>,
175
176 /// Global auto-param defaults for list queries (injected from TOML by the merger).
177 ///
178 /// Never present in `schema.json` — populated at compile time from `[query_defaults]`
179 /// in `fraiseql.toml`. Used by the converter to resolve per-query `auto_params`.
180 #[serde(default, skip_serializing_if = "Option::is_none")]
181 pub query_defaults: Option<IntermediateQueryDefaults>,
182
183 /// Naming convention for GraphQL operation names.
184 ///
185 /// Compiled from `fraiseql.toml` top-level `naming_convention` setting.
186 #[serde(default)]
187 pub naming_convention: NamingConvention,
188
189 /// Session variable injection configuration.
190 ///
191 /// When populated, the executor calls `set_config()` before each query and
192 /// mutation to inject per-request values (JWT claims, HTTP headers, or literals)
193 /// as PostgreSQL transaction-scoped settings.
194 ///
195 /// Embedded verbatim from the `session_variables` key in `schema.json`.
196 #[serde(default, skip_serializing_if = "Option::is_none")]
197 pub session_variables: Option<SessionVariablesConfig>,
198
199 /// Hierarchy definitions for ID-based ltree operators.
200 ///
201 /// Compiled from the `[hierarchies]` TOML section. Maps hierarchy names
202 /// to table/path_column pairs for subquery generation.
203 #[serde(default, skip_serializing_if = "Option::is_none")]
204 pub hierarchies_config: Option<fraiseql_core::schema::HierarchiesConfig>,
205
206 /// Changelog GraphQL-exposure configuration.
207 ///
208 /// Compiled from the `[changelog]` TOML section by the merger. Drives the
209 /// converter's injection of the `EntityChangeLog` / `TransportCheckpoint`
210 /// types and their operations.
211 #[serde(default, skip_serializing_if = "Option::is_none")]
212 pub changelog_config: Option<fraiseql_core::schema::ChangelogConfig>,
213}
214
215fn default_version() -> String {
216 "2.0.0".to_string()
217}
218
219#[cfg(test)]
220mod tests;