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 MATERIALIZED VIEW ... WITH NO DATA`.
106 CreateMaterializedView,
107 /// `DROP MATERIALIZED VIEW`.
108 DropMaterializedView,
109 /// `REFRESH MATERIALIZED VIEW [CONCURRENTLY]`.
110 RefreshMaterializedView,
111 /// `ALTER VIEW ... SET (...)`.
112 AlterViewSetReloption,
113 /// `COMMENT ON VIEW / MATERIALIZED VIEW / COLUMN` for views and MVs.
114 CommentOnView,
115
116 // --- v0.2 user-defined type step kinds ---
117 /// `CREATE TYPE` (enum, domain, or composite).
118 CreateType,
119 /// `DROP TYPE`.
120 DropType,
121 /// `ALTER TYPE … ADD VALUE`.
122 AlterTypeAddValue,
123 /// `ALTER TYPE … RENAME VALUE`.
124 AlterTypeRenameValue,
125 /// `ALTER DOMAIN … ADD CONSTRAINT … CHECK (…)`.
126 AlterDomainAddConstraint,
127 /// `ALTER DOMAIN … DROP CONSTRAINT`.
128 AlterDomainDropConstraint,
129 /// `ALTER DOMAIN … SET DEFAULT` / `DROP DEFAULT`.
130 AlterDomainSetDefault,
131 /// `ALTER DOMAIN … SET NOT NULL` / `DROP NOT NULL`.
132 AlterDomainSetNotNull,
133 /// `ALTER TYPE … ADD ATTRIBUTE`.
134 AlterTypeAddAttribute,
135 /// `ALTER TYPE … DROP ATTRIBUTE`.
136 AlterTypeDropAttribute,
137 /// `ALTER TYPE … ALTER ATTRIBUTE … TYPE`.
138 AlterTypeAlterAttributeType,
139 /// `COMMENT ON TYPE` / `COMMENT ON DOMAIN`.
140 CommentOnType,
141
142 // --- v0.2 function / procedure step kinds ---
143 /// `CREATE OR REPLACE FUNCTION`.
144 CreateOrReplaceFunction,
145 /// `DROP FUNCTION`.
146 DropFunction,
147 /// `COMMENT ON FUNCTION`.
148 CommentOnFunction,
149 /// `CREATE OR REPLACE PROCEDURE`.
150 CreateOrReplaceProcedure,
151 /// `DROP PROCEDURE`.
152 DropProcedure,
153 /// `COMMENT ON PROCEDURE`.
154 CommentOnProcedure,
155
156 // --- v0.2 extension step kinds ---
157 /// `CREATE EXTENSION [IF NOT EXISTS] name [WITH SCHEMA s] [VERSION 'v']`.
158 CreateExtension,
159 /// `DROP EXTENSION name CASCADE`. Destructive (intent required).
160 DropExtension,
161 /// `ALTER EXTENSION name UPDATE TO 'v'`.
162 AlterExtensionUpdate,
163 /// `COMMENT ON EXTENSION name IS '...'`.
164 CommentOnExtension,
165
166 // --- v0.2 trigger step kinds ---
167 /// `CREATE [CONSTRAINT] TRIGGER name ... ON table ...`.
168 CreateTrigger,
169 /// `DROP TRIGGER name ON table`.
170 DropTrigger,
171 /// `COMMENT ON TRIGGER name ON table IS '...'`.
172 CommentOnTrigger,
173
174 // --- v0.2 partition step kinds ---
175 /// `ALTER TABLE parent ATTACH PARTITION child FOR VALUES ...`.
176 AttachPartition,
177 /// `ALTER TABLE parent DETACH PARTITION child`.
178 DetachPartition,
179
180 // --- v0.3 cluster / role step kinds ---
181 /// `CREATE ROLE`.
182 CreateRole,
183 /// `DROP ROLE`.
184 DropRole,
185 /// `ALTER ROLE … WITH <options>`.
186 AlterRole,
187 /// `GRANT role TO member`.
188 GrantRoleMembership,
189 /// `REVOKE role FROM member`.
190 RevokeRoleMembership,
191 /// `COMMENT ON ROLE`.
192 CommentOnRole,
193
194 // --- v0.3.1 grant / ownership step kinds ---
195 /// `ALTER <kind> qname OWNER TO new_owner`.
196 AlterObjectOwner,
197 /// `GRANT priv ON <kind> qname TO grantee [WITH GRANT OPTION]`.
198 GrantObjectPrivilege,
199 /// `REVOKE priv ON <kind> qname FROM grantee`.
200 RevokeObjectPrivilege,
201 /// `GRANT priv (col, …) ON TABLE qname TO grantee [WITH GRANT OPTION]`.
202 GrantColumnPrivilege,
203 /// `REVOKE priv (col, …) ON TABLE qname FROM grantee`.
204 RevokeColumnPrivilege,
205 /// `ALTER DEFAULT PRIVILEGES FOR ROLE x [IN SCHEMA y] GRANT/REVOKE priv ON … TO/FROM z`.
206 AlterDefaultPrivileges,
207
208 // --- v0.3.2 row-level security policy step kinds ---
209 /// `CREATE POLICY name ON table …`.
210 CreatePolicy,
211 /// `DROP POLICY name ON table`.
212 DropPolicy,
213 /// `ALTER POLICY name ON table TO … USING (…) WITH CHECK (…)`.
214 AlterPolicy,
215 /// `ALTER TABLE qname { ENABLE | DISABLE } ROW LEVEL SECURITY`.
216 SetTableRowSecurity,
217 /// `ALTER TABLE qname { FORCE | NO FORCE } ROW LEVEL SECURITY`.
218 SetTableForceRowSecurity,
219
220 // --- v0.3.3 reloption step kinds ---
221 /// `ALTER TABLE qname SET (fillfactor = …, …)`.
222 SetTableStorage,
223 /// `ALTER INDEX qname SET (fillfactor = …, …)`.
224 SetIndexStorage,
225 /// `ALTER MATERIALIZED VIEW qname SET (fillfactor = …, …)`.
226 SetMaterializedViewStorage,
227
228 // --- v0.3.4 publication step kinds ---
229 /// `CREATE PUBLICATION …`.
230 CreatePublication,
231 /// `DROP PUBLICATION …`. Destructive (intent required).
232 DropPublication,
233 /// `DROP PUBLICATION old; CREATE PUBLICATION new;` — mode swap. Destructive.
234 ReplacePublication,
235 /// `ALTER PUBLICATION p ADD TABLE x [(cols)] [WHERE (filter)]`.
236 AlterPublicationAddTable,
237 /// `ALTER PUBLICATION p DROP TABLE x`.
238 AlterPublicationDropTable,
239 /// `ALTER PUBLICATION p SET TABLE x (cols) WHERE (filter)`.
240 AlterPublicationSetTable,
241 /// `ALTER PUBLICATION p ADD TABLES IN SCHEMA s` (PG 15+).
242 AlterPublicationAddSchema,
243 /// `ALTER PUBLICATION p DROP TABLES IN SCHEMA s` (PG 15+).
244 AlterPublicationDropSchema,
245 /// `ALTER PUBLICATION p SET (publish = '...')`.
246 AlterPublicationSetPublish,
247 /// `ALTER PUBLICATION p SET (publish_via_partition_root = ...)`.
248 AlterPublicationSetViaRoot,
249 /// `COMMENT ON PUBLICATION p IS '...'`.
250 CommentOnPublication,
251}
252
253/// One unit of work the executor will attempt.
254///
255/// `step_no` and `intent_id` start at zero / `None` and are assigned later
256/// by [`Plan::from_grouped`](crate::plan::Plan::from_grouped). The rewrite
257/// pass (Phase 6) builds steps without that numbering.
258#[derive(Debug, Clone, PartialEq, Eq)]
259pub struct RawStep {
260 /// 1-indexed step number across the whole plan. `0` until assigned by
261 /// `Plan::from_grouped`.
262 pub step_no: u32,
263 /// What kind of operation.
264 pub kind: StepKind,
265 /// Whether the step is destructive (requires explicit intent approval).
266 pub destructive: bool,
267 /// Human-readable reason for destructiveness, if any.
268 pub destructive_reason: Option<String>,
269 /// Intent id assigned by `Plan::from_grouped`; `None` until then.
270 pub intent_id: Option<u32>,
271 /// IR objects this step affects (used by directive comments).
272 pub targets: Vec<QualifiedName>,
273 /// Final SQL emitted to disk.
274 pub sql: String,
275 /// Whether the step can run inside a transaction.
276 pub transactional: TransactionConstraint,
277}
278
279#[cfg(test)]
280mod tests {
281 use super::*;
282
283 #[test]
284 fn step_kind_serializes_as_snake_case() {
285 let s = serde_json::to_string(&StepKind::CreateIndexConcurrent).unwrap();
286 assert_eq!(s, "\"create_index_concurrent\"");
287 }
288
289 #[test]
290 fn step_kind_round_trips_through_serde() {
291 for kind in [
292 StepKind::CreateSchema,
293 StepKind::DropSchema,
294 StepKind::AlterSchemaComment,
295 StepKind::CreateTable,
296 StepKind::DropTable,
297 StepKind::AlterTableSetComment,
298 StepKind::AddColumn,
299 StepKind::DropColumn,
300 StepKind::AlterColumnType,
301 StepKind::SetColumnNullable,
302 StepKind::SetColumnDefault,
303 StepKind::SetColumnComment,
304 StepKind::SetColumnIdentity,
305 StepKind::SetColumnGenerated,
306 StepKind::SetColumnStorage,
307 StepKind::SetColumnCompression,
308 StepKind::AddConstraint,
309 StepKind::AddConstraintNotValid,
310 StepKind::ValidateConstraint,
311 StepKind::DropConstraint,
312 StepKind::SetConstraintComment,
313 StepKind::CreateIndex,
314 StepKind::CreateIndexConcurrent,
315 StepKind::DropIndex,
316 StepKind::DropIndexConcurrent,
317 StepKind::CreateSequence,
318 StepKind::DropSequence,
319 StepKind::AlterSequence,
320 StepKind::AddCheckForNotNull,
321 StepKind::CreateView,
322 StepKind::DropView,
323 StepKind::CreateMaterializedView,
324 StepKind::DropMaterializedView,
325 StepKind::RefreshMaterializedView,
326 StepKind::AlterViewSetReloption,
327 StepKind::CommentOnView,
328 StepKind::CreateType,
329 StepKind::DropType,
330 StepKind::AlterTypeAddValue,
331 StepKind::AlterTypeRenameValue,
332 StepKind::AlterDomainAddConstraint,
333 StepKind::AlterDomainDropConstraint,
334 StepKind::AlterDomainSetDefault,
335 StepKind::AlterDomainSetNotNull,
336 StepKind::AlterTypeAddAttribute,
337 StepKind::AlterTypeDropAttribute,
338 StepKind::AlterTypeAlterAttributeType,
339 StepKind::CommentOnType,
340 StepKind::CreateOrReplaceFunction,
341 StepKind::DropFunction,
342 StepKind::CommentOnFunction,
343 StepKind::CreateOrReplaceProcedure,
344 StepKind::DropProcedure,
345 StepKind::CommentOnProcedure,
346 StepKind::CreateExtension,
347 StepKind::DropExtension,
348 StepKind::AlterExtensionUpdate,
349 StepKind::CommentOnExtension,
350 StepKind::CreateTrigger,
351 StepKind::DropTrigger,
352 StepKind::CommentOnTrigger,
353 StepKind::AttachPartition,
354 StepKind::DetachPartition,
355 StepKind::CreateRole,
356 StepKind::DropRole,
357 StepKind::AlterRole,
358 StepKind::GrantRoleMembership,
359 StepKind::RevokeRoleMembership,
360 StepKind::CommentOnRole,
361 StepKind::AlterObjectOwner,
362 StepKind::GrantObjectPrivilege,
363 StepKind::RevokeObjectPrivilege,
364 StepKind::GrantColumnPrivilege,
365 StepKind::RevokeColumnPrivilege,
366 StepKind::AlterDefaultPrivileges,
367 StepKind::CreatePolicy,
368 StepKind::DropPolicy,
369 StepKind::AlterPolicy,
370 StepKind::SetTableRowSecurity,
371 StepKind::SetTableForceRowSecurity,
372 StepKind::SetTableStorage,
373 StepKind::SetIndexStorage,
374 StepKind::SetMaterializedViewStorage,
375 StepKind::CreatePublication,
376 StepKind::DropPublication,
377 StepKind::ReplacePublication,
378 StepKind::AlterPublicationAddTable,
379 StepKind::AlterPublicationDropTable,
380 StepKind::AlterPublicationSetTable,
381 StepKind::AlterPublicationAddSchema,
382 StepKind::AlterPublicationDropSchema,
383 StepKind::AlterPublicationSetPublish,
384 StepKind::AlterPublicationSetViaRoot,
385 StepKind::CommentOnPublication,
386 ] {
387 let json = serde_json::to_string(&kind).unwrap();
388 let back: StepKind = serde_json::from_str(&json).unwrap();
389 assert_eq!(kind, back);
390 }
391 }
392
393 #[test]
394 fn transaction_constraint_serializes_as_snake_case() {
395 assert_eq!(
396 serde_json::to_string(&TransactionConstraint::OutsideTransaction).unwrap(),
397 "\"outside_transaction\"",
398 );
399 }
400}