import { SchemaRouter, SqlProgram, StatementFacts } from '@pgpmjs/transform'; import { SqlObjectGraph } from './object-graph'; import { SqlObjectRef } from './refs'; /** * Selects a *subsystem*: the set of objects a module owns that a consumer * wants to remove and substitute with another provider. Selection is by * schema — every object created in one of these schemas belongs to the * subsystem, as do the schemas themselves. */ export interface SubsystemSelector { schemas: string[]; } /** * One reference the surviving statements make *into* the subsystem. This is * the subsystem's external contract: whatever replaces it must satisfy every * one of these (or the consumer must rewrite the referencing statement). */ export interface SubsystemDependency { /** The subsystem object being depended on. */ object: SqlObjectRef; /** True when at least one dependent is a foreign-key constraint. */ fk: boolean; /** Statement indexes (into the classified statement list) that depend on it. */ dependents: number[]; } /** * The measured external contract of a subsystem: what the rest of the SQL * actually requires of it, derived purely from the reference graph. */ export interface SubsystemContract { /** Objects the subsystem creates. */ provides: SqlObjectRef[]; /** Subsystem objects referenced from outside — the replacement surface. */ required: SubsystemDependency[]; /** Subsystem objects nothing outside references — safe to drop silently. */ internal: SqlObjectRef[]; } export interface ExcludeWarning { /** * - `mixed-statement`: a statement creates objects both inside and outside * the subsystem, so it can be neither dropped nor kept cleanly. * - `opaque-statement`: a statement's target is invisible to classification * (e.g. `COMMENT ON`, bare `DROP`), so it is kept but may reference a * dropped object. * - `dynamic-sql`: a kept statement runs `EXECUTE`; references inside the * dynamic string cannot be checked against the subsystem. */ kind: 'mixed-statement' | 'opaque-statement' | 'dynamic-sql'; statement: number; detail: string; } /** * A kept statement references a subsystem object that no route rebinds to a * replacement. Exclusion is unsafe until every one of these is resolved. */ export interface UnsatisfiedReference { object: SqlObjectRef; statement: number; fk: boolean; } export interface ExcludeResult { /** Indexes of statements belonging to the subsystem (to be dropped). */ excluded: number[]; /** Indexes of surviving statements. */ kept: number[]; /** The subsystem's measured external contract. */ contract: SubsystemContract; /** * References into the subsystem from kept statements that the provided * router does not rebind. Empty ⇔ the exclusion is safe. */ unsatisfied: UnsatisfiedReference[]; warnings: ExcludeWarning[]; /** The classified statements, for callers that need the facts. */ statements: StatementFacts[]; /** The parsed program the analysis ran over (one parse, shared with strip). */ program: SqlProgram; } /** * Partition a SQL script into a subsystem (statements to exclude) and its * survivors, measure the subsystem's external contract, and verify that a * routing profile rebinds every surviving reference into it. * * Pure and I/O-free. The caller applies the actual removal/rewrite (e.g. via * `transpileBundle`'s `transformScript` with the same router); this function * only *decides* and *checks* — exclusion is safe iff `unsatisfied` is empty. */ export declare function excludeSubsystem(sql: string, selector: SubsystemSelector, options?: { rebinds?: SchemaRouter; }): ExcludeResult; /** An `UnsatisfiedReference`/`ExcludeWarning` tagged with its owning program. */ export type ProgramUnsatisfiedReference = UnsatisfiedReference & { program: string; }; export type ProgramExcludeWarning = ExcludeWarning & { program: string; }; /** Per-program exclusion decisions from {@link excludeSubsystemPrograms}. */ export interface ProgramExclusion { /** Statement indexes removed: subsystem members + opaque subsystem-targeted. */ dropped: number[]; /** * The whole program consists of subsystem statements (plus transaction * control): it should be removed as a unit rather than emptied in place. */ fullyExcluded: boolean; /** The surviving SQL with the dropped statements sliced out. */ sql: string; } export interface ExcludeProgramsResult { /** The unified object graph over every analyzed program. */ graph: SqlObjectGraph; /** The subsystem's external contract, measured across all programs. */ contract: SubsystemContract; /** Unrebound references into the subsystem, tagged with their program. */ unsatisfied: ProgramUnsatisfiedReference[]; warnings: ProgramExcludeWarning[]; /** Per-program decisions, keyed by program name. */ programs: Map; } /** * Analyze a subsystem exclusion across a set of already-parsed programs * (typically one per pgpm change) in a single pass: the contract and cascade * safety are measured over all programs together — which is what catches * cross-change dependencies on the subsystem — while drop/strip/prune * decisions are returned per program, derived from statement membership and * ownership rather than survivor counting. The unified {@link SqlObjectGraph} * over the same programs is returned for structural queries. */ export declare function excludeSubsystemPrograms(programs: Map | Array<[string, SqlProgram]>, selector: SubsystemSelector, options?: { rebinds?: SchemaRouter; }): ExcludeProgramsResult; /** * Blank a script: keep its leading text (pgpm header) and transaction * statements, drop everything else. Used for the scripts of a change whose * deploy is entirely inside an excluded subsystem — its verify/revert bodies * target dropped objects, so they must go with it. */ export declare function blankScriptSql(sql: string): string; export interface StripSubsystemResult { /** The surviving SQL, with subsystem statements removed. */ sql: string; /** The analysis behind the removal (contract, unsatisfied, warnings). */ result: ExcludeResult; /** Every removed statement index (excluded + opaque subsystem-targeted). */ dropped: number[]; } /** * Remove a subsystem's statements from a SQL script, preserving the original * text of every survivor (no reformat — statements are sliced out of the * source by parser-reported location). Also removes opaque statements that * provably target only subsystem objects (`DROP`/`COMMENT ON` them), which * membership classification alone keeps. * * Requires `await loadModule()` first (same as every other sync API here). * This performs no safety check by itself — callers decide what to do with * `result.unsatisfied` (typically: refuse before ever writing output). */ export declare function stripSubsystemSql(sql: string, selector: SubsystemSelector, options?: { rebinds?: SchemaRouter; }): StripSubsystemResult;