11import { parseSync , scanSync } from '@libpg-query/parser' ;
22import { ParseResult , Node } from '@pgsql/types' ;
3- import { Deparser } from 'pgsql-deparser' ;
3+ import { Deparser , DeparserOptions } from 'pgsql-deparser' ;
44import {
55 HydratedExprQuery ,
66 HydratedExprRaw ,
@@ -15,6 +15,18 @@ import {
1515} from './hydrate-types' ;
1616import { PLpgSQLParseResult } from './types' ;
1717
18+ /**
19+ * Options for dehydrating (converting back to strings) a hydrated PL/pgSQL AST
20+ */
21+ export interface DehydrationOptions {
22+ /**
23+ * Options to pass to the SQL deparser when deparsing sql-stmt expressions.
24+ * This allows callers to control formatting (pretty printing, etc.) of
25+ * embedded SQL statements inside PL/pgSQL function bodies.
26+ */
27+ sqlDeparseOptions ?: DeparserOptions ;
28+ }
29+
1830function extractExprFromSelectWrapper ( result : ParseResult ) : Node | undefined {
1931 const stmt = result . stmts ?. [ 0 ] ?. stmt as any ;
2032 if ( stmt ?. SelectStmt ?. targetList ?. [ 0 ] ?. ResTarget ?. val ) {
@@ -352,17 +364,17 @@ export function getOriginalQuery(query: string | HydratedExprQuery): string {
352364 return query . original ;
353365}
354366
355- export function dehydratePlpgsqlAst < T > ( ast : T ) : T {
356- return dehydrateNode ( ast ) as T ;
367+ export function dehydratePlpgsqlAst < T > ( ast : T , options ?: DehydrationOptions ) : T {
368+ return dehydrateNode ( ast , options ) as T ;
357369}
358370
359- function dehydrateNode ( node : any ) : any {
371+ function dehydrateNode ( node : any , options ?: DehydrationOptions ) : any {
360372 if ( node === null || node === undefined ) {
361373 return node ;
362374 }
363375
364376 if ( Array . isArray ( node ) ) {
365- return node . map ( item => dehydrateNode ( item ) ) ;
377+ return node . map ( item => dehydrateNode ( item , options ) ) ;
366378 }
367379
368380 if ( typeof node !== 'object' ) {
@@ -377,7 +389,7 @@ function dehydrateNode(node: any): any {
377389 if ( typeof query === 'string' ) {
378390 dehydratedQuery = query ;
379391 } else if ( isHydratedExpr ( query ) ) {
380- dehydratedQuery = dehydrateQuery ( query ) ;
392+ dehydratedQuery = dehydrateQuery ( query , options ?. sqlDeparseOptions ) ;
381393 } else {
382394 dehydratedQuery = String ( query ) ;
383395 }
@@ -392,12 +404,12 @@ function dehydrateNode(node: any): any {
392404
393405 const result : any = { } ;
394406 for ( const [ key , value ] of Object . entries ( node ) ) {
395- result [ key ] = dehydrateNode ( value ) ;
407+ result [ key ] = dehydrateNode ( value , options ) ;
396408 }
397409 return result ;
398410}
399411
400- function dehydrateQuery ( query : HydratedExprQuery ) : string {
412+ function dehydrateQuery ( query : HydratedExprQuery , sqlDeparseOptions ?: DeparserOptions ) : string {
401413 switch ( query . kind ) {
402414 case 'assign' : {
403415 // For assignments, use the target and value strings directly
@@ -408,10 +420,11 @@ function dehydrateQuery(query: HydratedExprQuery): string {
408420 case 'sql-stmt' : {
409421 // Deparse the modified parseResult back to SQL
410422 // This enables AST-based transformations (e.g., schema renaming)
423+ // Pass through sqlDeparseOptions to control formatting (pretty printing, etc.)
411424 const stmtQuery = query as HydratedExprSqlStmt ;
412425 if ( stmtQuery . parseResult ?. stmts ?. [ 0 ] ?. stmt ) {
413426 try {
414- return Deparser . deparse ( stmtQuery . parseResult . stmts [ 0 ] . stmt ) ;
427+ return Deparser . deparse ( stmtQuery . parseResult . stmts [ 0 ] . stmt , sqlDeparseOptions ) ;
415428 } catch {
416429 // Fall back to original if deparse fails
417430 return query . original ;
0 commit comments