reshape/migrations/
remove_foreign_key.rs1use super::{Action, MigrationContext};
2use crate::{
3 db::{Conn, Transaction},
4 schema::Schema,
5};
6use anyhow::{anyhow, Context};
7use serde::{Deserialize, Serialize};
8
9#[derive(Serialize, Deserialize, Debug)]
10pub struct RemoveForeignKey {
11 table: String,
12 foreign_key: String,
13}
14
15#[typetag::serde(name = "remove_foreign_key")]
16impl Action for RemoveForeignKey {
17 fn describe(&self) -> String {
18 format!(
19 "Removing foreign key \"{}\" from table \"{}\"",
20 self.foreign_key, self.table
21 )
22 }
23
24 fn run(
25 &self,
26 _ctx: &MigrationContext,
27 db: &mut dyn Conn,
28 schema: &Schema,
29 ) -> anyhow::Result<()> {
30 let table = schema.get_table(db, &self.table)?;
42 let fk_exists = !db
43 .query(&format!(
44 r#"
45 SELECT constraint_name
46 FROM information_schema.table_constraints
47 WHERE
48 constraint_type = 'FOREIGN KEY' AND
49 table_name = '{table_name}' AND
50 constraint_name = '{foreign_key}'
51 "#,
52 table_name = table.real_name,
53 foreign_key = self.foreign_key,
54 ))
55 .context("failed to check for foreign key")?
56 .is_empty();
57
58 if !fk_exists {
59 return Err(anyhow!(
60 "no foreign key \"{}\" exists on table \"{}\"",
61 self.foreign_key,
62 self.table
63 ));
64 }
65
66 Ok(())
67 }
68
69 fn complete<'a>(
70 &self,
71 _ctx: &MigrationContext,
72 db: &'a mut dyn Conn,
73 ) -> anyhow::Result<Option<Transaction<'a>>> {
74 db.run(&format!(
75 r#"
76 ALTER TABLE {table}
77 DROP CONSTRAINT IF EXISTS {foreign_key}
78 "#,
79 table = self.table,
80 foreign_key = self.foreign_key,
81 ))
82 .context("failed to remove foreign key")?;
83 Ok(None)
84 }
85
86 fn update_schema(&self, _ctx: &MigrationContext, _schema: &mut Schema) {}
87
88 fn abort(&self, _ctx: &MigrationContext, _db: &mut dyn Conn) -> anyhow::Result<()> {
89 Ok(())
90 }
91}