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