Skip to main content

safe_migrate/analysis/
facts.rs

1// FILE: src/analysis/facts.rs
2use crate::analysis::expr_ir::ExprIr;
3use crate::ast::identifiers::{Ident, QualifiedName};
4
5#[derive(Clone, Debug, PartialEq)]
6pub enum PersistenceFact {
7    Permanent,
8    Temporary,
9    Unlogged,
10}
11
12#[derive(Clone, Debug, PartialEq)]
13pub enum PolicyCommand {
14    All,
15    Select,
16    Insert,
17    Update,
18    Delete,
19}
20
21#[derive(Clone, Debug, PartialEq)]
22pub enum SearchPathTarget {
23    Default,
24    Schemas(Vec<String>),
25}
26
27#[derive(Clone, Debug, PartialEq)]
28pub enum TypeCreationKind {
29    Enum { variants: Vec<String> },
30    Range,
31    Composite,
32    Base,
33}
34
35#[derive(Clone, Debug, PartialEq)]
36pub enum AlterViewAction {
37    RenameTo {
38        new_name: Ident,
39    },
40    OwnerTo {
41        new_owner: RoleFact,
42    },
43    SetSchema {
44        new_schema: String,
45    },
46    SetDefault {
47        column: String,
48        default: Option<ExprIr>,
49    },
50    DropDefault {
51        column: String,
52    },
53    RenameColumn {
54        from: Ident,
55        to: Ident,
56    },
57    SetOptions {
58        options: Vec<String>,
59    },
60    ResetOptions {
61        options: Vec<String>,
62    },
63}
64
65#[derive(Clone, Debug, PartialEq)]
66pub enum StatementFact {
67    CreateSchema {
68        name: QualifiedName,
69        if_not_exists: bool,
70    },
71    AlterSchema {
72        name: QualifiedName,
73        new_name: Option<Ident>,
74    },
75    DropSchema {
76        names: Vec<QualifiedName>,
77        if_exists: bool,
78        cascade: bool,
79    },
80    CreateTable {
81        name: QualifiedName,
82        if_not_exists: bool,
83        as_select: bool,
84        persistence: PersistenceFact,
85        columns: Vec<ColumnFact>,
86        foreign_keys: Vec<FkFact>,
87        table_constraints: Vec<TableConstraintFact>,
88        partition_by: Option<String>,
89        partition_of: Option<QualifiedName>,
90        partition_type: Option<String>,
91    },
92    CreateView {
93        name: QualifiedName,
94        or_replace: bool,
95        depends_on: Vec<QualifiedName>,
96    },
97    AlterView {
98        name: QualifiedName,
99        action: AlterViewAction,
100    },
101    CreateMaterializedView {
102        name: QualifiedName,
103        depends_on: Vec<QualifiedName>,
104    },
105    AlterMaterializedView {
106        name: QualifiedName,
107        new_name: Option<Ident>,
108    },
109    RefreshMaterializedView {
110        name: QualifiedName,
111        concurrently: bool,
112    },
113    CreateIndex {
114        name: QualifiedName,
115        relation: QualifiedName,
116        if_not_exists: bool,
117        concurrently: bool,
118        using_method: Option<String>,
119        has_predicate: bool,
120        unique: bool, // Added for CreateIndexFact
121    },
122    CreatePolicy {
123        name: String,
124        table: QualifiedName,
125        permissive: bool,
126        command: PolicyCommand,
127    },
128    DropPolicy {
129        name: String,
130        table: QualifiedName,
131        if_exists: bool,
132    },
133    CreateTrigger {
134        name: String,
135        table: QualifiedName,
136        function: Option<QualifiedName>,
137    },
138    DropTrigger {
139        name: String,
140        table: QualifiedName,
141        if_exists: bool,
142    },
143    AlterTable {
144        name: QualifiedName,
145        actions: Vec<AlterTableActionFact>,
146    },
147    AlterIndex {
148        name: QualifiedName,
149        actions: Vec<AlterIndexActionFact>,
150    },
151    CreateType(CreateTypeFact),
152    AlterType(AlterTypeFact),
153    CreateDomain {
154        name: QualifiedName,
155        base_type: String,
156    },
157    AlterDomain {
158        name: QualifiedName,
159        action: Option<AlterDomainActionFact>,
160    },
161    DropDomain {
162        names: Vec<QualifiedName>,
163        if_exists: bool,
164        cascade: bool,
165    },
166    DropType {
167        names: Vec<QualifiedName>,
168        if_exists: bool,
169        cascade: bool,
170    },
171    CreateSequence {
172        name: QualifiedName,
173        if_not_exists: bool,
174        owned_by: Option<(QualifiedName, String)>,
175    },
176    AlterSequence {
177        name: QualifiedName,
178        owned_by: Option<(QualifiedName, String)>,
179    },
180    DropSequence {
181        names: Vec<QualifiedName>,
182        if_exists: bool,
183        cascade: bool,
184    },
185    DropTable {
186        name: QualifiedName,
187        if_exists: bool,
188        cascade: bool,
189    },
190    DropView {
191        name: QualifiedName,
192        if_exists: bool,
193        cascade: bool,
194    },
195    DropMaterializedView {
196        names: Vec<QualifiedName>,
197        if_exists: bool,
198        cascade: bool,
199    },
200    DropIndex {
201        names: Vec<QualifiedName>,
202        if_exists: bool,
203        concurrently: bool,
204    },
205    SetSearchPath {
206        target: SearchPathTarget,
207    },
208    BeginTransaction,
209    CommitTransaction,
210    CommitAndChain,
211    RollbackTransaction,
212    RollbackAndChain,
213    RollbackToSavepoint {
214        name: String,
215    },
216    Savepoint {
217        name: String,
218    },
219    ReleaseSavepoint {
220        name: String,
221    },
222    PrepareTransaction {
223        name: String,
224    },
225    SetTransaction,
226    SetConstraints,
227    OpaqueBlock,
228    Execute,
229    Vacuum {
230        relation: Option<QualifiedName>,
231        is_full: bool,
232    },
233    CreateFunction(CreateFunctionFact),
234    AlterFunction(AlterFunctionFact),
235    DropFunction(DropFunctionFact),
236    CreateProcedure(CreateProcedureFact),
237    AlterProcedure(AlterProcedureFact),
238    DropProcedure(DropProcedureFact),
239    CreatePublication(CreatePublicationFact),
240    AlterPublication(AlterPublicationFact),
241    DropPublication(DropPublicationFact),
242    CreateSubscription(CreateSubscriptionFact),
243    AlterSubscription(AlterSubscriptionFact),
244    DropSubscription(DropSubscriptionFact),
245    CreateRole(CreateRoleFact),
246    AlterRole(AlterRoleFact),
247    DropRole(DropRoleFact),
248    Grant(GrantFact),
249    Revoke(RevokeFact),
250    CreateDatabase(CreateDatabaseFact),
251    AlterDatabase(AlterDatabaseFact),
252    DropDatabase(DropDatabaseFact),
253    /// `SET [LOCAL] ROLE { rolename | NONE }` or
254    /// `SET [LOCAL] SESSION AUTHORIZATION { rolename | DEFAULT }`.
255    /// `role = None` means NONE / DEFAULT (restore the session default).
256    /// `local = true` means the change is scoped to the current transaction.
257    /// `is_session_auth = true` means SET SESSION AUTHORIZATION (which also
258    /// updates the session-level default, unlike plain SET ROLE).
259    SetRole {
260        role: Option<RoleFact>,
261        local: bool,
262        is_session_auth: bool,
263    },
264}
265
266#[derive(Clone, Debug, PartialEq)]
267pub enum AlterIndexActionFact {
268    RenameTo { new_name: Ident },
269}
270
271#[derive(Clone, Debug, PartialEq)]
272pub struct CreateTypeFact {
273    pub name: QualifiedName,
274    pub kind: TypeCreationKind,
275}
276
277#[derive(Clone, Debug, PartialEq)]
278pub struct AlterTypeFact {
279    pub name: QualifiedName,
280    pub actions: Vec<AlterTypeActionFact>,
281}
282
283#[derive(Clone, Debug, PartialEq)]
284pub enum AlterTypeActionFact {
285    AddValue {
286        new_value: String,
287        neighbor: Option<String>,
288        before: bool,
289    },
290    RenameValue {
291        old_value: String,
292        new_value: String,
293    },
294}
295
296#[derive(Clone, Debug, PartialEq, Default)]
297pub enum RoleFact {
298    #[default]
299    Unknown,
300    Named {
301        name: String,
302        via_legacy_group_syntax: bool,
303    },
304    CurrentUser,
305    CurrentRole,
306    SessionUser,
307}
308
309#[derive(Clone, Debug, PartialEq)]
310pub struct CreateRoleFact {
311    pub name: String,
312    pub inherits: bool,
313}
314
315#[derive(Clone, Debug, PartialEq)]
316pub struct AlterRoleFact {
317    pub name: RoleFact,
318    pub inherits: Option<bool>,
319}
320
321#[derive(Clone, Debug, PartialEq)]
322pub struct DropRoleFact {
323    pub names: Vec<String>,
324    pub if_exists: bool,
325}
326
327#[derive(Clone, Debug, PartialEq)]
328pub struct CreateFunctionFact {
329    pub name: QualifiedName,
330    pub or_replace: bool,
331    pub params: Vec<ParamFact>,
332    pub return_type: Option<RetTypeFact>,
333    pub options: Vec<FuncOptionFact>,
334}
335
336#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
337pub struct ParamFact {
338    pub mode: ParamModeFact,
339    pub name: Option<String>,
340    pub ty: String,
341    pub default: Option<ExprIr>,
342}
343
344#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
345pub enum ParamModeFact {
346    In,
347    Out,
348    InOut,
349    Variadic,
350}
351
352#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
353pub enum RetTypeFact {
354    Table(Vec<ColumnFact>),
355    Scalar(String),
356}
357
358#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
359pub enum FuncOptionFact {
360    Language(String),
361    Volatility(VolatilityKind),
362    Security(SecurityKind),
363    Strict(StrictKind),
364    Leakproof(bool),
365    Parallel(String),
366    Cost,
367    Rows,
368    Reset(String),
369    As {
370        definition: Option<String>,
371        obj_file: Option<String>,
372        link_symbol: Option<String>,
373    },
374    Transform,
375    Window,
376    Support,
377    Unknown,
378}
379
380#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
381pub enum VolatilityKind {
382    Immutable,
383    Stable,
384    Volatile,
385}
386#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
387pub enum SecurityKind {
388    Invoker,
389    Definer,
390}
391#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
392pub enum StrictKind {
393    Strict,
394    CalledOnNull,
395    ReturnsNullOnNull,
396}
397
398#[derive(Clone, Debug, PartialEq)]
399pub struct AlterFunctionFact {
400    pub name: QualifiedName,
401    pub params: Vec<String>,
402    pub action: AlterFunctionAction,
403}
404
405#[derive(Clone, Debug, PartialEq)]
406pub enum AlterFunctionAction {
407    Rename { from: String, to: String },
408    OwnerChange(RoleFact),
409    SchemaChange { new_schema: String },
410    DependsOnExtension { extension: String },
411    NoDependsOnExtension { extension: String },
412    OptionsChange(Vec<FuncOptionFact>),
413}
414
415#[derive(Clone, Debug, PartialEq)]
416pub struct DropFunctionFact {
417    pub signatures: Vec<FunctionSigFact>,
418    pub if_exists: bool,
419    pub cascade: bool,
420}
421
422#[derive(Clone, Debug, PartialEq)]
423pub struct FunctionSigFact {
424    pub name: QualifiedName,
425    pub params: Vec<String>,
426}
427
428#[derive(Clone, Debug, PartialEq)]
429pub struct CreateProcedureFact {
430    pub name: QualifiedName,
431    pub or_replace: bool,
432    pub params: Vec<ParamFact>,
433    pub options: Vec<FuncOptionFact>,
434}
435
436#[derive(Clone, Debug, PartialEq)]
437pub struct AlterProcedureFact {
438    pub name: QualifiedName,
439    pub params: Vec<String>,
440    pub action: AlterFunctionAction,
441}
442
443#[derive(Clone, Debug, PartialEq)]
444pub struct DropProcedureFact {
445    pub signatures: Vec<FunctionSigFact>,
446    pub if_exists: bool,
447    pub cascade: bool,
448}
449
450#[derive(Clone, Debug, PartialEq)]
451pub struct CreatePublicationFact {
452    pub name: String,
453    pub scope: PublicationScope,
454    pub params: Vec<AttributeFact>,
455}
456
457#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
458pub enum PublicationScope {
459    AllTables { except: Vec<String> },
460    Explicit(Vec<PublicationObjectFact>),
461}
462
463#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
464pub enum PublicationObjectFact {
465    Table {
466        name: QualifiedName,
467        only: bool,
468        include_partitions: bool,
469        columns: Option<Vec<String>>,
470        row_filter: Option<ExprIr>,
471    },
472    SchemaTables {
473        schema: String,
474        row_filter: Option<ExprIr>,
475    },
476    CurrentSchemaShorthand,
477    Unknown,
478}
479
480#[derive(Clone, Debug, PartialEq)]
481pub struct AlterPublicationFact {
482    pub name: String,
483}
484
485#[derive(Clone, Debug, PartialEq)]
486pub struct DropPublicationFact {
487    pub names: Vec<String>,
488    pub if_exists: bool,
489    pub cascade: bool,
490}
491
492#[derive(Clone, Debug, PartialEq)]
493pub struct CreateSubscriptionFact {
494    pub name: Option<String>,
495    pub connection: ConnectionTarget,
496    pub publications: Vec<String>,
497    pub params: Option<Vec<AttributeFact>>,
498}
499
500#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
501pub enum ConnectionTarget {
502    Literal(Option<String>),
503    Server(Option<String>),
504}
505
506#[derive(Clone, Debug, PartialEq)]
507pub struct AlterSubscriptionFact {
508    pub name: String,
509}
510
511#[derive(Clone, Debug, PartialEq)]
512pub struct DropSubscriptionFact {
513    pub name: String,
514    pub if_exists: bool,
515}
516
517#[derive(Clone, Debug, PartialEq)]
518pub struct GrantFact {
519    pub privileges: PrivilegeSpec,
520    pub target: GrantTarget,
521    pub grantees: Vec<RoleFact>,
522    pub with_grant_option: bool,
523    pub granted_by: Option<RoleFact>,
524}
525
526#[derive(Clone, Debug, PartialEq)]
527pub struct RevokeFact {
528    pub grant_option_only: bool,
529    pub privileges: PrivilegeSpec,
530    pub target: GrantTarget,
531    pub revokees: Vec<RoleFact>,
532    pub granted_by: Option<RoleFact>,
533    pub cascade: bool,
534}
535
536#[derive(Clone, Debug, PartialEq)]
537pub enum PrivilegeSpec {
538    All,
539    List(Vec<PrivilegeFact>),
540}
541
542#[derive(Clone, Debug, PartialEq)]
543pub enum PrivilegeFact {
544    Select,
545    Insert,
546    Update,
547    Delete,
548    Truncate,
549    References,
550    Trigger,
551    Execute,
552    Create,
553    Temporary,
554    AlterSystem,
555    All,
556    Named(String),
557    RoleMembership(String),
558    Unknown,
559}
560
561#[derive(Clone, Debug, PartialEq)]
562pub enum GrantTarget {
563    Tables(Vec<QualifiedName>),
564    AllTablesInSchema(Vec<String>),
565}
566
567#[derive(Clone, Debug, PartialEq)]
568pub struct CreateDatabaseFact {
569    pub name: String,
570    pub options: Vec<DatabaseOptionFact>,
571}
572
573#[derive(Clone, Debug, PartialEq)]
574pub enum DatabaseOptionFact {
575    Owner(DatabaseOptionValue),
576    Template(DatabaseOptionValue),
577    Encoding(DatabaseOptionValue),
578    Tablespace(DatabaseOptionValue),
579    ConnectionLimit(DatabaseOptionValue),
580    Named(String, DatabaseOptionValue),
581    Unknown(DatabaseOptionValue),
582}
583
584#[derive(Clone, Debug, PartialEq)]
585pub enum DatabaseOptionValue {
586    Default,
587    Literal(Option<String>),
588}
589
590#[derive(Clone, Debug, PartialEq)]
591pub struct AlterDatabaseFact {
592    pub name: QualifiedName,
593    pub action: AlterDatabaseAction,
594}
595
596#[derive(Clone, Debug, PartialEq)]
597pub enum AlterDatabaseAction {
598    Rename { to: String },
599    OwnerChange(RoleFact),
600    TablespaceChange { new_tablespace: String },
601    SetConfigParam { param: String },
602    ResetConfigParam { param: Option<String> },
603    RefreshCollationVersion,
604    OptionChanges(Vec<DatabaseOptionFact>),
605}
606
607#[derive(Clone, Debug, PartialEq)]
608pub struct DropDatabaseFact {
609    pub name: QualifiedName,
610    pub if_exists: bool,
611}
612
613#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
614pub struct AttributeFact {
615    pub name: String,
616    pub value: String,
617}
618
619#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
620pub struct ColumnFact {
621    pub name: String,
622    pub ty: Option<String>,
623    pub not_null: bool,
624    pub is_primary_key: bool,
625    pub primary_key_constraint_name: Option<String>,
626    pub is_unique: bool,
627    pub unique_constraint_name: Option<String>,
628    pub default: Option<ExprIr>,
629}
630
631#[derive(Clone, Debug, PartialEq)]
632pub struct FkFact {
633    pub constraint_name: Option<String>,
634    pub references: QualifiedName,
635    pub from_columns: Vec<String>,
636    pub to_columns: Vec<String>,
637}
638
639#[derive(Clone, Debug, PartialEq)]
640pub enum TableConstraintFact {
641    PrimaryKey {
642        constraint_name: Option<String>,
643        columns: Vec<String>,
644    },
645    Unique {
646        constraint_name: Option<String>,
647        columns: Vec<String>,
648    },
649    Check,
650    Exclude,
651}
652
653#[derive(Clone, Debug, PartialEq)]
654pub enum AlterDomainActionFact {
655    AddConstraint,
656    DropConstraint,
657    DropDefault,
658    DropNotNull,
659    OwnerChange,
660    RenameConstraint,
661    RenameTo,
662    SetDefault,
663    SetNotNull,
664    SetSchema,
665    ValidateConstraint,
666}
667
668#[derive(Clone, Debug, PartialEq)]
669pub enum AlterTableActionFact {
670    AddColumn {
671        name: String,
672        ty: Option<String>,
673        if_not_exists: bool,
674        not_null: bool,
675        default: Option<ExprIr>,
676    },
677    DropColumn {
678        name: String,
679        if_exists: bool,
680    },
681    RenameColumn {
682        from: Ident,
683        to: Ident,
684    },
685    RenameTo {
686        new_name: Ident,
687    },
688    AddForeignKey {
689        constraint_name: Option<String>,
690        references: QualifiedName,
691        from_columns: Vec<String>,
692        to_columns: Vec<String>,
693        not_valid: bool,
694    },
695    AlterConstraint {
696        name: Option<String>,
697        deferrable: bool,
698    },
699    RenameConstraint {
700        old_name: String,
701        new_name: String,
702    },
703    DropConstraint {
704        name: String,
705    },
706    AddCheckConstraint {
707        constraint_name: Option<String>,
708        not_valid: bool,
709    },
710    AddUniqueConstraint {
711        constraint_name: Option<String>,
712        using_index: Option<QualifiedName>,
713    },
714    AddPrimaryKeyConstraint {
715        constraint_name: Option<String>,
716        using_index: Option<QualifiedName>,
717    },
718    AddExcludeConstraint {
719        constraint_name: Option<String>,
720    },
721    SetNotNull {
722        column: String,
723    },
724    DropNotNull {
725        column: String,
726    },
727    SetType {
728        column: String,
729        ty: String,
730        has_using: bool,
731    },
732    SetDefault {
733        column: String,
734        default: Option<ExprIr>,
735    },
736    SetExpression {
737        column: String,
738        expr: ExprIr,
739    },
740    SetOptions {
741        column: String,
742        attributes: Vec<AttributeFact>,
743    },
744    Inherit {
745        column: String,
746        parent: QualifiedName,
747    },
748    NoInherit {
749        column: String,
750        parent: QualifiedName,
751    },
752    ValidateConstraint {
753        constraint_name: String,
754    },
755    DisableTrigger {
756        trigger_name: Option<String>,
757    },
758    EnableTrigger {
759        trigger_name: Option<String>,
760    },
761    AttachPartition {
762        child: QualifiedName,
763    },
764    DetachPartition {
765        child: QualifiedName,
766    },
767    SetStorage {
768        column: String,
769    },
770    SetAccessMethod,
771    ClusterOn {
772        index: String,
773    },
774    InheritTable {
775        parent: QualifiedName,
776    },
777    NoInheritTable {
778        parent: QualifiedName,
779    },
780    MergePartitions {
781        parent: QualifiedName,
782    },
783    SplitPartition,
784    SetSchema {
785        new_schema: String,
786    },
787    SetTablespace {
788        tablespace: String,
789    },
790    SetLogged,
791    SetUnlogged,
792    OwnerTo {
793        new_owner: RoleFact,
794    },
795    ReplicaIdentity {
796        option: String,
797    },
798    ForceRls,
799    EnableRls,
800    DisableRls,
801    EnableAlwaysTrigger {
802        trigger_name: Option<String>,
803    },
804    EnableReplicaTrigger {
805        trigger_name: Option<String>,
806    },
807}