import { AstEdges } from './closure'; import { SqlObjectRef } from './refs'; import { DependencyGraph } from './types'; /** * A change is *per-tenant* when it must be materialized once per instance * (its objects are duplicated across tenants), and *shared* when it can be * deployed a single time and reused. The partition is derived purely from the * reference graph: any change that (transitively) reaches a per-tenant seed is * itself per-tenant; everything else is provably tenant-independent. */ export interface PartitionResult { /** Changes that must be transpiled per tenant (a seed, or a dependent of one). */ perTenant: Set; /** Changes safe to deploy once and share across all instances. */ shared: Set; /** * For each per-tenant change, the shared changes it depends on. This is the * cross-boundary edge set: a per-tenant module `requires` the shared module * that owns these changes. Shared changes never depend on per-tenant ones by * construction, so the boundary is one-directional. */ sharedDependencies: Map>; /** Conditions that make the partition potentially unsound (see below). */ warnings: PartitionWarning[]; } export interface PartitionWarning { /** * - `dynamic-sql`: a change classified as shared runs `EXECUTE`, so its true * references are invisible to the parser — it *might* touch per-tenant data * and be unsafe to share. The partition cannot prove otherwise. * - `unresolved-reference`: a reference no change in the plan produces (an * installed module / extension); informational, not a soundness problem. * - `unknown-seed`: a requested seed change is not in the plan. */ kind: 'dynamic-sql' | 'unresolved-reference' | 'unknown-seed'; change: string; detail: string; } export interface PartitionInput { graph: DependencyGraph; astEdges: AstEdges; /** Change names whose objects are duplicated per tenant. */ seeds: Iterable; } /** * Pure partition core: classify every change in the graph as per-tenant or * shared by propagating "per-tenant-ness" from the seeds along dependency * edges (a change that depends on a per-tenant change is itself per-tenant). * * Deterministic and I/O-free — the on-disk entry point is * {@link partitionModule}. */ export declare function partitionChanges(input: PartitionInput): PartitionResult; export interface PartitionModuleOptions { /** Module root containing `pgpm.plan` and `deploy/`. */ moduleDir: string; /** Objects that are inherently per-tenant (e.g. a tenant-owned table). */ seedObjects: SqlObjectRef[]; /** Plan path override (defaults to `/pgpm.plan`). */ planPath?: string; } export interface PartitionModuleResult extends PartitionResult { /** The change that produces each seed object, in resolution order. */ seedChanges: string[]; } /** * On-disk entry point: parse a module's plan + deploy SQL, resolve the given * per-tenant seed *objects* to the changes that create them, and partition the * module into shared vs per-tenant changes. * * `loadModule()` from `plpgsql-parser` must have been awaited first (the SQL * fact extraction is synchronous over the WASM parser). */ export declare function partitionModule(options: PartitionModuleOptions): PartitionModuleResult;