Skip to main content

safe_migrate/analysis/
mutations.rs

1// FILE: src/analysis/mutations.rs
2use crate::analysis::expr_ir::ExprIr;
3use crate::analysis::facts::{SearchPathTarget, TableConstraintFact};
4use crate::ast::identifiers::ObjectId;
5use crate::model::types::TypeKind;
6
7#[derive(Clone, Debug, PartialEq)]
8pub enum PersistenceMutation {
9    Permanent,
10    Temporary,
11    Unlogged,
12}
13
14#[derive(Clone, Debug, PartialEq)]
15pub enum Mutation {
16    CreateSchema(CreateSchemaMutation),
17    DropSchema(DropSchemaMutation),
18    CreateTable(CreateTable),
19    CreateView(CreateView),
20    CreateMaterializedView(CreateMaterializedView),
21    RefreshMaterializedView(RefreshMaterializedViewMutation),
22    CreateIndex(CreateIndex),
23    CreatePolicy(CreatePolicyMutation),
24    DropPolicy(DropPolicyMutation),
25    CreateTrigger(CreateTriggerMutation),
26    DropTrigger(DropTriggerMutation),
27    AlterTable(AlterTable),
28    CreateType(CreateTypeMutation),
29    AlterType(AlterTypeMutation),
30    CreateDomain(CreateDomainMutation),
31    AlterDomain(AlterDomainMutation),
32    DropDomain(DropDomainMutation),
33    DropType(DropTypeMutation),
34    CreateSequence(CreateSequenceMutation),
35    AlterSequence(AlterSequenceMutation),
36    DropSequence(DropSequenceMutation),
37    Rename(Rename),
38    DropTable(DropTable),
39    DropView(DropViewMutation),
40    DropMaterializedView(DropMaterializedViewMutation),
41    DropIndex(DropIndex),
42    ChangeRelationOwner {
43        id: ObjectId,
44        new_owner: crate::analysis::facts::RoleFact,
45    },
46    SearchPath(SearchPathChange),
47    BeginTransaction,
48    CommitTransaction,
49    CommitAndChain,
50    RollbackTransaction,
51    RollbackAndChain,
52    RollbackToSavepoint(RollbackToSavepointMutation),
53    Savepoint(SavepointMutation),
54    ReleaseSavepoint(ReleaseSavepointMutation),
55    CreateFunction(CreateFunctionMutation),
56    AlterFunction(AlterFunctionMutation),
57    DropFunction(DropFunctionMutation),
58    CreateProcedure(CreateProcedureMutation),
59    AlterProcedure(AlterProcedureMutation),
60    DropProcedure(DropProcedureMutation),
61    CreatePublication(CreatePublicationMutation),
62    AlterPublication(AlterPublicationMutation),
63    DropPublication(DropPublicationMutation),
64    CreateSubscription(CreateSubscriptionMutation),
65    AlterSubscription(AlterSubscriptionMutation),
66    DropSubscription(DropSubscriptionMutation),
67    CreateRole(CreateRoleMutation),
68    AlterRole(AlterRoleMutation),
69    DropRole(DropRoleMutation),
70    Grant(GrantMutation),
71    Revoke(RevokeMutation),
72    CreateDatabase(CreateDatabaseMutation),
73    AlterDatabase(AlterDatabaseMutation),
74    DropDatabase(DropDatabaseMutation),
75    /// Produced by `SET [LOCAL] ROLE` and `SET [LOCAL] SESSION AUTHORIZATION`.
76    /// `role = None` means ROLE NONE / SESSION AUTHORIZATION DEFAULT.
77    /// `local = true` means the active value expires at transaction end.
78    SwitchRole {
79        role: Option<crate::analysis::facts::RoleFact>,
80        local: bool,
81        is_session_auth: bool,
82    },
83    Opaque(OpaqueMutation),
84    Vacuum {
85        table_id: Option<ObjectId>,
86        is_full: bool,
87    },
88}
89
90#[derive(Clone, Debug, PartialEq)]
91pub struct CreateSchemaMutation {
92    pub name: String,
93    pub if_not_exists: bool,
94}
95
96#[derive(Clone, Debug, PartialEq)]
97pub struct DropSchemaMutation {
98    pub names: Vec<String>,
99    pub if_exists: bool,
100    pub cascade: bool,
101}
102
103#[derive(Clone, Debug, PartialEq)]
104pub struct CreatePolicyMutation {
105    pub name: String,
106    pub table: ObjectId,
107    pub permissive: bool,
108    pub command: crate::analysis::facts::PolicyCommand,
109}
110
111#[derive(Clone, Debug, PartialEq)]
112pub struct DropPolicyMutation {
113    pub name: String,
114    pub table: ObjectId,
115    pub if_exists: bool,
116}
117
118#[derive(Clone, Debug, PartialEq)]
119pub struct CreateTriggerMutation {
120    pub name: String,
121    pub table: ObjectId,
122    pub function_id: ObjectId,
123}
124
125#[derive(Clone, Debug, PartialEq)]
126pub struct DropTriggerMutation {
127    pub name: String,
128    pub table: ObjectId,
129    pub if_exists: bool,
130}
131
132#[derive(Clone, Debug, PartialEq)]
133pub struct DropViewMutation {
134    pub ids: Vec<ObjectId>,
135    pub if_exists: bool,
136    pub cascade: bool,
137}
138
139#[derive(Clone, Debug, PartialEq)]
140pub struct DropMaterializedViewMutation {
141    pub ids: Vec<ObjectId>,
142    pub if_exists: bool,
143    pub cascade: bool,
144}
145
146#[derive(Clone, Debug, PartialEq)]
147pub struct CreateMaterializedView {
148    pub id: ObjectId,
149    pub depends_on: Vec<ObjectId>,
150}
151
152#[derive(Clone, Debug, PartialEq)]
153pub struct RefreshMaterializedViewMutation {
154    pub id: ObjectId,
155    pub concurrently: bool,
156}
157
158#[derive(Clone, Debug, PartialEq)]
159pub struct CreateSequenceMutation {
160    pub id: ObjectId,
161    pub if_not_exists: bool,
162    pub owned_by: Option<(ObjectId, String)>,
163}
164
165#[derive(Clone, Debug, PartialEq)]
166pub struct AlterSequenceMutation {
167    pub id: ObjectId,
168    pub owned_by: Option<(ObjectId, String)>,
169}
170
171#[derive(Clone, Debug, PartialEq)]
172pub struct DropSequenceMutation {
173    pub ids: Vec<ObjectId>,
174    pub if_exists: bool,
175    pub cascade: bool,
176}
177
178#[derive(Clone, Debug, PartialEq)]
179pub struct CreateDomainMutation {
180    pub id: ObjectId,
181    pub base_type: String,
182}
183
184#[derive(Clone, Debug, PartialEq)]
185pub struct AlterDomainMutation {
186    pub id: ObjectId,
187    pub action: Option<crate::analysis::facts::AlterDomainActionFact>,
188}
189
190#[derive(Clone, Debug, PartialEq)]
191pub struct DropDomainMutation {
192    pub ids: Vec<ObjectId>,
193    pub if_exists: bool,
194    pub cascade: bool,
195}
196
197#[derive(Clone, Debug, PartialEq)]
198pub struct DropTypeMutation {
199    pub ids: Vec<ObjectId>,
200    pub if_exists: bool,
201    pub cascade: bool,
202}
203
204#[derive(Clone, Debug, PartialEq)]
205pub struct CreateTypeMutation {
206    pub id: ObjectId,
207    pub kind: TypeKind,
208}
209
210#[derive(Clone, Debug, PartialEq)]
211pub struct AlterTypeMutation {
212    pub id: ObjectId,
213    pub action: AlterTypeActionMutation,
214}
215
216#[derive(Clone, Debug, PartialEq)]
217pub enum AlterTypeActionMutation {
218    AddValue {
219        new_value: String,
220        neighbor: Option<String>,
221        before: bool,
222    },
223    RenameValue {
224        old_value: String,
225        new_value: String,
226    },
227}
228
229#[derive(Clone, Debug, PartialEq)]
230pub struct CreateTable {
231    pub id: ObjectId,
232    pub if_not_exists: bool,
233    pub as_select: bool,
234    pub persistence: PersistenceMutation,
235    pub columns: Vec<ColumnMutation>,
236    pub foreign_keys: Vec<FkMutation>,
237    pub table_constraints: Vec<TableConstraintFact>,
238    pub partition_by: Option<String>,
239    pub partition_of: Option<ObjectId>,
240    pub partition_type: Option<String>,
241}
242
243#[derive(Clone, Debug, PartialEq)]
244pub struct ColumnMutation {
245    pub name: String,
246    pub ty: Option<String>,
247    pub not_null: bool,
248    pub is_primary_key: bool,
249    pub primary_key_constraint_name: Option<String>,
250    pub is_unique: bool,
251    pub unique_constraint_name: Option<String>,
252    pub default: Option<ExprIr>,
253}
254
255#[derive(Clone, Debug, PartialEq)]
256pub struct FkMutation {
257    pub constraint_name: Option<String>,
258    pub to_table: ObjectId,
259    pub from_columns: Vec<String>,
260    pub to_columns: Vec<String>,
261}
262
263#[derive(Clone, Debug, PartialEq)]
264pub struct CreateView {
265    pub id: ObjectId,
266    pub or_replace: bool,
267    pub depends_on: Vec<ObjectId>,
268}
269
270#[derive(Clone, Debug, PartialEq)]
271pub struct CreateIndex {
272    pub id: ObjectId,
273    pub table: ObjectId,
274    pub if_not_exists: bool,
275    pub concurrently: bool,
276    pub using_method: Option<String>,
277    pub has_predicate: bool,
278    pub unique: bool,
279}
280
281#[derive(Clone, Debug, PartialEq)]
282pub struct AlterTable {
283    pub id: ObjectId,
284    pub action: AlterTableActionMutation,
285}
286
287#[derive(Clone, Debug, PartialEq)]
288pub struct Rename {
289    pub old_id: ObjectId,
290    pub new_id: ObjectId,
291}
292
293#[derive(Clone, Debug, PartialEq)]
294pub struct DropTable {
295    pub id: ObjectId,
296    pub if_exists: bool,
297    pub cascade: bool,
298}
299
300#[derive(Clone, Debug, PartialEq)]
301pub struct DropIndex {
302    pub id: ObjectId,
303    pub if_exists: bool,
304    pub concurrently: bool,
305}
306
307#[derive(Clone, Debug, PartialEq)]
308pub struct SearchPathChange {
309    pub target: SearchPathTarget,
310}
311
312#[derive(Clone, Debug, PartialEq)]
313pub struct SavepointMutation {
314    pub name: String,
315}
316
317#[derive(Clone, Debug, PartialEq)]
318pub struct ReleaseSavepointMutation {
319    pub name: String,
320}
321
322#[derive(Clone, Debug, PartialEq)]
323pub struct RollbackToSavepointMutation {
324    pub name: String,
325}
326
327#[derive(Clone, Debug, PartialEq)]
328pub struct CreateFunctionMutation {
329    pub id: ObjectId,
330    pub or_replace: bool,
331    pub params: Vec<crate::analysis::facts::ParamFact>,
332    pub return_type: Option<crate::analysis::facts::RetTypeFact>,
333    pub options: Vec<crate::analysis::facts::FuncOptionFact>,
334}
335
336#[derive(Clone, Debug, PartialEq)]
337pub struct AlterFunctionMutation {
338    pub id: ObjectId,
339    pub action: crate::analysis::facts::AlterFunctionAction,
340}
341
342#[derive(Clone, Debug, PartialEq)]
343pub struct DropFunctionMutation {
344    pub signatures: Vec<crate::analysis::facts::FunctionSigFact>,
345    pub if_exists: bool,
346    pub cascade: bool,
347}
348
349#[derive(Clone, Debug, PartialEq)]
350pub struct CreateProcedureMutation {
351    pub id: ObjectId,
352    pub or_replace: bool,
353    pub params: Vec<crate::analysis::facts::ParamFact>,
354    pub options: Vec<crate::analysis::facts::FuncOptionFact>,
355}
356
357#[derive(Clone, Debug, PartialEq)]
358pub struct AlterProcedureMutation {
359    pub id: ObjectId,
360    pub action: crate::analysis::facts::AlterFunctionAction,
361}
362
363#[derive(Clone, Debug, PartialEq)]
364pub struct DropProcedureMutation {
365    pub signatures: Vec<crate::analysis::facts::FunctionSigFact>,
366    pub if_exists: bool,
367    pub cascade: bool,
368}
369
370#[derive(Clone, Debug, PartialEq)]
371pub struct CreatePublicationMutation {
372    pub name: String,
373    pub scope: crate::analysis::facts::PublicationScope,
374    pub params: Vec<crate::analysis::facts::AttributeFact>,
375}
376
377#[derive(Clone, Debug, PartialEq)]
378pub struct AlterPublicationMutation {
379    pub name: String,
380}
381
382#[derive(Clone, Debug, PartialEq)]
383pub struct DropPublicationMutation {
384    pub names: Vec<String>,
385    pub if_exists: bool,
386    pub cascade: bool,
387}
388
389#[derive(Clone, Debug, PartialEq)]
390pub struct CreateSubscriptionMutation {
391    pub name: Option<String>,
392    pub connection: crate::analysis::facts::ConnectionTarget,
393    pub publications: Vec<String>,
394    pub params: Option<Vec<crate::analysis::facts::AttributeFact>>,
395}
396
397#[derive(Clone, Debug, PartialEq)]
398pub struct AlterSubscriptionMutation {
399    pub name: String,
400}
401
402#[derive(Clone, Debug, PartialEq)]
403pub struct DropSubscriptionMutation {
404    pub name: String,
405    pub if_exists: bool,
406}
407
408#[derive(Clone, Debug, PartialEq)]
409pub struct CreateRoleMutation {
410    pub name: String,
411    pub inherits: bool,
412}
413
414#[derive(Clone, Debug, PartialEq)]
415pub struct AlterRoleMutation {
416    pub name: crate::analysis::facts::RoleFact,
417    pub inherits: Option<bool>,
418}
419
420#[derive(Clone, Debug, PartialEq)]
421pub struct DropRoleMutation {
422    pub names: Vec<String>,
423    pub if_exists: bool,
424}
425
426#[derive(Clone, Debug, PartialEq)]
427pub enum ResolvedGrantTarget {
428    Tables(Vec<ObjectId>),
429    AllTablesInSchema(Vec<String>),
430}
431
432#[derive(Clone, Debug, PartialEq)]
433pub struct GrantMutation {
434    pub privileges: crate::analysis::facts::PrivilegeSpec,
435    pub target: ResolvedGrantTarget,
436    pub grantees: Vec<crate::analysis::facts::RoleFact>,
437    pub with_grant_option: bool,
438    pub granted_by: Option<crate::analysis::facts::RoleFact>,
439}
440
441#[derive(Clone, Debug, PartialEq)]
442pub struct RevokeMutation {
443    pub grant_option_only: bool,
444    pub privileges: crate::analysis::facts::PrivilegeSpec,
445    pub target: ResolvedGrantTarget,
446    pub revokees: Vec<crate::analysis::facts::RoleFact>,
447    pub granted_by: Option<crate::analysis::facts::RoleFact>,
448    pub cascade: bool,
449}
450
451#[derive(Clone, Debug, PartialEq)]
452pub struct CreateDatabaseMutation {
453    pub name: String,
454    pub options: Vec<crate::analysis::facts::DatabaseOptionFact>,
455}
456
457#[derive(Clone, Debug, PartialEq)]
458pub struct AlterDatabaseMutation {
459    pub id: ObjectId,
460    pub action: crate::analysis::facts::AlterDatabaseAction,
461}
462
463#[derive(Clone, Debug, PartialEq)]
464pub struct DropDatabaseMutation {
465    pub id: ObjectId,
466    pub if_exists: bool,
467}
468
469#[derive(Clone, Debug, PartialEq)]
470pub enum OpaqueMutation {
471    /// Squawk accepted the statement but safe-migrate has no typed extractor
472    /// for it. Treating it as a no-op would leave later analysis falsely exact.
473    UnsupportedStatement,
474    DoBlock,
475    Execute,
476    DynamicSql,
477    PrepareTransaction,
478    SetTransaction,
479    SetConstraints,
480    StateCollision(String),
481    UnresolvedReference {
482        object_kind: crate::report::violations::ObjectKind,
483        object_name: String,
484    },
485}
486
487#[derive(Clone, Debug, PartialEq)]
488pub enum AlterTableActionMutation {
489    AddColumn {
490        name: String,
491        ty: Option<String>,
492        if_not_exists: bool,
493        not_null: bool,
494        default: Option<ExprIr>,
495        depends_on: Option<(ObjectId, String)>,
496    },
497    DropColumn {
498        name: String,
499        if_exists: bool,
500    },
501    RenameColumn {
502        from: String,
503        to: String,
504    },
505    AddForeignKey {
506        constraint_name: Option<String>,
507        to_table: ObjectId,
508        from_columns: Vec<String>,
509        to_columns: Vec<String>,
510        not_valid: bool,
511    },
512    AlterConstraint {
513        name: Option<String>,
514        deferrable: bool,
515    },
516    RenameConstraint {
517        old_name: String,
518        new_name: String,
519    },
520    DropConstraint {
521        name: String,
522    },
523    AddCheckConstraint {
524        constraint_name: Option<String>,
525        not_valid: bool,
526    },
527    AddUniqueConstraint {
528        constraint_name: Option<String>,
529        using_index: Option<ObjectId>,
530    },
531    AddPrimaryKeyConstraint {
532        constraint_name: Option<String>,
533        using_index: Option<ObjectId>,
534    },
535    AddExcludeConstraint {
536        constraint_name: Option<String>,
537    },
538    SetNotNull {
539        column: String,
540    },
541    DropNotNull {
542        column: String,
543    },
544    SetType {
545        column: String,
546        ty: String,
547        has_using: bool,
548    },
549    SetDefault {
550        column: String,
551        default: Option<ExprIr>,
552    },
553    ValidateConstraint {
554        constraint_name: String,
555    },
556    DisableTrigger {
557        trigger_name: Option<String>,
558    },
559    EnableTrigger {
560        trigger_name: Option<String>,
561    },
562    AttachPartition {
563        child: ObjectId,
564    },
565    DetachPartition {
566        child: ObjectId,
567    },
568    SetStorage {
569        column: String,
570    },
571    SetAccessMethod,
572    OwnerTo {
573        new_owner: crate::analysis::facts::RoleFact,
574    },
575    Opaque,
576}