doido_generators/generators/
storage_install.rs1use crate::generator::{GeneratedFile, Generator};
9use crate::generators::bootstrap_migrations::{
10 apply_bootstrap_migrations, storage_config_section, storage_migration_installed,
11};
12use crate::generators::migration_support::{MIGRATION_LIB_BASE, MIGRATION_SRC_DIR};
13use doido_core::Result;
14
15pub struct StorageInstallGenerator;
16
17fn config_file(path: &str, active: &str) -> Option<GeneratedFile> {
19 let existing = std::fs::read_to_string(path).ok()?;
20 if existing.contains("storage:") {
21 return None;
22 }
23 Some(GeneratedFile {
24 path: path.to_string(),
25 content: format!(
26 "{}\n{}",
27 existing.trim_end(),
28 storage_config_section(active)
29 ),
30 })
31}
32
33impl Generator for StorageInstallGenerator {
34 fn name(&self) -> &str {
35 "storage:install"
36 }
37
38 fn generate(&self, _args: &[&str]) -> Result<Vec<GeneratedFile>> {
39 let lib_path = format!("{MIGRATION_SRC_DIR}/lib.rs");
40 let existing =
41 std::fs::read_to_string(&lib_path).unwrap_or_else(|_| MIGRATION_LIB_BASE.to_string());
42
43 let mut files = Vec::new();
44 if storage_migration_installed(&existing) {
45 files.push(GeneratedFile {
46 path: lib_path,
47 content: existing,
48 });
49 } else {
50 let (lib, migrations) = apply_bootstrap_migrations(&existing, false);
51 files.push(GeneratedFile {
52 path: lib_path,
53 content: lib,
54 });
55 for (module, content) in migrations {
56 files.push(GeneratedFile {
57 path: format!("{MIGRATION_SRC_DIR}/{module}.rs"),
58 content,
59 });
60 }
61 }
62
63 if let Some(f) = config_file("config/development.yml", "local") {
65 files.push(f);
66 }
67 if let Some(f) = config_file("config/test.yml", "test") {
68 files.push(f);
69 }
70
71 Ok(files)
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78 use crate::generators::bootstrap_migrations::STORAGE_MIGRATION_MODULE;
79
80 #[test]
81 fn emits_migration_and_registers_it() {
82 let files = StorageInstallGenerator.generate(&[]).unwrap();
83 let migration = files
85 .iter()
86 .find(|f| f.path.contains(STORAGE_MIGRATION_MODULE) && f.path.ends_with(".rs"))
87 .expect("migration file emitted");
88 assert!(migration.content.contains("storage_blobs"));
89 assert!(migration.content.contains("storage_attachments"));
90 assert!(migration.content.contains("storage_variant_records"));
91 assert!(migration
92 .content
93 .contains("impl MigrationName for Migration"));
94 assert!(!migration.content.contains("DeriveMigrationName"));
95 let module = migration
96 .path
97 .strip_prefix("db/migration/src/")
98 .unwrap()
99 .strip_suffix(".rs")
100 .unwrap();
101 assert!(migration.content.contains(&format!("\"{module}\"")));
102
103 let lib = files
104 .iter()
105 .find(|f| f.path.ends_with("lib.rs"))
106 .expect("lib.rs emitted");
107 assert!(lib.content.contains(STORAGE_MIGRATION_MODULE));
108 }
109}