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 /// Custom scalar type definitions
102 ///
103 /// Defines custom GraphQL scalar types with validation rules.
104 /// Custom scalars can be defined in Python, TypeScript, Java, Go, and Rust SDKs,
105 /// and are compiled into the CompiledSchema's CustomTypeRegistry.
106 #[serde(default, skip_serializing_if = "Option::is_none")]
107 pub custom_scalars: Option<Vec<IntermediateScalar>>,
108
109 /// Security configuration (from fraiseql.toml)
110 /// Compiled from the security section of fraiseql.toml at compile time.
111 /// Optional - if not provided, defaults are used.
112 #[serde(default, skip_serializing_if = "Option::is_none")]
113 pub security: Option<serde_json::Value>,
114
115 /// Observers/event system configuration (from fraiseql.toml).
116 ///
117 /// Contains backend connection settings (redis_url, nats_url, etc.) compiled
118 /// from the `[observers]` TOML section. Embedded verbatim into the compiled schema.
119 #[serde(default, skip_serializing_if = "Option::is_none")]
120 pub observers_config: Option<serde_json::Value>,
121
122 /// Federation configuration.
123 ///
124 /// Two authoring workflows feed this field:
125 /// - The TOML merger embeds the `[federation]` section under `federation_config`.
126 /// - Language SDKs (e.g. the Python SDK's `export_schema(federation=...)`) emit the block
127 /// under the top-level `federation` key in `schema.json`; the `alias` binds it here so the
128 /// legacy JSON workflow does not silently drop it.
129 ///
130 /// Carried verbatim by the converter into `CompiledSchema.federation`.
131 #[serde(default, alias = "federation", skip_serializing_if = "Option::is_none")]
132 pub federation_config: Option<serde_json::Value>,
133
134 /// WebSocket subscription configuration (hooks, limits).
135 ///
136 /// Compiled from the `[subscriptions]` TOML section. Embedded verbatim into
137 /// the compiled schema for server-side consumption.
138 #[serde(default, skip_serializing_if = "Option::is_none")]
139 pub subscriptions_config: Option<SubscriptionsConfig>,
140
141 /// Query validation config (depth/complexity limits).
142 ///
143 /// Compiled from `[validation]` in `fraiseql.toml`. Embedded into the compiled
144 /// schema for server-side consumption.
145 #[serde(default, skip_serializing_if = "Option::is_none")]
146 pub validation_config: Option<ValidationConfig>,
147
148 /// Debug/development configuration.
149 ///
150 /// Compiled from `[debug]` in `fraiseql.toml`. Embedded into the compiled
151 /// schema for server-side consumption.
152 #[serde(default, skip_serializing_if = "Option::is_none")]
153 pub debug_config: Option<DebugConfig>,
154
155 /// MCP (Model Context Protocol) server configuration.
156 ///
157 /// Compiled from `[mcp]` in `fraiseql.toml`. Embedded into the compiled
158 /// schema for server-side consumption.
159 #[serde(default, skip_serializing_if = "Option::is_none")]
160 pub mcp_config: Option<McpConfig>,
161
162 /// REST transport configuration.
163 ///
164 /// Compiled from `[rest]` in `fraiseql.toml`. Embedded into the compiled
165 /// schema for server-side consumption.
166 #[serde(default, skip_serializing_if = "Option::is_none")]
167 pub rest_config: Option<RestConfig>,
168
169 /// Global auto-param defaults for list queries (injected from TOML by the merger).
170 ///
171 /// Never present in `schema.json` — populated at compile time from `[query_defaults]`
172 /// in `fraiseql.toml`. Used by the converter to resolve per-query `auto_params`.
173 #[serde(default, skip_serializing_if = "Option::is_none")]
174 pub query_defaults: Option<IntermediateQueryDefaults>,
175
176 /// Naming convention for GraphQL operation names.
177 ///
178 /// Compiled from `fraiseql.toml` top-level `naming_convention` setting.
179 #[serde(default)]
180 pub naming_convention: NamingConvention,
181
182 /// Session variable injection configuration.
183 ///
184 /// When populated, the executor calls `set_config()` before each query and
185 /// mutation to inject per-request values (JWT claims, HTTP headers, or literals)
186 /// as PostgreSQL transaction-scoped settings.
187 ///
188 /// Embedded verbatim from the `session_variables` key in `schema.json`.
189 #[serde(default, skip_serializing_if = "Option::is_none")]
190 pub session_variables: Option<SessionVariablesConfig>,
191
192 /// Hierarchy definitions for ID-based ltree operators.
193 ///
194 /// Compiled from the `[hierarchies]` TOML section. Maps hierarchy names
195 /// to table/path_column pairs for subquery generation.
196 #[serde(default, skip_serializing_if = "Option::is_none")]
197 pub hierarchies_config: Option<fraiseql_core::schema::HierarchiesConfig>,
198
199 /// Changelog GraphQL-exposure configuration.
200 ///
201 /// Compiled from the `[changelog]` TOML section by the merger. Drives the
202 /// converter's injection of the `EntityChangeLog` / `TransportCheckpoint`
203 /// types and their operations.
204 #[serde(default, skip_serializing_if = "Option::is_none")]
205 pub changelog_config: Option<fraiseql_core::schema::ChangelogConfig>,
206}
207
208fn default_version() -> String {
209 "2.0.0".to_string()
210}
211
212#[cfg(test)]
213mod tests;