/** * AST-based Schema Name Transformer (Core Logic) * * Pure transformation functions for converting schema names in SQL strings. * No file I/O — takes SQL strings in and returns transformed SQL strings out. * * The transformer handles: * - Schema-qualified identifiers in RangeVar nodes (schema.table) * - Schema names in CreateSchemaStmt nodes * - Schema-qualified function names in FuncCall and CreateFunctionStmt nodes * - Schema-qualified type names in TypeName nodes * - Schema names in GrantStmt objects array * - Schema names in VariableSetStmt (SET search_path) * - Schema names in AlterDefaultPrivilegesStmt * - Schema names in DropStmt (DROP SCHEMA) * - Schema-qualified trigger function names in CreateTrigStmt * - Schema-qualified object references in CommentStmt * - Schema-qualified names in DefineStmt (CREATE TYPE, CREATE AGGREGATE) * - Schema-qualified names in CreateDomainStmt, CreateEnumStmt, AlterEnumStmt * - Schema-qualified names in AlterDomainStmt, AlterTypeStmt * - Schema-qualified names in ObjectWithArgs (ALTER FUNCTION, etc.) * - Schema name in AlterObjectSchemaStmt (ALTER ... SET SCHEMA) * - Schema names inside PL/pgSQL function bodies (hydrated AST) * - Comment headers, verify function calls, JSON string values (regex fallback) */ import type { QualifyUnqualifiedOptions } from './qualify'; import type { RouteNamespace } from './router'; import { SchemaRouter } from './router'; /** A schema mapping accepted by the transform: the classic whole-schema map or a router. */ export type SchemaMappingInput = Map | SchemaRouter; export interface SchemaTransformResult { schemasFound: Set; schemasTransformed: Map; errors: Array<{ file: string; error: string; }>; } /** * A pluggable string-level transform pass. * * Extension passes run on the raw SQL text before or after the core AST * transformation. They exist for content that is opaque to the SQL parser * (string literals, comments, JSON values, etc.). * * Each pass receives the current content string, the schema mapping, and the * shared result tracker, and must return the (possibly transformed) content. */ export type SchemaTransformPass = (content: string, schemaMapping: Map, result: SchemaTransformResult) => string; /** * Options for transform_sql. */ export interface TransformSqlOptions { /** * Extension passes that run BEFORE the core AST transformation. * Use these for app-specific string-level transforms that must happen * before the parser sees the content (e.g. verify calls, JSON values). */ prePasses?: SchemaTransformPass[]; /** * Extension passes that run AFTER the core AST transformation. * Use these for app-specific transforms on the deparsed output. */ postPasses?: SchemaTransformPass[]; /** * Validate that the emitted SQL re-parses to an AST structurally identical * to the transformed AST that was deparsed (catches deparser fidelity bugs * such as dropped array bounds). Adds a second parse per file. */ roundTrip?: boolean; /** * Qualify unqualified object references BEFORE the schema mapping runs * (an extra AST pass, opt-in). Pin unqualified references to a schema * (typically `'public'`) so a mapping on that schema moves them too — * the ingestion path for handwritten, unqualified SQL. Only names in the * inventory (defaulting to objects the content itself creates) are * qualified. See {@link qualifyUnqualified}. */ qualifyUnqualified?: QualifyUnqualifiedOptions; /** * Schema names (post-mapping) whose `CREATE SCHEMA` statements should be * emitted as `CREATE SCHEMA IF NOT EXISTS`. Use when mapping into a schema * that always exists — e.g. mapping a named schema onto `public`. */ assumeSchemasExist?: string[]; } /** * Transform a schema name if it exists in the mapping */ export declare function transformSchemaName(schemaName: string | undefined, schemaMapping: Map): string | undefined; /** * Check if a schema name should be transformed */ export declare function shouldTransformSchema(schemaName: string | undefined, schemaMapping: Map): boolean; /** * Transform schema names in a String node array (used for funcname, names, etc.) * These arrays contain String nodes like { String: { sval: 'schema_name' } } * * `ns` names the namespace of the referenced object so object-level routes can * apply; the object's own name is the last element of the list. When `ns` is * `unknown` (the default) only the schema-level default applies — identical to * the historic whole-schema behaviour. */ export declare function transformNameList(names: any[] | undefined, schemaMapping: SchemaMappingInput, result: SchemaTransformResult, ns?: RouteNamespace): void; /** * Transform a bare schema-name field on a node (e.g. { String: { sval } } * entries in GrantStmt.objects, RenameStmt.subname, CommentStmt.object). * Returns the (possibly new) schema name. */ export declare function transformSchemaNameField(container: any, field: string, schemaMapping: SchemaMappingInput, result: SchemaTransformResult): void; /** * Transform a RangeVar-like relation object (has schemaname/relname fields). * The walker auto-recurses into embedded relations (concrete `RangeVar` * fields are tag-synthesized), so the generic `RangeVar` visitor covers * every occurrence; statement handlers call this directly only when they * carry extra context, and the claim guard keeps each relation routed once. */ export declare function transformRelation(relation: any, schemaMapping: SchemaMappingInput, result: SchemaTransformResult): void; /** * Transform schema-qualified references embedded in a plain string * (e.g. advisory-lock keys like 'schema-name.fn_name', COMMENT text, * RAISE messages). Only occurrences of a mapped schema name immediately * followed by a dot are rewritten. */ export declare function transformSchemaRefsInString(str: string, schemaMapping: SchemaMappingInput, result: SchemaTransformResult): string; /** * The namespace a cast resolves its operand in, or `undefined` when the target * type is not an object-identity type. */ export declare function identityCastNamespace(typeName: any): RouteNamespace | undefined; /** * Route the object reference carried in the string operand of an identity * cast. `ns` comes from the cast's target type. * * Unqualified operands (`'tbl'::regclass`) name no schema — they resolve * through `search_path` — so they are returned unchanged. */ export declare function transformIdentityCastLiteral(sval: string, ns: RouteNamespace, schemaMapping: SchemaMappingInput, result: SchemaTransformResult): string; /** * Create a SQL AST visitor that transforms schema names. * * The walker from @pgsql/traverse auto-recurses into child nodes, so visitors * like RangeVar and TypeName fire for every occurrence regardless of parent. * However, some node types carry schema names as plain strings or name lists * that require explicit handlers. */ export declare function createSqlVisitor(schemaMapping: SchemaMappingInput, result: SchemaTransformResult, visitorOptions?: { assumeSchemasExist?: Set; }): { RangeVar: (path: any) => void; CreateSchemaStmt: (path: any) => void; FuncCall: (path: any) => void; TypeName: (path: any) => void; ColumnRef: (path: any) => void; GrantStmt: (path: any) => void; VariableSetStmt: (path: any) => void; AlterDefaultPrivilegesStmt: (path: any) => void; DropStmt: (path: any) => void; AlterSeqStmt: (path: any) => void; CreateFunctionStmt: (path: any) => void; CreateTrigStmt: (path: any) => void; CommentStmt: (path: any) => void; A_Const: (path: any) => void; TypeCast: (path: any) => void; DefineStmt: (path: any) => void; CreateDomainStmt: (path: any) => void; CreateEnumStmt: (path: any) => void; AlterEnumStmt: (path: any) => void; AlterDomainStmt: (path: any) => void; AlterTypeStmt: (path: any) => void; ObjectWithArgs: (path: any) => void; AlterObjectSchemaStmt: (path: any) => void; RenameStmt: (path: any) => void; AlterFunctionStmt: (path: any) => void; AlterOwnerStmt: (path: any) => void; CreateCastStmt: (path: any) => void; CreateEventTrigStmt: (path: any) => void; IndexElem: (path: any) => void; SecLabelStmt: (path: any) => void; DoStmt: (path: any) => void; }; /** * Validate that no untransformed schema names remain in the output. * Checks both schema-qualified references (schema.object) and standalone * schema name contexts (ON SCHEMA, IN SCHEMA, CREATE SCHEMA, etc.). * * Throws an error if any schema names from the mapping are found in the output, * indicating that the AST visitor is missing a handler for that node type. */ export declare function validateNoUntransformedSchemas(content: string, schemaMapping: SchemaMappingInput): void; /** * Create a PL/pgSQL visitor that transforms schema names in PL/pgSQL-specific nodes. */ export declare function createPlpgsqlVisitor(schemaMapping: SchemaMappingInput, result: SchemaTransformResult): { PLpgSQL_type: (path: any) => void; PLpgSQL_var: (path: any) => void; }; /** * Transform a PLpgSQL_type typname using proper AST parsing. */ export declare function transformPlpgsqlTypeAst(typname: string, schemaMapping: SchemaMappingInput, result: SchemaTransformResult): string; /** * Fallback string-based transformation for PLpgSQL_type typname. * Uses @pgsql/quotes QuoteUtils for proper identifier quoting. */ export declare function transformPlpgsqlTypeString(typname: string, schemaMapping: SchemaMappingInput, result: SchemaTransformResult): string; /** * Recursively walk the PL/pgSQL AST to transform schema names. */ export declare function walkPlpgsqlForSchemas(node: any, schemaMapping: SchemaMappingInput, result: SchemaTransformResult): void; /** * Escape a string for use in a regular expression */ export declare function escapeRegexp(str: string): string; /** * Extract pgpm header comments from the beginning of SQL content. */ export declare function extractPgpmHeader(content: string): { header: string; body: string; }; /** * Transform comment headers (-- Deploy:, -- requires:, etc.) * These are not part of the SQL AST, so we use regexp for these. */ export declare function transformComments(content: string, schemaMapping: Map, result: SchemaTransformResult): string; /** * Transform schema names inside JSON/JSONB string values. */ export declare function transformJsonStringValues(content: string, schemaMapping: Map, result: SchemaTransformResult): string; /** * Transform a single SQL string using full AST-based transformation. * * This is the main entry point for transforming SQL content. It: * 1. Runs any user-supplied pre-passes (string-level) * 2. Extracts pgpm header comments and transforms them * 3. Runs full AST transformation on the SQL body * 4. Runs any user-supplied post-passes (string-level) * 5. Validates no untransformed schema names remain * 6. Returns the combined result * * App-specific string-level transforms (verify calls, JSON values, etc.) * are NOT included by default — pass them via `options.pre_passes` or * `options.post_passes`. The built-in passes `transform_verify_calls` * and `transform_json_string_values` are exported for convenience. */ export declare function transformSql(content: string, schemaMapping: SchemaMappingInput, options?: TransformSqlOptions | SchemaTransformResult, result?: SchemaTransformResult): { content: string; result: SchemaTransformResult; }; /** * Transform a single SQL statement string using AST. * Unlike transform_sql, this does NOT handle headers, verify calls, or JSON values. * Use this for testing individual SQL statements. */ export declare function transformSqlStatement(sql: string, schemaMapping: SchemaMappingInput, result?: SchemaTransformResult): { sql: string; result: SchemaTransformResult; };