@@ -23,7 +23,9 @@ import {
2323 buildStatementGraph ,
2424 classifyStatements ,
2525 identityOf ,
26- restructureSql
26+ restructureSql ,
27+ revertFor ,
28+ verifyFor
2729} from '@pgsql/transform' ;
2830
2931export type { Granularity } from '@pgsql/transform' ;
@@ -38,6 +40,22 @@ export interface GranularityChange {
3840 deploy : string ;
3941}
4042
43+ /** A restructured change: deploy plus generated revert/verify scripts. */
44+ export interface RestructuredChange extends GranularityChange {
45+ /**
46+ * Generated revert SQL (headerless): mechanical inverses of the change's
47+ * statements in reverse topological order within the group, via
48+ * `revertFor`. Non-invertible statements leave a `-- revert not
49+ * derivable` comment and a warning.
50+ */
51+ revert : string ;
52+ /**
53+ * Generated verify SQL (headerless): one raise-on-failure existence check
54+ * per created object, via `verifyFor`.
55+ */
56+ verify : string ;
57+ }
58+
4159export interface RestructureModuleOptions {
4260 granularity : Granularity ;
4361 /**
@@ -50,7 +68,7 @@ export interface RestructureModuleOptions {
5068
5169export interface RestructureModuleResult {
5270 /** Restructured changes in deploy order, dependencies recomputed. */
53- changes : GranularityChange [ ] ;
71+ changes : RestructuredChange [ ] ;
5472 /** Non-fatal notes (folds rejected to preserve ordering, etc.). */
5573 warnings : string [ ] ;
5674}
@@ -145,14 +163,17 @@ export function restructureChanges(
145163 }
146164 } ) ;
147165
148- // Slice statement text per group, in the emitted (topological) order.
166+ // Slice statement text per group, in the emitted (topological) order,
167+ // and collect each group's facts for revert/verify generation.
149168 const groupSql : string [ ] [ ] = groupNames . map ( ( ) : string [ ] => [ ] ) ;
169+ const groupStatements : StatementFacts [ ] [ ] = groupNames . map ( ( ) : StatementFacts [ ] => [ ] ) ;
150170
151171 facts . forEach ( ( f , i ) => {
152172 const text = sql . slice ( f . span . start , f . span . start + f . span . len ) . trim ( ) ;
153173 const g = groupOf [ i ] ;
154174 if ( g !== - 1 && text ) {
155175 groupSql [ g ] . push ( text . endsWith ( ';' ) ? text : `${ text } ;` ) ;
176+ groupStatements [ g ] . push ( f ) ;
156177 }
157178 } ) ;
158179
@@ -185,13 +206,25 @@ export function restructureChanges(
185206 return firstA - firstB ;
186207 } ) ;
187208
188- const result : GranularityChange [ ] = order
209+ const result : RestructuredChange [ ] = order
189210 . filter ( g => groupSql [ g ] . length > 0 )
190- . map ( g => ( {
191- name : groupNames [ g ] ,
192- dependencies : [ ...groupDeps [ g ] ] . map ( d => groupNames [ d ] ) . sort ( ) ,
193- deploy : groupSql [ g ] . join ( '\n\n' )
194- } ) ) ;
211+ . map ( g => {
212+ const revert = revertFor ( groupStatements [ g ] ) ;
213+ const verify = verifyFor ( groupStatements [ g ] ) ;
214+ for ( const warning of revert . warnings ) {
215+ warnings . push ( `${ groupNames [ g ] } : ${ warning } ` ) ;
216+ }
217+ for ( const warning of verify . warnings ) {
218+ warnings . push ( `${ groupNames [ g ] } : ${ warning } ` ) ;
219+ }
220+ return {
221+ name : groupNames [ g ] ,
222+ dependencies : [ ...groupDeps [ g ] ] . map ( d => groupNames [ d ] ) . sort ( ) ,
223+ deploy : groupSql [ g ] . join ( '\n\n' ) ,
224+ revert : revert . sql ,
225+ verify : verify . sql
226+ } ;
227+ } ) ;
195228
196229 return { changes : result , warnings } ;
197230}
0 commit comments