forge_runtime/migrations/
builtin.rs1use super::runner::Migration;
17
18pub const SYSTEM_MIGRATION_PREFIX: &str = "__forge_v";
20
21const V001_INITIAL: &str = include_str!("../../migrations/system/v001_initial.sql");
24
25#[derive(Debug, Clone)]
27pub struct SystemMigration {
28 pub version: u32,
30 pub sql: &'static str,
32 pub description: &'static str,
34}
35
36impl SystemMigration {
37 pub fn name(&self) -> String {
39 format!("{}{:03}", SYSTEM_MIGRATION_PREFIX, self.version)
40 }
41
42 pub fn to_migration(&self) -> Migration {
44 Migration::new(self.name(), self.sql)
45 }
46}
47
48pub fn get_system_migrations() -> Vec<SystemMigration> {
52 vec![SystemMigration {
53 version: 1,
54 sql: V001_INITIAL,
55 description: "Initial FORGE schema with jobs, workflows, crons, daemons, webhooks, and auth",
56 }]
57}
58
59pub fn get_builtin_migrations() -> Vec<Migration> {
61 get_system_migrations()
62 .into_iter()
63 .map(|m| m.to_migration())
64 .collect()
65}
66
67pub fn get_all_system_sql() -> String {
72 get_system_migrations()
73 .into_iter()
74 .map(|m| m.sql)
75 .collect::<Vec<_>>()
76 .join("\n\n")
77}
78
79pub fn is_system_migration(name: &str) -> bool {
81 name.starts_with(SYSTEM_MIGRATION_PREFIX)
82}
83
84pub fn extract_version(name: &str) -> Option<u32> {
87 name.strip_prefix(SYSTEM_MIGRATION_PREFIX)
88 .and_then(|suffix| suffix.parse().ok())
89}
90
91#[cfg(test)]
92#[allow(clippy::unwrap_used, clippy::indexing_slicing, clippy::panic)]
93mod tests {
94 use super::*;
95
96 #[test]
97 fn test_get_system_migrations() {
98 let migrations = get_system_migrations();
99 assert!(!migrations.is_empty());
100 assert_eq!(migrations[0].version, 1);
101 assert_eq!(migrations[0].name(), "__forge_v001");
102 }
103
104 #[test]
105 fn test_migration_sql_not_empty() {
106 let migrations = get_system_migrations();
107 for m in migrations {
108 assert!(!m.sql.is_empty(), "Migration v{} has empty SQL", m.version);
109 }
110 }
111
112 #[test]
113 fn test_migration_sql_contains_tables() {
114 let migrations = get_system_migrations();
115 let sql = migrations[0].sql;
116
117 assert!(sql.contains("forge_nodes"));
119 assert!(sql.contains("forge_leaders"));
120 assert!(sql.contains("forge_jobs"));
121 assert!(sql.contains("forge_cron_runs"));
122 assert!(sql.contains("forge_workflow_runs"));
123 assert!(sql.contains("forge_workflow_steps"));
124 assert!(sql.contains("forge_sessions"));
125 assert!(sql.contains("forge_subscriptions"));
126 assert!(sql.contains("forge_daemons"));
127 assert!(sql.contains("forge_webhook_events"));
128 assert!(sql.contains("forge_refresh_tokens"));
129 assert!(sql.contains("forge_oauth_clients"));
130 assert!(sql.contains("forge_oauth_codes"));
131
132 assert!(sql.contains("forge_signals_events"));
134 assert!(sql.contains("forge_signals_sessions"));
135 assert!(sql.contains("forge_signals_users"));
136 }
137
138 #[test]
139 fn test_is_system_migration() {
140 assert!(is_system_migration("__forge_v001"));
141 assert!(is_system_migration("__forge_v002"));
142 assert!(is_system_migration("__forge_v100"));
143 assert!(!is_system_migration("0001_create_users"));
144 assert!(!is_system_migration("user_migration"));
145 }
146
147 #[test]
148 fn test_extract_version() {
149 assert_eq!(extract_version("__forge_v001"), Some(1));
150 assert_eq!(extract_version("__forge_v002"), Some(2));
151 assert_eq!(extract_version("__forge_v100"), Some(100));
152 assert_eq!(extract_version("0001_create_users"), None);
153 assert_eq!(extract_version("invalid"), None);
154 }
155
156 #[test]
157 fn test_system_migrations_version_ordering() {
158 let migrations = get_system_migrations();
159 for window in migrations.windows(2) {
160 assert!(
161 window[0].version < window[1].version,
162 "Migrations must be in ascending version order: v{} >= v{}",
163 window[0].version,
164 window[1].version,
165 );
166 }
167 }
168
169 #[test]
170 fn test_system_migration_to_migration() {
171 let sys = SystemMigration {
172 version: 1,
173 sql: "SELECT 1;",
174 description: "Test",
175 };
176 let m = sys.to_migration();
177 assert_eq!(m.name, "__forge_v001");
178 assert_eq!(m.up_sql, "SELECT 1;");
179 }
180}