1use mockforge_data::SchemaDefinition;
8use serde::{Deserialize, Serialize};
9use serde_json::Value;
10use std::collections::HashMap;
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct VbrSchemaDefinition {
15 #[serde(flatten)]
17 pub base: SchemaDefinition,
18
19 pub primary_key: Vec<String>,
21
22 pub foreign_keys: Vec<ForeignKeyDefinition>,
24
25 pub indexes: Vec<IndexDefinition>,
27
28 pub unique_constraints: Vec<UniqueConstraint>,
30
31 pub auto_generation: HashMap<String, AutoGenerationRule>,
33
34 pub many_to_many: Vec<ManyToManyDefinition>,
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize)]
40pub struct ForeignKeyDefinition {
41 pub field: String,
43
44 pub target_entity: String,
46
47 pub target_field: String,
49
50 #[serde(default)]
52 pub on_delete: CascadeAction,
53
54 #[serde(default)]
56 pub on_update: CascadeAction,
57}
58
59#[derive(Debug, Clone, Serialize, Deserialize)]
64pub struct ManyToManyDefinition {
65 pub entity_a: String,
67
68 pub entity_b: String,
70
71 pub junction_table: Option<String>,
74
75 pub entity_a_field: String,
77
78 pub entity_b_field: String,
80
81 #[serde(default)]
83 pub on_delete_a: CascadeAction,
84
85 #[serde(default)]
87 pub on_delete_b: CascadeAction,
88}
89
90impl ManyToManyDefinition {
91 pub fn new(entity_a: String, entity_b: String) -> Self {
93 let (field_a, field_b) = if entity_a.to_lowercase() < entity_b.to_lowercase() {
95 (
96 format!("{}_id", entity_a.to_lowercase()),
97 format!("{}_id", entity_b.to_lowercase()),
98 )
99 } else {
100 (
101 format!("{}_id", entity_b.to_lowercase()),
102 format!("{}_id", entity_a.to_lowercase()),
103 )
104 };
105
106 let junction_table = if entity_a.to_lowercase() < entity_b.to_lowercase() {
107 Some(format!("{}_{}", entity_a.to_lowercase(), entity_b.to_lowercase()))
108 } else {
109 Some(format!("{}_{}", entity_b.to_lowercase(), entity_a.to_lowercase()))
110 };
111
112 Self {
113 entity_a: entity_a.clone(),
114 entity_b: entity_b.clone(),
115 junction_table,
116 entity_a_field: format!("{}_id", entity_a.to_lowercase()),
117 entity_b_field: format!("{}_id", entity_b.to_lowercase()),
118 on_delete_a: CascadeAction::Cascade,
119 on_delete_b: CascadeAction::Cascade,
120 }
121 }
122
123 pub fn with_junction_table(mut self, table_name: String) -> Self {
125 self.junction_table = Some(table_name);
126 self
127 }
128
129 pub fn with_fields(mut self, entity_a_field: String, entity_b_field: String) -> Self {
131 self.entity_a_field = entity_a_field;
132 self.entity_b_field = entity_b_field;
133 self
134 }
135
136 pub fn with_cascade_actions(
138 mut self,
139 on_delete_a: CascadeAction,
140 on_delete_b: CascadeAction,
141 ) -> Self {
142 self.on_delete_a = on_delete_a;
143 self.on_delete_b = on_delete_b;
144 self
145 }
146}
147
148#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
150#[serde(rename_all = "UPPERCASE")]
151pub enum CascadeAction {
152 #[default]
154 NoAction,
155 Cascade,
157 SetNull,
159 SetDefault,
161 Restrict,
163}
164
165#[derive(Debug, Clone, Serialize, Deserialize)]
167pub struct IndexDefinition {
168 pub name: String,
170
171 pub fields: Vec<String>,
173
174 #[serde(default)]
176 pub unique: bool,
177}
178
179#[derive(Debug, Clone, Serialize, Deserialize)]
181pub struct UniqueConstraint {
182 pub name: String,
184
185 pub fields: Vec<String>,
187}
188
189#[derive(Debug, Clone, Serialize, Deserialize)]
191#[serde(tag = "type", rename_all = "snake_case")]
192pub enum AutoGenerationRule {
193 AutoIncrement,
195 Uuid,
197 Timestamp,
199 Date,
201 Custom(String),
203 Pattern(String),
215 Realistic {
223 prefix: String,
225 length: usize,
227 },
228}
229
230impl VbrSchemaDefinition {
231 pub fn new(base: SchemaDefinition) -> Self {
233 Self {
234 base,
235 primary_key: vec!["id".to_string()], foreign_keys: Vec::new(),
237 indexes: Vec::new(),
238 unique_constraints: Vec::new(),
239 auto_generation: HashMap::new(),
240 many_to_many: Vec::new(),
241 }
242 }
243
244 pub fn with_primary_key(mut self, fields: Vec<String>) -> Self {
246 self.primary_key = fields;
247 self
248 }
249
250 pub fn with_foreign_key(mut self, fk: ForeignKeyDefinition) -> Self {
252 self.foreign_keys.push(fk);
253 self
254 }
255
256 pub fn with_index(mut self, index: IndexDefinition) -> Self {
258 self.indexes.push(index);
259 self
260 }
261
262 pub fn with_unique_constraint(mut self, constraint: UniqueConstraint) -> Self {
264 self.unique_constraints.push(constraint);
265 self
266 }
267
268 pub fn with_auto_generation(mut self, field: String, rule: AutoGenerationRule) -> Self {
270 self.auto_generation.insert(field, rule);
271 self
272 }
273
274 pub fn with_many_to_many(mut self, m2m: ManyToManyDefinition) -> Self {
276 self.many_to_many.push(m2m);
277 self
278 }
279}