Skip to main content

pgevolve_core/plan/
raw_step.rs

1//! [`RawStep`] — the smallest unit of work the executor will attempt.
2//!
3//! After the rewrite pass, every step's SQL is fixed: the executor performs
4//! no further transformation. `intent_id` is populated later, in the plan
5//! serializer, once destructive intents have been collated.
6
7use serde::{Deserialize, Serialize};
8
9use crate::identifier::QualifiedName;
10
11/// Whether a step can run inside a `BEGIN; ... COMMIT;` block.
12///
13/// Used by [`group_steps`](super::grouping::group_steps) to partition the
14/// step list into transactional vs. non-transactional groups. `CONCURRENTLY`
15/// index ops are the typical [`OutsideTransaction`](Self::OutsideTransaction)
16/// case in v0.1.
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
18#[serde(rename_all = "snake_case")]
19pub enum TransactionConstraint {
20    /// May execute inside a `BEGIN ... COMMIT`.
21    InTransaction,
22    /// Must execute outside a transaction (e.g., `CREATE INDEX CONCURRENTLY`).
23    OutsideTransaction,
24}
25
26/// What kind of operation a [`RawStep`] performs.
27///
28/// Serialized via `serde` as the `kind=` value in the plan's
29/// `-- @pgevolve step ...` directive comments (spec §7.1). The
30/// `snake_case` rename keeps the on-disk form stable across renames here.
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
32#[serde(rename_all = "snake_case")]
33pub enum StepKind {
34    /// `CREATE SCHEMA`.
35    CreateSchema,
36    /// `DROP SCHEMA`.
37    DropSchema,
38    /// `COMMENT ON SCHEMA`.
39    AlterSchemaComment,
40
41    /// `CREATE TABLE`.
42    CreateTable,
43    /// `DROP TABLE`.
44    DropTable,
45    /// `COMMENT ON TABLE`.
46    AlterTableSetComment,
47
48    /// `ALTER TABLE ... ADD COLUMN`.
49    AddColumn,
50    /// `ALTER TABLE ... DROP COLUMN`.
51    DropColumn,
52    /// `ALTER TABLE ... ALTER COLUMN ... TYPE`.
53    AlterColumnType,
54    /// `ALTER TABLE ... ALTER COLUMN ... SET/DROP NOT NULL`.
55    SetColumnNullable,
56    /// `ALTER TABLE ... ALTER COLUMN ... SET/DROP DEFAULT`.
57    SetColumnDefault,
58    /// `COMMENT ON COLUMN`.
59    SetColumnComment,
60    /// `ALTER TABLE ... ALTER COLUMN ... ADD/DROP IDENTITY`.
61    SetColumnIdentity,
62    /// `ALTER TABLE ... ALTER COLUMN ... SET/DROP EXPRESSION`.
63    SetColumnGenerated,
64    /// `ALTER TABLE ... ALTER COLUMN ... SET STORAGE`.
65    SetColumnStorage,
66    /// `ALTER TABLE ... ALTER COLUMN ... SET COMPRESSION`.
67    SetColumnCompression,
68
69    /// `ALTER TABLE ... ADD CONSTRAINT` (validated immediately).
70    AddConstraint,
71    /// `ALTER TABLE ... ADD CONSTRAINT ... NOT VALID`.
72    AddConstraintNotValid,
73    /// `ALTER TABLE ... VALIDATE CONSTRAINT`.
74    ValidateConstraint,
75    /// `ALTER TABLE ... DROP CONSTRAINT`.
76    DropConstraint,
77    /// `COMMENT ON CONSTRAINT`.
78    SetConstraintComment,
79
80    /// `CREATE INDEX`.
81    CreateIndex,
82    /// `CREATE INDEX CONCURRENTLY`.
83    CreateIndexConcurrent,
84    /// `DROP INDEX`.
85    DropIndex,
86    /// `DROP INDEX CONCURRENTLY`.
87    DropIndexConcurrent,
88
89    /// `CREATE SEQUENCE`.
90    CreateSequence,
91    /// `DROP SEQUENCE`.
92    DropSequence,
93    /// `ALTER SEQUENCE`.
94    AlterSequence,
95
96    /// Intermediate `ADD CONSTRAINT __pgevolve_chk_<col> CHECK (col IS NOT NULL) NOT VALID`
97    /// step in the SET NOT NULL pattern (spec §6.5).
98    AddCheckForNotNull,
99
100    // --- v0.2 view / materialized-view step kinds ---
101    /// `CREATE [OR REPLACE] VIEW`.
102    CreateView,
103    /// `DROP VIEW`.
104    DropView,
105    /// `CREATE OR REPLACE VIEW … WITH [LOCAL|CASCADED] CHECK OPTION` (no
106    /// direct ALTER; pgevolve re-issues the full definition).
107    AlterViewSetCheckOption,
108    /// `CREATE MATERIALIZED VIEW ... WITH NO DATA`.
109    CreateMaterializedView,
110    /// `DROP MATERIALIZED VIEW`.
111    DropMaterializedView,
112    /// `REFRESH MATERIALIZED VIEW [CONCURRENTLY]`.
113    RefreshMaterializedView,
114    /// `ALTER VIEW ... SET (...)`.
115    AlterViewSetReloption,
116    /// `COMMENT ON VIEW / MATERIALIZED VIEW / COLUMN` for views and MVs.
117    CommentOnView,
118
119    // --- v0.2 user-defined type step kinds ---
120    /// `CREATE TYPE` (enum, domain, or composite).
121    CreateType,
122    /// `DROP TYPE`.
123    DropType,
124    /// `ALTER TYPE … ADD VALUE`.
125    AlterTypeAddValue,
126    /// `ALTER TYPE … RENAME VALUE`.
127    AlterTypeRenameValue,
128    /// `ALTER DOMAIN … ADD CONSTRAINT … CHECK (…)`.
129    AlterDomainAddConstraint,
130    /// `ALTER DOMAIN … DROP CONSTRAINT`.
131    AlterDomainDropConstraint,
132    /// `ALTER DOMAIN … SET DEFAULT` / `DROP DEFAULT`.
133    AlterDomainSetDefault,
134    /// `ALTER DOMAIN … SET NOT NULL` / `DROP NOT NULL`.
135    AlterDomainSetNotNull,
136    /// `ALTER TYPE … ADD ATTRIBUTE`.
137    AlterTypeAddAttribute,
138    /// `ALTER TYPE … DROP ATTRIBUTE`.
139    AlterTypeDropAttribute,
140    /// `ALTER TYPE … ALTER ATTRIBUTE … TYPE`.
141    AlterTypeAlterAttributeType,
142    /// `COMMENT ON TYPE` / `COMMENT ON DOMAIN`.
143    CommentOnType,
144
145    // --- v0.2 function / procedure step kinds ---
146    /// `CREATE OR REPLACE FUNCTION`.
147    CreateOrReplaceFunction,
148    /// `DROP FUNCTION`.
149    DropFunction,
150    /// `COMMENT ON FUNCTION`.
151    CommentOnFunction,
152    /// `CREATE OR REPLACE PROCEDURE`.
153    CreateOrReplaceProcedure,
154    /// `DROP PROCEDURE`.
155    DropProcedure,
156    /// `COMMENT ON PROCEDURE`.
157    CommentOnProcedure,
158
159    // --- v0.2 extension step kinds ---
160    /// `CREATE EXTENSION [IF NOT EXISTS] name [WITH SCHEMA s] [VERSION 'v']`.
161    CreateExtension,
162    /// `DROP EXTENSION name CASCADE`. Destructive (intent required).
163    DropExtension,
164    /// `ALTER EXTENSION name UPDATE TO 'v'`.
165    AlterExtensionUpdate,
166    /// `COMMENT ON EXTENSION name IS '...'`.
167    CommentOnExtension,
168
169    // --- v0.2 trigger step kinds ---
170    /// `CREATE [CONSTRAINT] TRIGGER name ... ON table ...`.
171    CreateTrigger,
172    /// `DROP TRIGGER name ON table`.
173    DropTrigger,
174    /// `COMMENT ON TRIGGER name ON table IS '...'`.
175    CommentOnTrigger,
176
177    // --- v0.2 partition step kinds ---
178    /// `ALTER TABLE parent ATTACH PARTITION child FOR VALUES ...`.
179    AttachPartition,
180    /// `ALTER TABLE parent DETACH PARTITION child`.
181    DetachPartition,
182
183    // --- v0.3 cluster / role step kinds ---
184    /// `CREATE ROLE`.
185    CreateRole,
186    /// `DROP ROLE`.
187    DropRole,
188    /// `ALTER ROLE … WITH <options>`.
189    AlterRole,
190    /// `GRANT role TO member`.
191    GrantRoleMembership,
192    /// `REVOKE role FROM member`.
193    RevokeRoleMembership,
194    /// `COMMENT ON ROLE`.
195    CommentOnRole,
196
197    // --- v0.4 tablespace step kinds ---
198    /// `CREATE TABLESPACE`.
199    CreateTablespace,
200    /// `DROP TABLESPACE` — destructive.
201    DropTablespace,
202    /// `ALTER TABLESPACE … OWNER TO …`.
203    AlterTablespaceOwner,
204    /// `ALTER TABLESPACE … SET (…)`.
205    SetTablespaceOptions,
206    /// `COMMENT ON TABLESPACE`.
207    CommentOnTablespace,
208
209    // --- v0.3.1 grant / ownership step kinds ---
210    /// `ALTER <kind> qname OWNER TO new_owner`.
211    AlterObjectOwner,
212    /// `GRANT priv ON <kind> qname TO grantee [WITH GRANT OPTION]`.
213    GrantObjectPrivilege,
214    /// `REVOKE priv ON <kind> qname FROM grantee`.
215    RevokeObjectPrivilege,
216    /// `GRANT priv (col, …) ON TABLE qname TO grantee [WITH GRANT OPTION]`.
217    GrantColumnPrivilege,
218    /// `REVOKE priv (col, …) ON TABLE qname FROM grantee`.
219    RevokeColumnPrivilege,
220    /// `ALTER DEFAULT PRIVILEGES FOR ROLE x [IN SCHEMA y] GRANT/REVOKE priv ON … TO/FROM z`.
221    AlterDefaultPrivileges,
222
223    // --- v0.3.2 row-level security policy step kinds ---
224    /// `CREATE POLICY name ON table …`.
225    CreatePolicy,
226    /// `DROP POLICY name ON table`.
227    DropPolicy,
228    /// `ALTER POLICY name ON table TO … USING (…) WITH CHECK (…)`.
229    AlterPolicy,
230    /// `ALTER TABLE qname { ENABLE | DISABLE } ROW LEVEL SECURITY`.
231    SetTableRowSecurity,
232    /// `ALTER TABLE qname { FORCE | NO FORCE } ROW LEVEL SECURITY`.
233    SetTableForceRowSecurity,
234
235    // --- v0.3.3 reloption step kinds ---
236    /// `ALTER TABLE qname SET (fillfactor = …, …)`.
237    SetTableStorage,
238    /// `ALTER INDEX qname SET (fillfactor = …, …)`.
239    SetIndexStorage,
240    /// `ALTER MATERIALIZED VIEW qname SET (fillfactor = …, …)`.
241    SetMaterializedViewStorage,
242
243    // --- v0.3.4 publication step kinds ---
244    /// `CREATE PUBLICATION …`.
245    CreatePublication,
246    /// `DROP PUBLICATION …`. Destructive (intent required).
247    DropPublication,
248    /// `DROP PUBLICATION old; CREATE PUBLICATION new;` — mode swap. Destructive.
249    ReplacePublication,
250    /// `ALTER PUBLICATION p ADD TABLE x [(cols)] [WHERE (filter)]`.
251    AlterPublicationAddTable,
252    /// `ALTER PUBLICATION p DROP TABLE x`.
253    AlterPublicationDropTable,
254    /// `ALTER PUBLICATION p SET TABLE x (cols) WHERE (filter)`.
255    AlterPublicationSetTable,
256    /// `ALTER PUBLICATION p ADD TABLES IN SCHEMA s` (PG 15+).
257    AlterPublicationAddSchema,
258    /// `ALTER PUBLICATION p DROP TABLES IN SCHEMA s` (PG 15+).
259    AlterPublicationDropSchema,
260    /// `ALTER PUBLICATION p SET (publish = '...')`.
261    AlterPublicationSetPublish,
262    /// `ALTER PUBLICATION p SET (publish_via_partition_root = ...)`.
263    AlterPublicationSetViaRoot,
264    /// `COMMENT ON PUBLICATION p IS '...'`.
265    CommentOnPublication,
266
267    // --- v0.3.5 subscription step kinds ---
268    /// `CREATE SUBSCRIPTION …`.
269    CreateSubscription,
270    /// `DROP SUBSCRIPTION …`. Destructive (intent required).
271    DropSubscription,
272    /// `ALTER SUBSCRIPTION s CONNECTION '...'`.
273    AlterSubscriptionConnection,
274    /// `ALTER SUBSCRIPTION s ADD PUBLICATION p`.
275    AlterSubscriptionAddPublication,
276    /// `ALTER SUBSCRIPTION s DROP PUBLICATION p`.
277    AlterSubscriptionDropPublication,
278    /// `ALTER SUBSCRIPTION s SET (option = value, …)` — sparse-delta.
279    AlterSubscriptionSetOptions,
280    /// `COMMENT ON SUBSCRIPTION s IS '...'`.
281    CommentOnSubscription,
282
283    // --- v0.3.7 statistics step kinds ---
284    /// `CREATE STATISTICS …`.
285    CreateStatistic,
286    /// `DROP STATISTICS …`. Destructive (intent required).
287    DropStatistic,
288    /// `DROP STATISTICS old; CREATE STATISTICS new;` — structural change. Destructive.
289    ReplaceStatistic,
290    /// `ALTER STATISTICS s SET STATISTICS n`.
291    AlterStatisticSetTarget,
292    /// `COMMENT ON STATISTICS s IS '...'`.
293    CommentOnStatistic,
294
295    // --- v0.3.8 collation step kinds ---
296    /// `CREATE COLLATION qname (...)`.
297    CreateCollation,
298    /// `DROP COLLATION qname` — destructive.
299    DropCollation,
300    /// `ALTER COLLATION qname RENAME TO new_name`.
301    RenameCollation,
302    /// `DROP COLLATION old; CREATE COLLATION new;` — structural change.
303    ReplaceCollation,
304    /// `COMMENT ON COLLATION qname IS '...'`.
305    CommentOnCollation,
306
307    // --- v0.4 event trigger step kinds ---
308    /// `CREATE EVENT TRIGGER name ON event [WHEN TAG IN (...)] EXECUTE FUNCTION fn();`.
309    CreateEventTrigger,
310    /// `DROP EVENT TRIGGER name;` — destructive.
311    DropEventTrigger,
312    /// `ALTER EVENT TRIGGER name {ENABLE|DISABLE|ENABLE REPLICA|ENABLE ALWAYS};`.
313    AlterEventTriggerEnable,
314    /// `ALTER EVENT TRIGGER name OWNER TO role;`.
315    AlterEventTriggerOwner,
316    /// `COMMENT ON EVENT TRIGGER name IS '...';`.
317    CommentOnEventTrigger,
318
319    // --- v0.4 aggregate step kinds ---
320    /// `CREATE AGGREGATE qname(argtypes) (SFUNC = …, STYPE = …);`.
321    CreateAggregate,
322    /// `DROP AGGREGATE qname(argtypes);`.
323    DropAggregate,
324    /// `ALTER AGGREGATE qname(argtypes) OWNER TO role;`.
325    AlterAggregateOwner,
326    /// `COMMENT ON AGGREGATE qname(argtypes) IS '...';`.
327    CommentOnAggregate,
328
329    // --- v0.4 cast step kinds ---
330    /// `CREATE CAST (source AS target) …;`.
331    CreateCast,
332    /// `DROP CAST (source AS target);`.
333    DropCast,
334    /// `COMMENT ON CAST (source AS target) IS '...';`.
335    CommentOnCast,
336}
337
338/// One unit of work the executor will attempt.
339///
340/// `step_no` and `intent_id` start at zero / `None` and are assigned later
341/// by [`Plan::from_grouped`](crate::plan::Plan::from_grouped). The rewrite
342/// pass (Phase 6) builds steps without that numbering.
343#[derive(Debug, Clone, PartialEq, Eq)]
344pub struct RawStep {
345    /// 1-indexed step number across the whole plan. `0` until assigned by
346    /// `Plan::from_grouped`.
347    pub step_no: u32,
348    /// What kind of operation.
349    pub kind: StepKind,
350    /// Whether the step is destructive (requires explicit intent approval).
351    pub destructive: bool,
352    /// Human-readable reason for destructiveness, if any.
353    pub destructive_reason: Option<String>,
354    /// Intent id assigned by `Plan::from_grouped`; `None` until then.
355    pub intent_id: Option<u32>,
356    /// IR objects this step affects (used by directive comments).
357    pub targets: Vec<QualifiedName>,
358    /// Final SQL emitted to disk.
359    pub sql: String,
360    /// Whether the step can run inside a transaction.
361    pub transactional: TransactionConstraint,
362}
363
364#[cfg(test)]
365mod tests {
366    use super::*;
367
368    #[test]
369    fn step_kind_serializes_as_snake_case() {
370        let s = serde_json::to_string(&StepKind::CreateIndexConcurrent).unwrap();
371        assert_eq!(s, "\"create_index_concurrent\"");
372    }
373
374    #[allow(clippy::too_many_lines)] // One entry per StepKind variant — extraction would obscure intent.
375    #[test]
376    fn step_kind_round_trips_through_serde() {
377        for kind in [
378            StepKind::CreateSchema,
379            StepKind::DropSchema,
380            StepKind::AlterSchemaComment,
381            StepKind::CreateTable,
382            StepKind::DropTable,
383            StepKind::AlterTableSetComment,
384            StepKind::AddColumn,
385            StepKind::DropColumn,
386            StepKind::AlterColumnType,
387            StepKind::SetColumnNullable,
388            StepKind::SetColumnDefault,
389            StepKind::SetColumnComment,
390            StepKind::SetColumnIdentity,
391            StepKind::SetColumnGenerated,
392            StepKind::SetColumnStorage,
393            StepKind::SetColumnCompression,
394            StepKind::AddConstraint,
395            StepKind::AddConstraintNotValid,
396            StepKind::ValidateConstraint,
397            StepKind::DropConstraint,
398            StepKind::SetConstraintComment,
399            StepKind::CreateIndex,
400            StepKind::CreateIndexConcurrent,
401            StepKind::DropIndex,
402            StepKind::DropIndexConcurrent,
403            StepKind::CreateSequence,
404            StepKind::DropSequence,
405            StepKind::AlterSequence,
406            StepKind::AddCheckForNotNull,
407            StepKind::CreateView,
408            StepKind::DropView,
409            StepKind::AlterViewSetCheckOption,
410            StepKind::CreateMaterializedView,
411            StepKind::DropMaterializedView,
412            StepKind::RefreshMaterializedView,
413            StepKind::AlterViewSetReloption,
414            StepKind::CommentOnView,
415            StepKind::CreateType,
416            StepKind::DropType,
417            StepKind::AlterTypeAddValue,
418            StepKind::AlterTypeRenameValue,
419            StepKind::AlterDomainAddConstraint,
420            StepKind::AlterDomainDropConstraint,
421            StepKind::AlterDomainSetDefault,
422            StepKind::AlterDomainSetNotNull,
423            StepKind::AlterTypeAddAttribute,
424            StepKind::AlterTypeDropAttribute,
425            StepKind::AlterTypeAlterAttributeType,
426            StepKind::CommentOnType,
427            StepKind::CreateOrReplaceFunction,
428            StepKind::DropFunction,
429            StepKind::CommentOnFunction,
430            StepKind::CreateOrReplaceProcedure,
431            StepKind::DropProcedure,
432            StepKind::CommentOnProcedure,
433            StepKind::CreateExtension,
434            StepKind::DropExtension,
435            StepKind::AlterExtensionUpdate,
436            StepKind::CommentOnExtension,
437            StepKind::CreateTrigger,
438            StepKind::DropTrigger,
439            StepKind::CommentOnTrigger,
440            StepKind::AttachPartition,
441            StepKind::DetachPartition,
442            StepKind::CreateRole,
443            StepKind::DropRole,
444            StepKind::AlterRole,
445            StepKind::GrantRoleMembership,
446            StepKind::RevokeRoleMembership,
447            StepKind::CommentOnRole,
448            StepKind::CreateTablespace,
449            StepKind::DropTablespace,
450            StepKind::AlterTablespaceOwner,
451            StepKind::SetTablespaceOptions,
452            StepKind::CommentOnTablespace,
453            StepKind::AlterObjectOwner,
454            StepKind::GrantObjectPrivilege,
455            StepKind::RevokeObjectPrivilege,
456            StepKind::GrantColumnPrivilege,
457            StepKind::RevokeColumnPrivilege,
458            StepKind::AlterDefaultPrivileges,
459            StepKind::CreatePolicy,
460            StepKind::DropPolicy,
461            StepKind::AlterPolicy,
462            StepKind::SetTableRowSecurity,
463            StepKind::SetTableForceRowSecurity,
464            StepKind::SetTableStorage,
465            StepKind::SetIndexStorage,
466            StepKind::SetMaterializedViewStorage,
467            StepKind::CreatePublication,
468            StepKind::DropPublication,
469            StepKind::ReplacePublication,
470            StepKind::AlterPublicationAddTable,
471            StepKind::AlterPublicationDropTable,
472            StepKind::AlterPublicationSetTable,
473            StepKind::AlterPublicationAddSchema,
474            StepKind::AlterPublicationDropSchema,
475            StepKind::AlterPublicationSetPublish,
476            StepKind::AlterPublicationSetViaRoot,
477            StepKind::CommentOnPublication,
478            StepKind::CreateSubscription,
479            StepKind::DropSubscription,
480            StepKind::AlterSubscriptionConnection,
481            StepKind::AlterSubscriptionAddPublication,
482            StepKind::AlterSubscriptionDropPublication,
483            StepKind::AlterSubscriptionSetOptions,
484            StepKind::CommentOnSubscription,
485            StepKind::CreateStatistic,
486            StepKind::DropStatistic,
487            StepKind::ReplaceStatistic,
488            StepKind::AlterStatisticSetTarget,
489            StepKind::CommentOnStatistic,
490            StepKind::CreateCollation,
491            StepKind::DropCollation,
492            StepKind::RenameCollation,
493            StepKind::ReplaceCollation,
494            StepKind::CommentOnCollation,
495            StepKind::CreateEventTrigger,
496            StepKind::DropEventTrigger,
497            StepKind::AlterEventTriggerEnable,
498            StepKind::AlterEventTriggerOwner,
499            StepKind::CommentOnEventTrigger,
500            StepKind::CreateAggregate,
501            StepKind::DropAggregate,
502            StepKind::AlterAggregateOwner,
503            StepKind::CommentOnAggregate,
504            StepKind::CreateCast,
505            StepKind::DropCast,
506            StepKind::CommentOnCast,
507        ] {
508            let json = serde_json::to_string(&kind).unwrap();
509            let back: StepKind = serde_json::from_str(&json).unwrap();
510            assert_eq!(kind, back);
511        }
512    }
513
514    #[test]
515    fn transaction_constraint_serializes_as_snake_case() {
516        assert_eq!(
517            serde_json::to_string(&TransactionConstraint::OutsideTransaction).unwrap(),
518            "\"outside_transaction\"",
519        );
520    }
521}