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}
55
56#[derive(Clone, Debug, Serialize, Deserialize)]
57#[serde(untagged)]
58pub enum ColumnTypeConfig {
59 Simple(String),
60 Parameterized {
61 name: String,
62 params: Option<Vec<u32>>,
63 },
64}
65
66#[derive(Clone, Debug, Serialize)]
67pub enum ColumnDefaultConfig {
68 Literal(String),
69 Expression { expression: String },
70}
71
72impl<'de> Deserialize<'de> for ColumnDefaultConfig {
73 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
74 where
75 D: Deserializer<'de>,
76 {
77 let v = serde_json::Value::deserialize(deserializer)?;
78 match v {
79 serde_json::Value::String(s) => Ok(ColumnDefaultConfig::Literal(s)),
80 serde_json::Value::Object(mut obj) => {
81 if let Some(serde_json::Value::String(s)) = obj.remove("expression") {
82 return Ok(ColumnDefaultConfig::Expression { expression: s });
83 }
84 if let Some(serde_json::Value::String(s)) = obj.remove("value").or_else(|| obj.remove("literal")) {
85 return Ok(ColumnDefaultConfig::Literal(s));
86 }
87 Err(serde::de::Error::custom(format!(
88 "column default must be a string, {{ \"expression\": \"...\" }}, or {{ \"value\": \"...\" }}; got object with keys: {:?}",
89 obj.keys().collect::<Vec<_>>()
90 )))
91 }
92 serde_json::Value::Bool(b) => Ok(ColumnDefaultConfig::Literal(b.to_string())),
93 serde_json::Value::Number(n) => Ok(ColumnDefaultConfig::Literal(n.to_string())),
94 other => Err(serde::de::Error::custom(format!(
95 "column default must be a string, boolean, number, or {{ \"expression\": \"...\" }}; got {}",
96 type_name_of_json(&other)
97 ))),
98 }
99 }
100}
101
102fn type_name_of_json(v: &serde_json::Value) -> &'static str {
103 match v {
104 serde_json::Value::Null => "null",
105 serde_json::Value::Bool(_) => "boolean",
106 serde_json::Value::Number(_) => "number",
107 serde_json::Value::String(_) => "string",
108 serde_json::Value::Array(_) => "array",
109 serde_json::Value::Object(_) => "object",
110 }
111}
112
113#[derive(Clone, Debug, Serialize, Deserialize)]
114pub struct ColumnConfig {
115 pub id: String,
116 pub table_id: String,
117 pub name: String,
118 #[serde(rename = "type")]
119 pub type_: ColumnTypeConfig,
120 #[serde(default = "default_true")]
121 pub nullable: bool,
122 #[serde(default)]
123 pub default: Option<ColumnDefaultConfig>,
124 #[serde(default)]
125 pub comment: Option<String>,
126 #[serde(default)]
127 pub asset: Option<AssetColumnConfig>,
128}
129
130fn default_true() -> bool {
131 true
132}
133
134#[derive(Clone, Debug, Serialize, Deserialize)]
135#[serde(untagged)]
136pub enum IndexColumnEntry {
137 Name(String),
138 Spec {
139 name: String,
140 direction: Option<String>,
141 nulls: Option<String>,
142 },
143 Expression {
144 expression: String,
145 },
146}
147
148#[derive(Clone, Debug, Serialize, Deserialize)]
149pub struct IndexConfig {
150 pub id: String,
151 #[serde(default)]
152 pub schema_id: Option<String>,
153 pub table_id: String,
154 pub name: String,
155 #[serde(default)]
156 pub method: Option<String>,
157 #[serde(default)]
158 pub unique: bool,
159 pub columns: Vec<IndexColumnEntry>,
160 #[serde(default)]
161 pub include: Vec<String>,
162 #[serde(default, rename = "where")]
163 pub where_: Option<String>,
164 #[serde(default)]
165 pub comment: Option<String>,
166}
167
168impl IndexConfig {
169 pub fn where_clause(&self) -> Option<&str> {
170 self.where_.as_deref()
171 }
172}
173
174#[derive(Clone, Debug, Serialize, Deserialize)]
175pub struct RelationshipConfig {
176 pub id: String,
177 pub from_schema_id: String,
178 pub from_table_id: String,
179 pub from_column_id: String,
180 pub to_schema_id: String,
181 pub to_table_id: String,
182 pub to_column_id: String,
183 #[serde(default)]
184 pub on_update: Option<String>,
185 #[serde(default)]
186 pub on_delete: Option<String>,
187 #[serde(default)]
188 pub name: Option<String>,
189}
190
191#[derive(Clone, Debug, Default, Serialize, Deserialize)]
192pub struct ValidationRule {
193 #[serde(default)]
194 pub required: Option<bool>,
195 #[serde(default)]
196 pub format: Option<String>,
197 #[serde(default)]
198 pub max_length: Option<u32>,
199 #[serde(default)]
200 pub min_length: Option<u32>,
201 #[serde(default)]
202 pub pattern: Option<String>,
203 #[serde(default)]
204 pub allowed: Option<Vec<serde_json::Value>>,
205 #[serde(default)]
206 pub minimum: Option<f64>,
207 #[serde(default)]
208 pub maximum: Option<f64>,
209 #[serde(default)]
211 pub allowed_mime_types: Option<Vec<String>>,
212 #[serde(default)]
213 pub allowed_extensions: Option<Vec<String>>,
214 #[serde(default)]
215 pub max_size_mb: Option<f64>,
216 #[serde(default)]
217 pub min_size_kb: Option<f64>,
218 #[serde(default)]
219 pub max_filename_length: Option<u32>,
220}
221
222#[derive(Clone, Debug, Serialize, Deserialize)]
223pub struct AssetColumnConfig {
224 #[serde(default)]
226 pub prefix: Option<String>,
227 #[serde(default)]
229 pub compression: Option<String>,
230}
231
232#[derive(Clone, Debug, Serialize, Deserialize)]
233pub struct EventCondition {
234 pub field: String,
236 #[serde(default)]
238 pub changed_to: Option<serde_json::Value>,
239 #[serde(default)]
241 pub equals: Option<serde_json::Value>,
242 #[serde(default)]
244 pub not_null: Option<bool>,
245}
246
247#[derive(Clone, Debug, Serialize, Deserialize)]
248pub struct EntityEventTrigger {
249 pub id: String,
250 pub on: String,
252 #[serde(default)]
255 pub event_name: Option<String>,
256 #[serde(default)]
258 pub condition: Option<EventCondition>,
259}
260
261#[derive(Clone, Debug, Serialize, Deserialize)]
262pub struct ApiEntityConfig {
263 pub entity_id: String,
264 pub path_segment: String,
265 pub operations: Vec<String>,
266 #[serde(default)]
268 pub sensitive_columns: Vec<String>,
269 #[serde(default)]
270 pub validation: std::collections::HashMap<String, ValidationRule>,
271 #[serde(default)]
273 pub archive_field: Option<String>,
274 #[serde(default)]
276 pub events: Vec<EntityEventTrigger>,
277 #[serde(default)]
282 pub parent_ref_column: Option<String>,
283}
284
285#[derive(Clone, Debug, Serialize, Deserialize)]
286pub struct KvStoreConfig {
287 pub id: String,
288 pub namespace: String,
289 #[serde(default)]
290 pub comment: Option<String>,
291}
292
293#[derive(Clone, Debug, Default)]
295pub struct FullConfig {
296 pub schemas: Vec<SchemaConfig>,
297 pub enums: Vec<EnumConfig>,
298 pub tables: Vec<TableConfig>,
299 pub columns: Vec<ColumnConfig>,
300 pub indexes: Vec<IndexConfig>,
301 pub relationships: Vec<RelationshipConfig>,
302 pub api_entities: Vec<ApiEntityConfig>,
303 pub kv_stores: Vec<KvStoreConfig>,
304}