1use crate::entities::{Entity, EntityRegistry};
7use crate::schema::{CascadeAction, ManyToManyDefinition, VbrSchemaDefinition};
8use crate::{Error, Result};
9
10pub struct MigrationManager {
12 #[allow(dead_code)]
14 version: u64,
15}
16
17impl MigrationManager {
18 pub fn new() -> Self {
20 Self { version: 0 }
21 }
22
23 pub fn generate_create_table(&self, entity: &Entity) -> Result<String> {
25 let schema = &entity.schema;
26 let table_name = entity.table_name();
27
28 let mut sql = format!("CREATE TABLE IF NOT EXISTS {} (\n", table_name);
29 let mut columns = Vec::new();
30
31 for field in &schema.base.fields {
33 let column_def = self.field_to_column_definition(field, schema)?;
34 columns.push(column_def);
35 }
36
37 if !schema.primary_key.is_empty() {
39 let pk_fields = schema.primary_key.join(", ");
40 columns.push(format!("PRIMARY KEY ({})", pk_fields));
41 }
42
43 sql.push_str(&columns.join(",\n "));
44 sql.push_str("\n)");
45
46 Ok(sql)
47 }
48
49 pub fn generate_foreign_keys(&self, entity: &Entity) -> Vec<String> {
51 let mut fk_statements = Vec::new();
52 let table_name = entity.table_name();
53
54 for fk in &entity.schema.foreign_keys {
55 let on_delete = cascade_action_to_sql(fk.on_delete);
56 let on_update = cascade_action_to_sql(fk.on_update);
57
58 let fk_name = format!("fk_{}_{}", table_name, fk.field);
59 let statement = format!(
60 "ALTER TABLE {} ADD CONSTRAINT {} FOREIGN KEY ({}) REFERENCES {}({}) ON DELETE {} ON UPDATE {}",
61 table_name, fk_name, fk.field, fk.target_entity.to_lowercase() + "s", fk.target_field, on_delete, on_update
62 );
63 fk_statements.push(statement);
64 }
65
66 fk_statements
67 }
68
69 pub fn generate_indexes(&self, entity: &Entity) -> Vec<String> {
71 let mut index_statements = Vec::new();
72 let table_name = entity.table_name();
73
74 for index in &entity.schema.indexes {
75 let unique = if index.unique { "UNIQUE " } else { "" };
76 let fields = index.fields.join(", ");
77 let statement = format!(
78 "CREATE {}INDEX IF NOT EXISTS {} ON {} ({})",
79 unique, index.name, table_name, fields
80 );
81 index_statements.push(statement);
82 }
83
84 index_statements
85 }
86
87 pub fn generate_junction_table(&self, m2m: &ManyToManyDefinition) -> Result<String> {
89 let junction_table = m2m
90 .junction_table
91 .as_ref()
92 .ok_or_else(|| Error::generic("Junction table name is required".to_string()))?;
93
94 let table_a = m2m.entity_a.to_lowercase() + "s";
96 let table_b = m2m.entity_b.to_lowercase() + "s";
97
98 let on_delete_a = cascade_action_to_sql(m2m.on_delete_a);
99 let on_delete_b = cascade_action_to_sql(m2m.on_delete_b);
100
101 let sql = format!(
103 "CREATE TABLE IF NOT EXISTS {} (
104 {} TEXT NOT NULL,
105 {} TEXT NOT NULL,
106 PRIMARY KEY ({}, {}),
107 FOREIGN KEY ({}) REFERENCES {}(id) ON DELETE {},
108 FOREIGN KEY ({}) REFERENCES {}(id) ON DELETE {}
109)",
110 junction_table,
111 m2m.entity_a_field,
112 m2m.entity_b_field,
113 m2m.entity_a_field,
114 m2m.entity_b_field,
115 m2m.entity_a_field,
116 table_a,
117 on_delete_a,
118 m2m.entity_b_field,
119 table_b,
120 on_delete_b
121 );
122
123 Ok(sql)
124 }
125
126 pub fn generate_all_junction_tables(
128 &self,
129 registry: &EntityRegistry,
130 ) -> Result<Vec<(String, String)>> {
131 let mut junction_tables = Vec::new();
132 let mut processed = std::collections::HashSet::new();
133
134 for entity in registry.list() {
136 if let Some(entity_def) = registry.get(&entity) {
137 for m2m in &entity_def.schema.many_to_many {
138 let (a, b) = if m2m.entity_a < m2m.entity_b {
140 (m2m.entity_a.clone(), m2m.entity_b.clone())
141 } else {
142 (m2m.entity_b.clone(), m2m.entity_a.clone())
143 };
144 let key = format!("{}:{}", a, b);
145
146 if !processed.contains(&key) {
147 processed.insert(key);
148 let table_name = m2m
149 .junction_table
150 .as_ref()
151 .ok_or_else(|| {
152 Error::generic("Junction table name is required".to_string())
153 })?
154 .clone();
155 let create_sql = self.generate_junction_table(m2m)?;
156 junction_tables.push((table_name, create_sql));
157 }
158 }
159 }
160 }
161
162 Ok(junction_tables)
163 }
164
165 fn field_to_column_definition(
167 &self,
168 field: &mockforge_data::FieldDefinition,
169 schema: &VbrSchemaDefinition,
170 ) -> Result<String> {
171 let name = &field.name;
172 let sql_type = rust_type_to_sql_type(&field.field_type)?;
173 let mut parts = vec![format!("{} {}", name, sql_type)];
174
175 if field.required {
177 parts.push("NOT NULL".to_string());
178 }
179
180 if let Some(default) = &field.default {
182 let default_value = value_to_sql_default(default)?;
183 parts.push(format!("DEFAULT {}", default_value));
184 }
185
186 if let Some(rule) = schema.auto_generation.get(name) {
188 match rule {
189 crate::schema::AutoGenerationRule::AutoIncrement => {
190 parts.push("AUTOINCREMENT".to_string());
191 }
192 crate::schema::AutoGenerationRule::Uuid => {
193 }
195 crate::schema::AutoGenerationRule::Timestamp => {
196 parts.push("DEFAULT CURRENT_TIMESTAMP".to_string());
197 }
198 crate::schema::AutoGenerationRule::Date => {
199 parts.push("DEFAULT (date('now'))".to_string());
200 }
201 crate::schema::AutoGenerationRule::Custom(expr) => {
202 parts.push(format!("DEFAULT ({})", expr));
203 }
204 crate::schema::AutoGenerationRule::Pattern(_) => {
205 }
207 crate::schema::AutoGenerationRule::Realistic { .. } => {
208 }
210 }
211 }
212
213 Ok(parts.join(" "))
214 }
215
216 pub async fn migrate(
218 &self,
219 entities: &[Entity],
220 database: &mut dyn crate::database::VirtualDatabase,
221 ) -> Result<()> {
222 for entity in entities {
224 let create_table = self.generate_create_table(entity)?;
225 database.create_table(&create_table).await?;
226
227 for index_sql in self.generate_indexes(entity) {
229 database.execute(&index_sql, &[]).await?;
230 }
231
232 }
235
236 for entity in entities {
238 for fk_sql in self.generate_foreign_keys(entity) {
239 let _ = database.execute(&fk_sql, &[]).await;
241 }
242 }
243
244 Ok(())
245 }
246}
247
248impl Default for MigrationManager {
249 fn default() -> Self {
250 Self::new()
251 }
252}
253
254pub async fn create_table_for_entity(
263 database: &dyn crate::database::VirtualDatabase,
264 entity: &Entity,
265) -> Result<()> {
266 let manager = MigrationManager::new();
267
268 let create_table = manager.generate_create_table(entity)?;
270 database.create_table(&create_table).await?;
271
272 for index_sql in manager.generate_indexes(entity) {
274 database.execute(&index_sql, &[]).await?;
275 }
276
277 for fk_sql in manager.generate_foreign_keys(entity) {
279 let _ = database.execute(&fk_sql, &[]).await;
282 }
283
284 Ok(())
285}
286
287pub async fn create_junction_tables(
293 database: &dyn crate::database::VirtualDatabase,
294 registry: &EntityRegistry,
295) -> Result<()> {
296 let manager = MigrationManager::new();
297 let junction_tables = manager.generate_all_junction_tables(registry)?;
298
299 for (_table_name, create_sql) in junction_tables {
300 database.create_table(&create_sql).await?;
301 }
302
303 Ok(())
304}
305
306fn rust_type_to_sql_type(rust_type: &str) -> Result<&str> {
308 match rust_type.to_lowercase().as_str() {
309 "string" | "str" | "text" | "uuid" | "email" | "url" => Ok("TEXT"),
310 "integer" | "int" | "i32" | "i64" => Ok("INTEGER"),
311 "float" | "double" | "f32" | "f64" | "number" => Ok("REAL"),
312 "boolean" | "bool" => Ok("INTEGER"), "date" | "datetime" | "timestamp" => Ok("TEXT"), _ => Ok("TEXT"), }
316}
317
318fn cascade_action_to_sql(action: CascadeAction) -> &'static str {
320 match action {
321 CascadeAction::NoAction => "NO ACTION",
322 CascadeAction::Cascade => "CASCADE",
323 CascadeAction::SetNull => "SET NULL",
324 CascadeAction::SetDefault => "SET DEFAULT",
325 CascadeAction::Restrict => "RESTRICT",
326 }
327}
328
329fn value_to_sql_default(value: &serde_json::Value) -> Result<String> {
331 match value {
332 serde_json::Value::String(s) => Ok(format!("'{}'", s.replace("'", "''"))),
333 serde_json::Value::Number(n) => Ok(n.to_string()),
334 serde_json::Value::Bool(b) => Ok(if *b { "1" } else { "0" }.to_string()),
335 serde_json::Value::Null => Ok("NULL".to_string()),
336 _ => Err(Error::generic("Unsupported default value type".to_string())),
337 }
338}
339
340#[cfg(test)]
341mod tests {
342 use super::*;
343 use crate::database::{InMemoryDatabase, VirtualDatabase};
344 use crate::schema::{
345 AutoGenerationRule, CascadeAction, ForeignKeyDefinition, IndexDefinition,
346 ManyToManyDefinition,
347 };
348 use mockforge_data::{FieldDefinition, SchemaDefinition};
349
350 fn create_test_entity(name: &str) -> Entity {
351 let base_schema = SchemaDefinition::new(name.to_string())
352 .with_field(FieldDefinition::new("id".to_string(), "string".to_string()))
353 .with_field(FieldDefinition::new("name".to_string(), "string".to_string()));
354
355 let vbr_schema = VbrSchemaDefinition::new(base_schema);
356 Entity::new(name.to_string(), vbr_schema)
357 }
358
359 #[test]
361 fn test_migration_manager_new() {
362 let manager = MigrationManager::new();
363 assert_eq!(manager.version, 0);
364 }
365
366 #[test]
367 fn test_migration_manager_default() {
368 let manager = MigrationManager::default();
369 assert_eq!(manager.version, 0);
370 }
371
372 #[test]
373 fn test_generate_create_table() {
374 let manager = MigrationManager::new();
375 let entity = create_test_entity("User");
376
377 let result = manager.generate_create_table(&entity);
378 assert!(result.is_ok());
379
380 let sql = result.unwrap();
381 assert!(sql.contains("CREATE TABLE IF NOT EXISTS users"));
382 assert!(sql.contains("id TEXT"));
383 assert!(sql.contains("name TEXT"));
384 assert!(sql.contains("PRIMARY KEY (id)"));
385 }
386
387 #[test]
388 fn test_generate_create_table_with_multiple_fields() {
389 let manager = MigrationManager::new();
390
391 let base_schema = SchemaDefinition::new("Product".to_string())
392 .with_field(FieldDefinition::new("id".to_string(), "string".to_string()))
393 .with_field(FieldDefinition::new("name".to_string(), "string".to_string()))
394 .with_field(FieldDefinition::new("price".to_string(), "number".to_string()))
395 .with_field(FieldDefinition::new("in_stock".to_string(), "boolean".to_string()));
396
397 let vbr_schema = VbrSchemaDefinition::new(base_schema);
398 let entity = Entity::new("Product".to_string(), vbr_schema);
399
400 let sql = manager.generate_create_table(&entity).unwrap();
401 assert!(sql.contains("name TEXT"));
402 assert!(sql.contains("price REAL"));
403 assert!(sql.contains("in_stock INTEGER"));
404 }
405
406 #[test]
407 fn test_generate_foreign_keys() {
408 let manager = MigrationManager::new();
409
410 let base_schema = SchemaDefinition::new("Order".to_string())
411 .with_field(FieldDefinition::new("id".to_string(), "string".to_string()));
412
413 let mut vbr_schema = VbrSchemaDefinition::new(base_schema);
414 vbr_schema.foreign_keys.push(ForeignKeyDefinition {
415 field: "user_id".to_string(),
416 target_entity: "User".to_string(),
417 target_field: "id".to_string(),
418 on_delete: CascadeAction::Cascade,
419 on_update: CascadeAction::NoAction,
420 });
421
422 let entity = Entity::new("Order".to_string(), vbr_schema);
423
424 let fk_statements = manager.generate_foreign_keys(&entity);
425 assert_eq!(fk_statements.len(), 1);
426 assert!(fk_statements[0].contains("FOREIGN KEY"));
427 assert!(fk_statements[0].contains("user_id"));
428 assert!(fk_statements[0].contains("CASCADE"));
429 }
430
431 #[test]
432 fn test_generate_indexes() {
433 let manager = MigrationManager::new();
434
435 let base_schema = SchemaDefinition::new("User".to_string());
436 let mut vbr_schema = VbrSchemaDefinition::new(base_schema);
437
438 vbr_schema.indexes.push(IndexDefinition {
439 name: "idx_email".to_string(),
440 fields: vec!["email".to_string()],
441 unique: true,
442 });
443
444 let entity = Entity::new("User".to_string(), vbr_schema);
445
446 let index_statements = manager.generate_indexes(&entity);
447 assert_eq!(index_statements.len(), 1);
448 assert!(index_statements[0].contains("CREATE UNIQUE INDEX"));
449 assert!(index_statements[0].contains("idx_email"));
450 assert!(index_statements[0].contains("email"));
451 }
452
453 #[test]
454 fn test_generate_indexes_non_unique() {
455 let manager = MigrationManager::new();
456
457 let base_schema = SchemaDefinition::new("Product".to_string());
458 let mut vbr_schema = VbrSchemaDefinition::new(base_schema);
459
460 vbr_schema.indexes.push(IndexDefinition {
461 name: "idx_category".to_string(),
462 fields: vec!["category".to_string()],
463 unique: false,
464 });
465
466 let entity = Entity::new("Product".to_string(), vbr_schema);
467
468 let index_statements = manager.generate_indexes(&entity);
469 assert_eq!(index_statements.len(), 1);
470 assert!(index_statements[0].contains("CREATE INDEX"));
471 assert!(!index_statements[0].contains("UNIQUE"));
472 }
473
474 #[test]
475 fn test_generate_junction_table() {
476 let manager = MigrationManager::new();
477
478 let m2m = ManyToManyDefinition::new("User".to_string(), "Role".to_string());
479
480 let result = manager.generate_junction_table(&m2m);
481 assert!(result.is_ok());
482
483 let sql = result.unwrap();
484 assert!(sql.contains("CREATE TABLE IF NOT EXISTS"));
485 assert!(sql.contains("user_id"));
486 assert!(sql.contains("role_id"));
487 assert!(sql.contains("PRIMARY KEY"));
488 assert!(sql.contains("FOREIGN KEY"));
489 }
490
491 #[test]
492 fn test_generate_junction_table_custom() {
493 let manager = MigrationManager::new();
494
495 let m2m = ManyToManyDefinition::new("User".to_string(), "Role".to_string())
496 .with_junction_table("user_role_mapping".to_string())
497 .with_fields("usr_id".to_string(), "rol_id".to_string());
498
499 let sql = manager.generate_junction_table(&m2m).unwrap();
500 assert!(sql.contains("user_role_mapping"));
501 assert!(sql.contains("usr_id"));
502 assert!(sql.contains("rol_id"));
503 }
504
505 #[test]
506 fn test_generate_all_junction_tables() {
507 let manager = MigrationManager::new();
508 let mut registry = EntityRegistry::new();
509
510 let base_schema1 = SchemaDefinition::new("User".to_string());
512 let mut vbr_schema1 = VbrSchemaDefinition::new(base_schema1);
513 vbr_schema1
514 .many_to_many
515 .push(ManyToManyDefinition::new("User".to_string(), "Role".to_string()));
516 let entity1 = Entity::new("User".to_string(), vbr_schema1);
517 registry.register(entity1).unwrap();
518
519 let base_schema2 = SchemaDefinition::new("Role".to_string());
520 let vbr_schema2 = VbrSchemaDefinition::new(base_schema2);
521 let entity2 = Entity::new("Role".to_string(), vbr_schema2);
522 registry.register(entity2).unwrap();
523
524 let result = manager.generate_all_junction_tables(®istry);
525 assert!(result.is_ok());
526
527 let junction_tables = result.unwrap();
528 assert_eq!(junction_tables.len(), 1);
529 }
530
531 #[test]
532 fn test_generate_all_junction_tables_no_duplicates() {
533 let manager = MigrationManager::new();
534 let mut registry = EntityRegistry::new();
535
536 let base_schema1 = SchemaDefinition::new("User".to_string());
538 let mut vbr_schema1 = VbrSchemaDefinition::new(base_schema1);
539 vbr_schema1
540 .many_to_many
541 .push(ManyToManyDefinition::new("User".to_string(), "Role".to_string()));
542 let entity1 = Entity::new("User".to_string(), vbr_schema1);
543 registry.register(entity1).unwrap();
544
545 let base_schema2 = SchemaDefinition::new("Role".to_string());
546 let mut vbr_schema2 = VbrSchemaDefinition::new(base_schema2);
547 vbr_schema2
548 .many_to_many
549 .push(ManyToManyDefinition::new("Role".to_string(), "User".to_string()));
550 let entity2 = Entity::new("Role".to_string(), vbr_schema2);
551 registry.register(entity2).unwrap();
552
553 let junction_tables = manager.generate_all_junction_tables(®istry).unwrap();
554 assert_eq!(junction_tables.len(), 1);
556 }
557
558 #[tokio::test]
559 async fn test_migrate() {
560 let manager = MigrationManager::new();
561 let mut database = InMemoryDatabase::new().await.unwrap();
562 database.initialize().await.unwrap();
563
564 let entity = create_test_entity("User");
565 let entities = vec![entity];
566
567 let result = manager.migrate(&entities, &mut database).await;
568 assert!(result.is_ok());
569
570 assert!(database.table_exists("users").await.unwrap());
572 }
573
574 #[tokio::test]
575 async fn test_create_table_for_entity() {
576 let mut database = InMemoryDatabase::new().await.unwrap();
577 database.initialize().await.unwrap();
578
579 let entity = create_test_entity("Product");
580
581 let result = create_table_for_entity(&database, &entity).await;
582 assert!(result.is_ok());
583
584 assert!(database.table_exists("products").await.unwrap());
586 }
587
588 #[tokio::test]
589 async fn test_create_junction_tables() {
590 let mut database = InMemoryDatabase::new().await.unwrap();
591 database.initialize().await.unwrap();
592
593 let mut registry = EntityRegistry::new();
594
595 let base_schema1 = SchemaDefinition::new("User".to_string());
597 let mut vbr_schema1 = VbrSchemaDefinition::new(base_schema1);
598 vbr_schema1
599 .many_to_many
600 .push(ManyToManyDefinition::new("User".to_string(), "Group".to_string()));
601 let entity1 = Entity::new("User".to_string(), vbr_schema1);
602 registry.register(entity1).unwrap();
603
604 let result = create_junction_tables(&database, ®istry).await;
605 assert!(result.is_ok());
606 }
607
608 #[test]
610 fn test_rust_type_to_sql_type() {
611 assert_eq!(rust_type_to_sql_type("string").unwrap(), "TEXT");
612 assert_eq!(rust_type_to_sql_type("String").unwrap(), "TEXT");
613 assert_eq!(rust_type_to_sql_type("integer").unwrap(), "INTEGER");
614 assert_eq!(rust_type_to_sql_type("int").unwrap(), "INTEGER");
615 assert_eq!(rust_type_to_sql_type("i32").unwrap(), "INTEGER");
616 assert_eq!(rust_type_to_sql_type("float").unwrap(), "REAL");
617 assert_eq!(rust_type_to_sql_type("f64").unwrap(), "REAL");
618 assert_eq!(rust_type_to_sql_type("boolean").unwrap(), "INTEGER");
619 assert_eq!(rust_type_to_sql_type("bool").unwrap(), "INTEGER");
620 assert_eq!(rust_type_to_sql_type("date").unwrap(), "TEXT");
621 assert_eq!(rust_type_to_sql_type("datetime").unwrap(), "TEXT");
622 assert_eq!(rust_type_to_sql_type("unknown_type").unwrap(), "TEXT");
623 }
624
625 #[test]
626 fn test_cascade_action_to_sql() {
627 assert_eq!(cascade_action_to_sql(CascadeAction::NoAction), "NO ACTION");
628 assert_eq!(cascade_action_to_sql(CascadeAction::Cascade), "CASCADE");
629 assert_eq!(cascade_action_to_sql(CascadeAction::SetNull), "SET NULL");
630 assert_eq!(cascade_action_to_sql(CascadeAction::SetDefault), "SET DEFAULT");
631 assert_eq!(cascade_action_to_sql(CascadeAction::Restrict), "RESTRICT");
632 }
633
634 #[test]
635 fn test_value_to_sql_default() {
636 let result = value_to_sql_default(&serde_json::json!("test")).unwrap();
638 assert_eq!(result, "'test'");
639
640 let result = value_to_sql_default(&serde_json::json!("it's")).unwrap();
642 assert_eq!(result, "'it''s'");
643
644 let result = value_to_sql_default(&serde_json::json!(42)).unwrap();
646 assert_eq!(result, "42");
647
648 let result = value_to_sql_default(&serde_json::json!(true)).unwrap();
650 assert_eq!(result, "1");
651
652 let result = value_to_sql_default(&serde_json::json!(false)).unwrap();
654 assert_eq!(result, "0");
655
656 let result = value_to_sql_default(&serde_json::json!(null)).unwrap();
658 assert_eq!(result, "NULL");
659
660 let result = value_to_sql_default(&serde_json::json!([]));
662 assert!(result.is_err());
663 }
664
665 #[test]
666 fn test_field_to_column_definition_with_auto_generation() {
667 let manager = MigrationManager::new();
668
669 let base_schema = SchemaDefinition::new("User".to_string())
670 .with_field(FieldDefinition::new("id".to_string(), "string".to_string()));
671
672 let mut vbr_schema = VbrSchemaDefinition::new(base_schema);
673 vbr_schema.auto_generation.insert("id".to_string(), AutoGenerationRule::Uuid);
674
675 let field = &vbr_schema.base.fields[0];
677 let result = manager.field_to_column_definition(field, &vbr_schema);
678 assert!(result.is_ok());
679
680 let column_def = result.unwrap();
681 assert!(column_def.contains("id"));
682 assert!(column_def.contains("TEXT"));
683 }
684
685 #[test]
686 fn test_field_to_column_definition_with_default() {
687 let manager = MigrationManager::new();
688
689 let mut field = FieldDefinition::new("status".to_string(), "string".to_string());
690 field.default = Some(serde_json::json!("active"));
691 let base_schema = SchemaDefinition::new("User".to_string()).with_field(field);
692
693 let vbr_schema = VbrSchemaDefinition::new(base_schema);
694 let field_ref = &vbr_schema.base.fields[0];
695
696 let column_def = manager.field_to_column_definition(field_ref, &vbr_schema).unwrap();
697 assert!(column_def.contains("DEFAULT 'active'"));
698 }
699
700 #[test]
701 fn test_field_to_column_definition_required() {
702 let manager = MigrationManager::new();
703
704 let base_schema = SchemaDefinition::new("User".to_string())
705 .with_field(FieldDefinition::new("email".to_string(), "string".to_string()));
706
707 let vbr_schema = VbrSchemaDefinition::new(base_schema);
708 let field = &vbr_schema.base.fields[0];
709
710 let column_def = manager.field_to_column_definition(field, &vbr_schema).unwrap();
711 assert!(column_def.contains("NOT NULL"));
712 }
713
714 #[test]
715 fn test_generate_create_table_with_composite_primary_key() {
716 let manager = MigrationManager::new();
717
718 let base_schema = SchemaDefinition::new("UserRole".to_string());
719 let vbr_schema = VbrSchemaDefinition::new(base_schema)
720 .with_primary_key(vec!["user_id".to_string(), "role_id".to_string()]);
721
722 let entity = Entity::new("UserRole".to_string(), vbr_schema);
723
724 let sql = manager.generate_create_table(&entity).unwrap();
725 assert!(sql.contains("PRIMARY KEY (user_id, role_id)"));
726 }
727
728 #[test]
729 fn test_generate_create_table_with_auto_increment() {
730 let manager = MigrationManager::new();
731
732 let base_schema = SchemaDefinition::new("Counter".to_string())
733 .with_field(FieldDefinition::new("id".to_string(), "integer".to_string()));
734
735 let mut vbr_schema = VbrSchemaDefinition::new(base_schema);
736 vbr_schema
737 .auto_generation
738 .insert("id".to_string(), AutoGenerationRule::AutoIncrement);
739
740 let entity = Entity::new("Counter".to_string(), vbr_schema);
741
742 let sql = manager.generate_create_table(&entity).unwrap();
743 assert!(sql.contains("AUTOINCREMENT"));
744 }
745}