1use serde::{Deserialize, Deserializer, Serialize};
4
5#[derive(Clone, Debug, Serialize, Deserialize)]
6pub struct SchemaConfig {
7 pub id: String,
8 pub name: String,
9 #[serde(default)]
10 pub comment: Option<String>,
11}
12
13#[derive(Clone, Debug, Serialize, Deserialize)]
14pub struct EnumConfig {
15 pub id: String,
16 #[serde(default)]
17 pub schema_id: Option<String>,
18 pub name: String,
19 pub values: Vec<String>,
20 #[serde(default)]
21 pub comment: Option<String>,
22}
23
24#[derive(Clone, Debug, Serialize, Deserialize)]
25pub struct TableCheck {
26 pub name: String,
27 pub expression: String,
28}
29
30#[derive(Clone, Debug, Serialize, Deserialize)]
31#[serde(untagged)]
32pub enum PrimaryKeyConfig {
33 Single(String),
34 Composite(Vec<String>),
35}
36
37#[derive(Clone, Debug, Serialize, Deserialize)]
38pub struct TableConfig {
39 pub id: String,
40 #[serde(default)]
41 pub schema_id: Option<String>,
42 pub name: String,
43 #[serde(default)]
44 pub comment: Option<String>,
45 pub primary_key: PrimaryKeyConfig,
46 #[serde(default)]
47 pub unique: Vec<Vec<String>>,
48 #[serde(default)]
49 pub check: Vec<TableCheck>,
50 #[serde(default)]
53 pub audit_log: bool,
54 #[serde(default)]
57 pub versioning: Option<VersioningConfig>,
58}
59
60#[derive(Clone, Debug, Serialize, Deserialize)]
62pub struct VersioningConfig {
63 pub enabled: bool,
64 #[serde(default)]
67 pub keep_versions: Option<i64>,
68}
69
70#[derive(Clone, Debug, Serialize, Deserialize)]
71#[serde(untagged)]
72pub enum ColumnTypeConfig {
73 Simple(String),
74 Parameterized {
75 name: String,
76 params: Option<Vec<u32>>,
77 },
78}
79
80#[derive(Clone, Debug, Serialize)]
81pub enum ColumnDefaultConfig {
82 Literal(String),
83 Expression { expression: String },
84}
85
86impl<'de> Deserialize<'de> for ColumnDefaultConfig {
87 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
88 where
89 D: Deserializer<'de>,
90 {
91 let v = serde_json::Value::deserialize(deserializer)?;
92 match v {
93 serde_json::Value::String(s) => Ok(ColumnDefaultConfig::Literal(s)),
94 serde_json::Value::Object(mut obj) => {
95 if let Some(serde_json::Value::String(s)) = obj.remove("expression") {
96 return Ok(ColumnDefaultConfig::Expression { expression: s });
97 }
98 if let Some(serde_json::Value::String(s)) = obj.remove("value").or_else(|| obj.remove("literal")) {
99 return Ok(ColumnDefaultConfig::Literal(s));
100 }
101 Err(serde::de::Error::custom(format!(
102 "column default must be a string, {{ \"expression\": \"...\" }}, or {{ \"value\": \"...\" }}; got object with keys: {:?}",
103 obj.keys().collect::<Vec<_>>()
104 )))
105 }
106 serde_json::Value::Bool(b) => Ok(ColumnDefaultConfig::Literal(b.to_string())),
107 serde_json::Value::Number(n) => Ok(ColumnDefaultConfig::Literal(n.to_string())),
108 other => Err(serde::de::Error::custom(format!(
109 "column default must be a string, boolean, number, or {{ \"expression\": \"...\" }}; got {}",
110 type_name_of_json(&other)
111 ))),
112 }
113 }
114}
115
116fn type_name_of_json(v: &serde_json::Value) -> &'static str {
117 match v {
118 serde_json::Value::Null => "null",
119 serde_json::Value::Bool(_) => "boolean",
120 serde_json::Value::Number(_) => "number",
121 serde_json::Value::String(_) => "string",
122 serde_json::Value::Array(_) => "array",
123 serde_json::Value::Object(_) => "object",
124 }
125}
126
127#[derive(Clone, Debug, Serialize, Deserialize)]
128pub struct ColumnConfig {
129 pub id: String,
130 pub table_id: String,
131 pub name: String,
132 #[serde(rename = "type")]
133 pub type_: ColumnTypeConfig,
134 #[serde(default = "default_true")]
135 pub nullable: bool,
136 #[serde(default)]
137 pub default: Option<ColumnDefaultConfig>,
138 #[serde(default)]
139 pub comment: Option<String>,
140 #[serde(default)]
141 pub asset: Option<AssetColumnConfig>,
142 #[serde(default)]
147 pub extensible: bool,
148}
149
150fn default_true() -> bool {
151 true
152}
153
154#[derive(Clone, Debug, Serialize, Deserialize)]
155#[serde(untagged)]
156pub enum IndexColumnEntry {
157 Name(String),
158 Spec {
159 name: String,
160 direction: Option<String>,
161 nulls: Option<String>,
162 },
163 Expression {
164 expression: String,
165 },
166}
167
168#[derive(Clone, Debug, Serialize, Deserialize)]
169pub struct IndexConfig {
170 pub id: String,
171 #[serde(default)]
172 pub schema_id: Option<String>,
173 pub table_id: String,
174 pub name: String,
175 #[serde(default)]
176 pub method: Option<String>,
177 #[serde(default)]
178 pub unique: bool,
179 pub columns: Vec<IndexColumnEntry>,
180 #[serde(default)]
181 pub include: Vec<String>,
182 #[serde(default, rename = "where")]
183 pub where_: Option<String>,
184 #[serde(default)]
185 pub comment: Option<String>,
186}
187
188impl IndexConfig {
189 pub fn where_clause(&self) -> Option<&str> {
190 self.where_.as_deref()
191 }
192}
193
194#[derive(Clone, Debug, Serialize, Deserialize)]
195pub struct RelationshipConfig {
196 pub id: String,
197 #[serde(default)]
199 pub from_schema_id: Option<String>,
200 pub from_table_id: String,
201 pub from_column_id: String,
202 #[serde(default)]
205 pub to_package_id: Option<String>,
206 #[serde(default)]
209 pub to_schema_id: Option<String>,
210 pub to_table_id: String,
211 pub to_column_id: String,
212 #[serde(default)]
213 pub on_update: Option<String>,
214 #[serde(default)]
215 pub on_delete: Option<String>,
216 #[serde(default)]
217 pub name: Option<String>,
218}
219
220#[derive(Clone, Debug, Default, Serialize, Deserialize)]
221pub struct ValidationRule {
222 #[serde(default)]
223 pub required: Option<bool>,
224 #[serde(default)]
225 pub format: Option<String>,
226 #[serde(default)]
227 pub max_length: Option<u32>,
228 #[serde(default)]
229 pub min_length: Option<u32>,
230 #[serde(default)]
231 pub pattern: Option<String>,
232 #[serde(default)]
233 pub allowed: Option<Vec<serde_json::Value>>,
234 #[serde(default)]
235 pub minimum: Option<f64>,
236 #[serde(default)]
237 pub maximum: Option<f64>,
238 #[serde(default)]
240 pub allowed_mime_types: Option<Vec<String>>,
241 #[serde(default)]
242 pub allowed_extensions: Option<Vec<String>>,
243 #[serde(default)]
244 pub max_size_mb: Option<f64>,
245 #[serde(default)]
246 pub min_size_kb: Option<f64>,
247 #[serde(default)]
248 pub max_filename_length: Option<u32>,
249}
250
251#[derive(Clone, Debug, Serialize, Deserialize)]
252pub struct AssetColumnConfig {
253 #[serde(default)]
255 pub prefix: Option<String>,
256 #[serde(default)]
258 pub compression: Option<String>,
259}
260
261#[derive(Clone, Debug, Serialize, Deserialize)]
262pub struct EventCondition {
263 pub field: String,
265 #[serde(default)]
267 pub changed_to: Option<serde_json::Value>,
268 #[serde(default)]
270 pub equals: Option<serde_json::Value>,
271 #[serde(default)]
273 pub not_null: Option<bool>,
274}
275
276#[derive(Clone, Debug, Serialize, Deserialize)]
277pub struct EntityEventTrigger {
278 pub id: String,
279 pub on: String,
281 #[serde(default)]
284 pub event_name: Option<String>,
285 #[serde(default)]
287 pub condition: Option<EventCondition>,
288}
289
290#[derive(Clone, Debug, Serialize, Deserialize)]
293pub struct McpEntityConfig {
294 #[serde(default)]
296 pub enabled: bool,
297 #[serde(default)]
301 pub operations: Vec<String>,
302 #[serde(default)]
304 pub tool_prefix: Option<String>,
305 #[serde(default)]
307 pub description: Option<String>,
308}
309
310#[derive(Clone, Debug, Serialize, Deserialize)]
311pub struct ApiEntityConfig {
312 pub entity_id: String,
313 pub path_segment: String,
314 pub operations: Vec<String>,
315 #[serde(default)]
317 pub sensitive_columns: Vec<String>,
318 #[serde(default)]
319 pub validation: std::collections::HashMap<String, ValidationRule>,
320 #[serde(default)]
322 pub archive_field: Option<String>,
323 #[serde(default)]
325 pub events: Vec<EntityEventTrigger>,
326 #[serde(default)]
331 pub parent_ref_column: Option<String>,
332 #[serde(default)]
334 pub mcp: Option<McpEntityConfig>,
335}
336
337#[derive(Clone, Debug, Serialize, Deserialize)]
338pub struct KvStoreConfig {
339 pub id: String,
340 pub namespace: String,
341 #[serde(default)]
342 pub comment: Option<String>,
343}
344
345#[derive(Clone, Debug, Default)]
347pub struct FullConfig {
348 pub schemas: Vec<SchemaConfig>,
349 pub enums: Vec<EnumConfig>,
350 pub tables: Vec<TableConfig>,
351 pub columns: Vec<ColumnConfig>,
352 pub indexes: Vec<IndexConfig>,
353 pub relationships: Vec<RelationshipConfig>,
354 pub api_entities: Vec<ApiEntityConfig>,
355 pub kv_stores: Vec<KvStoreConfig>,
356}