fraiseql_cli/config/toml_schema/operations.rs
1//! Query and mutation operation definitions for TOML schema.
2
3use serde::{Deserialize, Serialize};
4
5use super::types::ArgumentDefinition;
6
7/// Global defaults for list-query auto-params.
8///
9/// Applied when a per-query `auto_params` does not specify a given flag.
10/// Relay queries and single-item queries are never affected.
11///
12/// ```toml
13/// [query_defaults]
14/// where = true
15/// order_by = true
16/// limit = false # e.g. Relay-first project
17/// offset = false
18/// ```
19#[derive(Debug, Clone, Deserialize, Serialize)]
20#[serde(default, deny_unknown_fields)]
21pub struct QueryDefaults {
22 /// Enable automatic `where` filter parameter (default: true)
23 #[serde(rename = "where", default = "default_true")]
24 pub where_clause: bool,
25 /// Enable automatic `order_by` parameter (default: true)
26 #[serde(default = "default_true")]
27 pub order_by: bool,
28 /// Enable automatic `limit` parameter (default: true)
29 #[serde(default = "default_true")]
30 pub limit: bool,
31 /// Enable automatic `offset` parameter (default: true)
32 #[serde(default = "default_true")]
33 pub offset: bool,
34}
35
36impl Default for QueryDefaults {
37 fn default() -> Self {
38 Self {
39 where_clause: true,
40 order_by: true,
41 limit: true,
42 offset: true,
43 }
44 }
45}
46
47fn default_true() -> bool {
48 true
49}
50
51/// Schema metadata
52#[derive(Debug, Clone, Deserialize, Serialize)]
53#[serde(default, deny_unknown_fields)]
54pub struct SchemaMetadata {
55 /// Schema name
56 pub name: String,
57 /// Schema version
58 pub version: String,
59 /// Optional schema description
60 pub description: Option<String>,
61 /// Target database (postgresql, mysql, sqlite, sqlserver)
62 pub database_target: String,
63}
64
65impl Default for SchemaMetadata {
66 fn default() -> Self {
67 Self {
68 name: "myapp".to_string(),
69 version: "1.0.0".to_string(),
70 description: None,
71 database_target: "postgresql".to_string(),
72 }
73 }
74}
75
76/// Query definition in TOML
77#[derive(Debug, Clone, Deserialize, Serialize)]
78#[serde(default, deny_unknown_fields)]
79pub struct QueryDefinition {
80 /// Return type name
81 pub return_type: String,
82 /// Whether query returns an array
83 #[serde(default)]
84 pub return_array: bool,
85 /// SQL source for the query
86 pub sql_source: String,
87 /// Query description
88 pub description: Option<String>,
89 /// Query arguments
90 pub args: Vec<ArgumentDefinition>,
91}
92
93impl Default for QueryDefinition {
94 fn default() -> Self {
95 Self {
96 return_type: "String".to_string(),
97 return_array: false,
98 sql_source: "v_entity".to_string(),
99 description: None,
100 args: vec![],
101 }
102 }
103}
104
105/// Mutation definition in TOML
106#[derive(Debug, Clone, Deserialize, Serialize)]
107#[serde(default, deny_unknown_fields)]
108pub struct MutationDefinition {
109 /// Return type name
110 pub return_type: String,
111 /// SQL function or procedure source.
112 ///
113 /// When absent, the compiler resolves the function name from the `[crud]`
114 /// naming config using the `operation` and the entity name derived from
115 /// `return_type`. A compile error is emitted if both are missing.
116 #[serde(skip_serializing_if = "Option::is_none")]
117 pub sql_source: Option<String>,
118 /// Operation type (CREATE, UPDATE, DELETE)
119 pub operation: String,
120 /// How the GraphQL `input` argument is passed to the SQL function:
121 /// `"flatten"` (positional columns, the default) or `"jsonb"` (the whole
122 /// input as one `jsonb` arg).
123 ///
124 /// Orthogonal to `operation`: set `"jsonb"` so a backend using the
125 /// single-`jsonb`-wrapper convention can register the real DML verb and
126 /// still receive the whole input as one argument — letting the Change Spine
127 /// record the true `modification_type`. Defaults to `"flatten"`.
128 #[serde(default = "default_input_style")]
129 pub input_style: String,
130 /// Whether a successful, state-changing run of this mutation also records the
131 /// changed entity's pre-image (before-state) into the Change-Spine
132 /// `object_data_before` column, sourced from an optional `entity_before` on the
133 /// mutation's `app.mutation_response`.
134 ///
135 /// Set `true` to opt an audit-sensitive mutation into an inline Debezium-style
136 /// `{before, after}` on the single change event. Defaults to `false`,
137 /// byte-identical to a schema authored before this field existed.
138 #[serde(default)]
139 pub changelog_pre_image: bool,
140 /// Mutation description
141 pub description: Option<String>,
142 /// Mutation arguments
143 pub args: Vec<ArgumentDefinition>,
144}
145
146impl Default for MutationDefinition {
147 fn default() -> Self {
148 Self {
149 return_type: "String".to_string(),
150 sql_source: None,
151 operation: "CREATE".to_string(),
152 input_style: default_input_style(),
153 changelog_pre_image: false,
154 description: None,
155 args: vec![],
156 }
157 }
158}
159
160/// Serde default for [`MutationDefinition::input_style`]: positional flatten.
161fn default_input_style() -> String {
162 "flatten".to_string()
163}