good_ormning/sqlite/graph/
field.rs

1use std::collections::{
2    HashSet,
3    HashMap,
4};
5use crate::{
6    sqlite::{
7        schema::field::Field,
8        types::{
9            to_sql_type,
10            Type,
11        },
12        query::{
13            utils::SqliteQueryCtx,
14            expr::{
15                ExprType,
16                Binding,
17                check_same,
18            },
19        },
20    },
21    graphmigrate::Comparison,
22    utils::Tokens,
23};
24use super::{
25    GraphId,
26    utils::{
27        SqliteNodeData,
28        SqliteMigrateCtx,
29        SqliteNodeDataDispatch,
30    },
31    Node,
32};
33
34#[derive(Clone)]
35pub(crate) struct NodeField_ {
36    pub def: Field,
37}
38
39impl NodeField_ {
40    pub fn compare(&self, old: &Self, created: &HashSet<GraphId>) -> Comparison {
41        if created.contains(&GraphId::Table(self.def.table.0.schema_id.clone())) {
42            return Comparison::Recreate;
43        }
44        let t = &self.def.type_.type_;
45        let old_t = &old.def.type_.type_;
46        if self.def.id != old.def.id || t.opt != old_t.opt || t.type_.type_ != old_t.type_.type_ {
47            Comparison::Update
48        } else {
49            Comparison::DoNothing
50        }
51    }
52
53    fn display_path(&self) -> rpds::Vector<String> {
54        rpds::vector![self.def.to_string()]
55    }
56}
57
58impl SqliteNodeData for NodeField_ {
59    fn update(&self, ctx: &mut SqliteMigrateCtx, old: &Self) {
60        if self.def.id != old.def.id {
61            let mut stmt = Tokens::new();
62            stmt
63                .s("alter table")
64                .id(&self.def.table.0.id)
65                .s("rename column")
66                .id(&old.def.id)
67                .s("to")
68                .id(&self.def.id);
69            ctx.statements.push(stmt.to_string());
70        }
71        let t = &self.def.type_.type_;
72        let old_t = &old.def.type_.type_;
73        if t.opt != old_t.opt {
74            ctx.errs.err(&self.display_path(), format!("Column optionality cannot be changed in sqlite"));
75        }
76        if t.type_.type_ != old_t.type_.type_ {
77            ctx.errs.err(&self.display_path(), format!("Column types cannot be changed in sqlite"));
78        }
79    }
80}
81
82impl SqliteNodeDataDispatch for NodeField_ {
83    fn create(&self, ctx: &mut SqliteMigrateCtx) {
84        let path = self.display_path();
85        if &self.def.schema_id.0 == "rowid" {
86            return;
87        }
88        let mut stmt = Tokens::new();
89        stmt
90            .s("alter table")
91            .id(&self.def.table.0.id)
92            .s("add column")
93            .id(&self.def.id)
94            .s(to_sql_type(&self.def.type_.type_.type_.type_));
95        if !self.def.type_.type_.opt {
96            if let Some(d) = &self.def.type_.migration_default {
97                stmt.s("not null default");
98                let mut qctx = SqliteQueryCtx::new(ctx.errs.clone(), HashMap::new());
99                let e_res = d.build(&mut qctx, &path, &HashMap::new());
100                check_same(&mut qctx.errs, &path, &ExprType(vec![(Binding::empty(), Type {
101                    type_: self.def.type_.type_.type_.clone(),
102                    opt: false,
103                    array: false,
104                })]), &e_res.0);
105                if !qctx.rust_args.is_empty() {
106                    qctx
107                        .errs
108                        .err(
109                            &path,
110                            format!(
111                                "Default expressions must not have any parameters, but this has {} parameters",
112                                qctx.rust_args.len()
113                            ),
114                        );
115                }
116                stmt.s(&e_res.1.to_string());
117            } else {
118                ctx.errs.err(&path, format!("New column missing default"));
119            }
120        }
121        ctx.statements.push(stmt.to_string());
122    }
123
124    fn delete(&self, ctx: &mut SqliteMigrateCtx) {
125        if &self.def.schema_id.0 == "rowid" {
126            return;
127        }
128        ctx
129            .statements
130            .push(
131                Tokens::new().s("alter table").id(&self.def.table.id).s("drop column").id(&self.def.id).to_string(),
132            );
133    }
134
135    fn create_coalesce(&mut self, other: Node) -> Option<Node> {
136        Some(other)
137    }
138
139    fn delete_coalesce(&mut self, other: Node) -> Option<Node> {
140        Some(other)
141    }
142}