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