reshape/migrations/
mod.rs1use crate::{
2 db::{Conn, Transaction},
3 schema::Schema,
4};
5use core::fmt::Debug;
6use serde::{Deserialize, Serialize};
7
8mod common;
10pub use common::Column;
11
12mod create_table;
13pub use create_table::CreateTable;
14
15mod alter_column;
16pub use alter_column::{AlterColumn, ColumnChanges};
17
18mod add_column;
19pub use add_column::AddColumn;
20
21mod remove_column;
22pub use remove_column::RemoveColumn;
23
24mod add_index;
25pub use add_index::{AddIndex, Index};
26
27mod remove_index;
28pub use remove_index::RemoveIndex;
29
30mod remove_table;
31pub use remove_table::RemoveTable;
32
33mod rename_table;
34pub use rename_table::RenameTable;
35
36mod create_enum;
37pub use create_enum::CreateEnum;
38
39mod remove_enum;
40pub use remove_enum::RemoveEnum;
41
42mod custom;
43pub use custom::Custom;
44
45mod add_foreign_key;
46pub use add_foreign_key::AddForeignKey;
47
48mod remove_foreign_key;
49pub use remove_foreign_key::RemoveForeignKey;
50
51#[derive(Serialize, Deserialize, Debug)]
52pub struct Migration {
53 pub name: String,
54 pub description: Option<String>,
55 pub actions: Vec<Box<dyn Action>>,
56}
57
58impl Migration {
59 pub fn new(name: impl Into<String>, description: Option<String>) -> Migration {
60 Migration {
61 name: name.into(),
62 description,
63 actions: vec![],
64 }
65 }
66
67 pub fn with_action(mut self, action: impl Action + 'static) -> Self {
68 self.actions.push(Box::new(action));
69 self
70 }
71}
72
73impl PartialEq for Migration {
74 fn eq(&self, other: &Self) -> bool {
75 self.name == other.name
76 }
77}
78
79impl Eq for Migration {}
80
81impl Clone for Migration {
82 fn clone(&self) -> Self {
83 let serialized = serde_json::to_string(self).unwrap();
84 serde_json::from_str(&serialized).unwrap()
85 }
86}
87
88pub struct MigrationContext {
89 migration_index: usize,
90 action_index: usize,
91 existing_schema_name: Option<String>,
92}
93
94impl MigrationContext {
95 pub fn new(
96 migration_index: usize,
97 action_index: usize,
98 existing_schema_name: Option<String>,
99 ) -> Self {
100 MigrationContext {
101 migration_index,
102 action_index,
103 existing_schema_name,
104 }
105 }
106
107 fn prefix(&self) -> String {
108 format!(
109 "__reshape_{:0>4}_{:0>4}",
110 self.migration_index, self.action_index
111 )
112 }
113
114 fn prefix_inverse(&self) -> String {
115 format!(
116 "__reshape_{:0>4}_{:0>4}",
117 1000 - self.migration_index,
118 1000 - self.action_index
119 )
120 }
121}
122
123#[typetag::serde(tag = "type")]
124pub trait Action: Debug {
125 fn describe(&self) -> String;
126 fn run(&self, ctx: &MigrationContext, db: &mut dyn Conn, schema: &Schema)
127 -> anyhow::Result<()>;
128 fn complete<'a>(
129 &self,
130 ctx: &MigrationContext,
131 db: &'a mut dyn Conn,
132 ) -> anyhow::Result<Option<Transaction<'a>>>;
133 fn update_schema(&self, ctx: &MigrationContext, schema: &mut Schema);
134 fn abort(&self, ctx: &MigrationContext, db: &mut dyn Conn) -> anyhow::Result<()>;
135}