@prisma-next/adapter-postgres 0.3.0-dev.41 → 0.3.0-dev.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -108,10 +108,22 @@ function renderNullCheck(expr, contract) {
108
108
  return expr.isNull ? `${renderedExpr} IS NULL` : `${renderedExpr} IS NOT NULL`;
109
109
  }
110
110
  function renderBinary(expr, contract) {
111
+ if (expr.right.kind === "listLiteral" && expr.right.values.length === 0) {
112
+ if (expr.op === "in") return "FALSE";
113
+ if (expr.op === "notIn") return "TRUE";
114
+ }
111
115
  const leftExpr = expr.left;
112
116
  const left = renderExpr(leftExpr, contract);
113
117
  const leftRendered = isOperationExpr(leftExpr) ? `(${left})` : left;
114
- const right = renderBinaryRight(expr.right, contract);
118
+ const leftCol = leftExpr.kind === "col" ? leftExpr : void 0;
119
+ const rightExpr = expr.right;
120
+ let right;
121
+ if (rightExpr.kind === "listLiteral") right = renderListLiteral(rightExpr, contract, leftCol?.table, leftCol?.column);
122
+ else if (rightExpr.kind === "literal") right = renderLiteral(rightExpr);
123
+ else if (rightExpr.kind === "col") right = renderColumn(rightExpr);
124
+ else if (rightExpr.kind === "param") right = renderParam(rightExpr, contract, leftCol?.table, leftCol?.column);
125
+ else if (rightExpr.kind === "operation") right = renderOperation(rightExpr, contract);
126
+ else right = renderColumn(rightExpr);
115
127
  return `${leftRendered} ${{
116
128
  eq: "=",
117
129
  neq: "!=",
@@ -125,16 +137,9 @@ function renderBinary(expr, contract) {
125
137
  notIn: "NOT IN"
126
138
  }[expr.op]} ${right}`;
127
139
  }
128
- function renderBinaryRight(right, contract) {
129
- if (right.kind === "col") return renderColumn(right);
130
- if (right.kind === "param") return renderParam(right, contract);
131
- if (right.kind === "literal") return renderLiteral(right);
132
- if (right.kind === "operation") return renderExpr(right, contract);
133
- if (right.kind === "listLiteral") {
134
- if (right.values.length === 0) return "(NULL)";
135
- return `(${right.values.map((value) => value.kind === "param" ? renderParam(value, contract) : renderLiteral(value)).join(", ")})`;
136
- }
137
- throw new Error(`Unsupported binary right expression kind: ${right.kind}`);
140
+ function renderListLiteral(expr, contract, tableName, columnName) {
141
+ if (expr.values.length === 0) return "(NULL)";
142
+ return `(${expr.values.map((v) => v.kind === "param" ? renderParam(v, contract, tableName, columnName) : renderLiteral(v)).join(", ")})`;
138
143
  }
139
144
  function renderColumn(ref) {
140
145
  return `${quoteIdentifier(ref.table)}.${quoteIdentifier(ref.column)}`;
@@ -177,12 +182,12 @@ function renderOperation(expr, contract) {
177
182
  if (expr.lowering.strategy === "function") return result;
178
183
  return result;
179
184
  }
180
- function renderJoin(join, _contract) {
181
- return `${join.joinType.toUpperCase()} JOIN ${quoteIdentifier(join.table.name)} ON ${renderJoinOn(join.on)}`;
185
+ function renderJoin(join, contract) {
186
+ return `${join.joinType.toUpperCase()} JOIN ${quoteIdentifier(join.table.name)} ON ${renderJoinOn(join.on, contract)}`;
182
187
  }
183
- function renderJoinOn(on) {
188
+ function renderJoinOn(on, contract) {
184
189
  if (on.kind === "eqCol") return `${renderColumn(on.left)} = ${renderColumn(on.right)}`;
185
- throw new Error(`Unsupported join ON expression kind: ${on.kind}`);
190
+ return renderWhere(on, contract);
186
191
  }
187
192
  function renderInclude(include, contract) {
188
193
  const alias = include.alias;
@@ -190,7 +195,7 @@ function renderInclude(include, contract) {
190
195
  const expr = renderExpr(item.expr, contract);
191
196
  return `'${item.alias}', ${expr}`;
192
197
  }).join(", ")})`;
193
- let whereClause = ` WHERE ${renderJoinOn(include.child.on)}`;
198
+ let whereClause = ` WHERE ${renderJoinOn(include.child.on, contract)}`;
194
199
  if (include.child.where) whereClause += ` AND ${renderWhere(include.child.where, contract)}`;
195
200
  const childOrderBy = include.child.orderBy?.length ? ` ORDER BY ${include.child.orderBy.map((order) => `${renderExpr(order.expr, contract)} ${order.dir.toUpperCase()}`).join(", ")}` : "";
196
201
  const childLimit = typeof include.child.limit === "number" ? ` LIMIT ${include.child.limit}` : "";
@@ -250,12 +255,12 @@ function renderUpdate(ast, contract) {
250
255
  else throw new Error(`Unsupported value kind in UPDATE: ${val.kind}`);
251
256
  return `${column} = ${value}`;
252
257
  });
253
- const whereClause = ` WHERE ${renderWhere(ast.where, contract)}`;
258
+ const whereClause = ast.where ? ` WHERE ${renderWhere(ast.where, contract)}` : "";
254
259
  const returningClause = ast.returning?.length ? ` RETURNING ${ast.returning.map((col) => `${quoteIdentifier(col.table)}.${quoteIdentifier(col.column)}`).join(", ")}` : "";
255
260
  return `UPDATE ${table} SET ${setClauses.join(", ")}${whereClause}${returningClause}`;
256
261
  }
257
262
  function renderDelete(ast, contract) {
258
- return `DELETE FROM ${quoteIdentifier(ast.table.name)}${` WHERE ${renderWhere(ast.where, contract)}`}${ast.returning?.length ? ` RETURNING ${ast.returning.map((col) => `${quoteIdentifier(col.table)}.${quoteIdentifier(col.column)}`).join(", ")}` : ""}`;
263
+ return `DELETE FROM ${quoteIdentifier(ast.table.name)}${ast.where ? ` WHERE ${renderWhere(ast.where, contract)}` : ""}${ast.returning?.length ? ` RETURNING ${ast.returning.map((col) => `${quoteIdentifier(col.table)}.${quoteIdentifier(col.column)}`).join(", ")}` : ""}`;
259
264
  }
260
265
  function createPostgresAdapter(options) {
261
266
  return Object.freeze(new PostgresAdapterImpl(options));
@@ -263,4 +268,4 @@ function createPostgresAdapter(options) {
263
268
 
264
269
  //#endregion
265
270
  export { createPostgresAdapter as t };
266
- //# sourceMappingURL=adapter-B5uYhMy7.mjs.map
271
+ //# sourceMappingURL=adapter-DtehReRR.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter-DtehReRR.mjs","names":["parameterizedCodecs: ReadonlyArray<CodecParamsDescriptor>","codec","sql: string","right: string","_exhaustive: never","subquery: string","alias","value: string"],"sources":["../src/core/adapter.ts"],"sourcesContent":["import type {\n Adapter,\n AdapterProfile,\n BinaryExpr,\n CodecParamsDescriptor,\n ColumnRef,\n DeleteAst,\n IncludeRef,\n InsertAst,\n JoinAst,\n JoinOnExpr,\n ListLiteralExpr,\n LiteralExpr,\n LowererContext,\n NullCheckExpr,\n OperationExpr,\n ParamRef,\n QueryAst,\n SelectAst,\n UpdateAst,\n WhereExpr,\n} from '@prisma-next/sql-relational-core/ast';\nimport { createCodecRegistry, isOperationExpr } from '@prisma-next/sql-relational-core/ast';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { PG_JSON_CODEC_ID, PG_JSONB_CODEC_ID } from './codec-ids';\nimport { codecDefinitions } from './codecs';\nimport { escapeLiteral } from './sql-utils';\nimport type { PostgresAdapterOptions, PostgresContract, PostgresLoweredStatement } from './types';\n\nconst VECTOR_CODEC_ID = 'pg/vector@1' as const;\n\nfunction getCodecParamCast(codecId: string | undefined): string | undefined {\n if (codecId === VECTOR_CODEC_ID) {\n return 'vector';\n }\n if (codecId === PG_JSON_CODEC_ID) {\n return 'json';\n }\n if (codecId === PG_JSONB_CODEC_ID) {\n return 'jsonb';\n }\n return undefined;\n}\n\nfunction renderTypedParam(index: number, codecId: string | undefined): string {\n const cast = getCodecParamCast(codecId);\n return cast ? `$${index}::${cast}` : `$${index}`;\n}\n\nconst defaultCapabilities = Object.freeze({\n postgres: {\n orderBy: true,\n limit: true,\n lateral: true,\n jsonAgg: true,\n returning: true,\n },\n sql: {\n enums: true,\n },\n});\n\ntype AdapterCodec = (typeof codecDefinitions)[keyof typeof codecDefinitions]['codec'];\ntype ParameterizedCodec = AdapterCodec & {\n readonly paramsSchema: NonNullable<AdapterCodec['paramsSchema']>;\n};\n\nconst parameterizedCodecs: ReadonlyArray<CodecParamsDescriptor> = Object.values(codecDefinitions)\n .map((definition) => definition.codec)\n .filter((codec): codec is ParameterizedCodec => codec.paramsSchema !== undefined)\n .map((codec) =>\n Object.freeze({\n codecId: codec.id,\n paramsSchema: codec.paramsSchema,\n ...ifDefined('init', codec.init),\n }),\n );\n\nclass PostgresAdapterImpl implements Adapter<QueryAst, PostgresContract, PostgresLoweredStatement> {\n // These fields make the adapter instance structurally compatible with\n // RuntimeAdapterInstance<'sql', 'postgres'> without introducing a runtime-plane dependency.\n readonly familyId = 'sql' as const;\n readonly targetId = 'postgres' as const;\n\n readonly profile: AdapterProfile<'postgres'>;\n private readonly codecRegistry = (() => {\n const registry = createCodecRegistry();\n for (const definition of Object.values(codecDefinitions)) {\n registry.register(definition.codec);\n }\n return registry;\n })();\n\n constructor(options?: PostgresAdapterOptions) {\n this.profile = Object.freeze({\n id: options?.profileId ?? 'postgres/default@1',\n target: 'postgres',\n capabilities: defaultCapabilities,\n codecs: () => this.codecRegistry,\n });\n }\n\n parameterizedCodecs(): ReadonlyArray<CodecParamsDescriptor> {\n return parameterizedCodecs;\n }\n\n lower(ast: QueryAst, context: LowererContext<PostgresContract>) {\n let sql: string;\n const params = context.params ? [...context.params] : [];\n\n if (ast.kind === 'select') {\n sql = renderSelect(ast, context.contract);\n } else if (ast.kind === 'insert') {\n sql = renderInsert(ast, context.contract);\n } else if (ast.kind === 'update') {\n sql = renderUpdate(ast, context.contract);\n } else if (ast.kind === 'delete') {\n sql = renderDelete(ast, context.contract);\n } else {\n throw new Error(`Unsupported AST kind: ${(ast as { kind: string }).kind}`);\n }\n\n return Object.freeze({\n profileId: this.profile.id,\n body: Object.freeze({ sql, params }),\n });\n }\n}\n\nfunction renderSelect(ast: SelectAst, contract?: PostgresContract): string {\n const selectClause = `SELECT ${renderProjection(ast, contract)}`;\n const fromClause = `FROM ${quoteIdentifier(ast.from.name)}`;\n\n const joinsClause = ast.joins?.length\n ? ast.joins.map((join) => renderJoin(join, contract)).join(' ')\n : '';\n const includesClause = ast.includes?.length\n ? ast.includes.map((include) => renderInclude(include, contract)).join(' ')\n : '';\n\n const whereClause = ast.where ? ` WHERE ${renderWhere(ast.where, contract)}` : '';\n const orderClause = ast.orderBy?.length\n ? ` ORDER BY ${ast.orderBy\n .map((order) => {\n const expr = renderExpr(order.expr as ColumnRef | OperationExpr, contract);\n return `${expr} ${order.dir.toUpperCase()}`;\n })\n .join(', ')}`\n : '';\n const limitClause = typeof ast.limit === 'number' ? ` LIMIT ${ast.limit}` : '';\n\n const clauses = [joinsClause, includesClause].filter(Boolean).join(' ');\n return `${selectClause} ${fromClause}${clauses ? ` ${clauses}` : ''}${whereClause}${orderClause}${limitClause}`.trim();\n}\n\nfunction renderProjection(ast: SelectAst, contract?: PostgresContract): string {\n return ast.project\n .map((item) => {\n const expr = item.expr as ColumnRef | IncludeRef | OperationExpr | LiteralExpr;\n if (expr.kind === 'includeRef') {\n // For include references, select the column from the LATERAL join alias\n // The LATERAL subquery returns a single column (the JSON array) with the alias\n // The table is aliased as {alias}_lateral, and the column inside is aliased as the include alias\n // We select it using table_alias.column_alias\n const tableAlias = `${expr.alias}_lateral`;\n return `${quoteIdentifier(tableAlias)}.${quoteIdentifier(expr.alias)} AS ${quoteIdentifier(item.alias)}`;\n }\n if (expr.kind === 'operation') {\n const operation = renderOperation(expr, contract);\n const alias = quoteIdentifier(item.alias);\n return `${operation} AS ${alias}`;\n }\n if (expr.kind === 'literal') {\n const literal = renderLiteral(expr);\n const alias = quoteIdentifier(item.alias);\n return `${literal} AS ${alias}`;\n }\n const column = renderColumn(expr as ColumnRef);\n const alias = quoteIdentifier(item.alias);\n return `${column} AS ${alias}`;\n })\n .join(', ');\n}\n\nfunction renderWhere(expr: WhereExpr, contract?: PostgresContract): string {\n if (expr.kind === 'exists') {\n const notKeyword = expr.not ? 'NOT ' : '';\n const subquery = renderSelect(expr.subquery, contract);\n return `${notKeyword}EXISTS (${subquery})`;\n }\n if (expr.kind === 'nullCheck') {\n return renderNullCheck(expr, contract);\n }\n if (expr.kind === 'and') {\n if (expr.exprs.length === 0) {\n return 'TRUE';\n }\n return `(${expr.exprs.map((part) => renderWhere(part, contract)).join(' AND ')})`;\n }\n if (expr.kind === 'or') {\n if (expr.exprs.length === 0) {\n return 'FALSE';\n }\n return `(${expr.exprs.map((part) => renderWhere(part, contract)).join(' OR ')})`;\n }\n return renderBinary(expr, contract);\n}\n\nfunction renderNullCheck(expr: NullCheckExpr, contract?: PostgresContract): string {\n const rendered = renderExpr(expr.expr as ColumnRef | OperationExpr, contract);\n // Only wrap in parentheses if it's an operation expression\n const renderedExpr = isOperationExpr(expr.expr) ? `(${rendered})` : rendered;\n return expr.isNull ? `${renderedExpr} IS NULL` : `${renderedExpr} IS NOT NULL`;\n}\n\nfunction renderBinary(expr: BinaryExpr, contract?: PostgresContract): string {\n if (expr.right.kind === 'listLiteral' && expr.right.values.length === 0) {\n if (expr.op === 'in') {\n return 'FALSE';\n }\n if (expr.op === 'notIn') {\n return 'TRUE';\n }\n }\n\n const leftExpr = expr.left as ColumnRef | OperationExpr;\n const left = renderExpr(leftExpr, contract);\n const leftRendered = isOperationExpr(leftExpr) ? `(${left})` : left;\n const leftCol = leftExpr.kind === 'col' ? leftExpr : undefined;\n\n const rightExpr = expr.right;\n let right: string;\n if (rightExpr.kind === 'listLiteral') {\n right = renderListLiteral(\n rightExpr as ListLiteralExpr,\n contract,\n leftCol?.table,\n leftCol?.column,\n );\n } else if (rightExpr.kind === 'literal') {\n right = renderLiteral(rightExpr);\n } else if (rightExpr.kind === 'col') {\n right = renderColumn(rightExpr);\n } else if (rightExpr.kind === 'param') {\n right = renderParam(rightExpr, contract, leftCol?.table, leftCol?.column);\n } else if (rightExpr.kind === 'operation') {\n right = renderOperation(rightExpr, contract);\n } else {\n right = renderColumn(rightExpr as ColumnRef);\n }\n\n const operatorMap: Record<BinaryExpr['op'], string> = {\n eq: '=',\n neq: '!=',\n gt: '>',\n lt: '<',\n gte: '>=',\n lte: '<=',\n like: 'LIKE',\n ilike: 'ILIKE',\n in: 'IN',\n notIn: 'NOT IN',\n };\n\n return `${leftRendered} ${operatorMap[expr.op]} ${right}`;\n}\n\nfunction renderListLiteral(\n expr: ListLiteralExpr,\n contract?: PostgresContract,\n tableName?: string,\n columnName?: string,\n): string {\n if (expr.values.length === 0) {\n return '(NULL)';\n }\n const values = expr.values\n .map((v) =>\n v.kind === 'param' ? renderParam(v, contract, tableName, columnName) : renderLiteral(v),\n )\n .join(', ');\n return `(${values})`;\n}\n\nfunction renderColumn(ref: ColumnRef): string {\n return `${quoteIdentifier(ref.table)}.${quoteIdentifier(ref.column)}`;\n}\n\nfunction renderExpr(expr: ColumnRef | OperationExpr, contract?: PostgresContract): string {\n if (isOperationExpr(expr)) {\n return renderOperation(expr, contract);\n }\n return renderColumn(expr);\n}\n\nfunction renderParam(\n ref: ParamRef,\n contract?: PostgresContract,\n tableName?: string,\n columnName?: string,\n): string {\n if (contract && tableName && columnName) {\n const tableMeta = contract.storage.tables[tableName];\n const columnMeta = tableMeta?.columns[columnName];\n return renderTypedParam(ref.index, columnMeta?.codecId);\n }\n return `$${ref.index}`;\n}\n\nfunction renderLiteral(expr: LiteralExpr): string {\n if (typeof expr.value === 'string') {\n return `'${escapeLiteral(expr.value)}'`;\n }\n if (typeof expr.value === 'number' || typeof expr.value === 'boolean') {\n return String(expr.value);\n }\n if (expr.value === null) {\n return 'NULL';\n }\n if (Array.isArray(expr.value)) {\n return `ARRAY[${expr.value.map((v: unknown) => renderLiteral({ kind: 'literal', value: v })).join(', ')}]`;\n }\n return JSON.stringify(expr.value);\n}\n\nfunction renderOperation(expr: OperationExpr, contract?: PostgresContract): string {\n const self = renderExpr(expr.self, contract);\n // For vector operations, cast param arguments to vector type\n const isVectorOperation = expr.forTypeId === VECTOR_CODEC_ID;\n const args = expr.args.map((arg: ColumnRef | ParamRef | LiteralExpr | OperationExpr) => {\n if (arg.kind === 'col') {\n return renderColumn(arg);\n }\n if (arg.kind === 'param') {\n // Cast vector operation parameters to vector type\n return isVectorOperation ? `$${arg.index}::vector` : renderParam(arg, contract);\n }\n if (arg.kind === 'literal') {\n return renderLiteral(arg);\n }\n if (arg.kind === 'operation') {\n return renderOperation(arg, contract);\n }\n const _exhaustive: never = arg;\n throw new Error(`Unsupported argument kind: ${(_exhaustive as { kind: string }).kind}`);\n });\n\n let result = expr.lowering.template;\n result = result.replace(/\\$\\{self\\}/g, self);\n for (let i = 0; i < args.length; i++) {\n result = result.replace(new RegExp(`\\\\$\\\\{arg${i}\\\\}`, 'g'), args[i] ?? '');\n }\n\n if (expr.lowering.strategy === 'function') {\n return result;\n }\n\n return result;\n}\n\nfunction renderJoin(join: JoinAst, contract?: PostgresContract): string {\n const joinType = join.joinType.toUpperCase();\n const table = quoteIdentifier(join.table.name);\n const onClause = renderJoinOn(join.on, contract);\n return `${joinType} JOIN ${table} ON ${onClause}`;\n}\n\nfunction renderJoinOn(on: JoinOnExpr, contract?: PostgresContract): string {\n if (on.kind === 'eqCol') {\n const left = renderColumn(on.left);\n const right = renderColumn(on.right);\n return `${left} = ${right}`;\n }\n return renderWhere(on, contract);\n}\n\nfunction renderInclude(\n include: NonNullable<SelectAst['includes']>[number],\n contract?: PostgresContract,\n): string {\n const alias = include.alias;\n\n // Build the lateral subquery\n const childProjection = include.child.project\n .map((item: { alias: string; expr: ColumnRef | OperationExpr }) => {\n const expr = renderExpr(item.expr, contract);\n return `'${item.alias}', ${expr}`;\n })\n .join(', ');\n\n const jsonBuildObject = `json_build_object(${childProjection})`;\n\n // Build the ON condition from the include's ON clause - this goes in the WHERE clause\n const onCondition = renderJoinOn(include.child.on, contract);\n\n // Build WHERE clause: combine ON condition with any additional WHERE clauses\n let whereClause = ` WHERE ${onCondition}`;\n if (include.child.where) {\n whereClause += ` AND ${renderWhere(include.child.where, contract)}`;\n }\n\n // Add ORDER BY if present - it goes inside json_agg() call\n const childOrderBy = include.child.orderBy?.length\n ? ` ORDER BY ${include.child.orderBy\n .map(\n (order: { expr: ColumnRef | OperationExpr; dir: string }) =>\n `${renderExpr(order.expr, contract)} ${order.dir.toUpperCase()}`,\n )\n .join(', ')}`\n : '';\n\n // Add LIMIT if present\n const childLimit = typeof include.child.limit === 'number' ? ` LIMIT ${include.child.limit}` : '';\n\n // Build the lateral subquery\n // When ORDER BY is present without LIMIT, it goes inside json_agg() call: json_agg(expr ORDER BY ...)\n // When LIMIT is present (with or without ORDER BY), we need to wrap in a subquery\n const childTable = quoteIdentifier(include.child.table.name);\n let subquery: string;\n if (typeof include.child.limit === 'number') {\n // With LIMIT, we need to wrap in a subquery\n // Select individual columns in inner query, then aggregate\n // Create a map of column references to their aliases for ORDER BY\n // Only ColumnRef can be mapped (OperationExpr doesn't have table/column properties)\n const columnAliasMap = new Map<string, string>();\n for (const item of include.child.project) {\n if (item.expr.kind === 'col') {\n const columnKey = `${item.expr.table}.${item.expr.column}`;\n columnAliasMap.set(columnKey, item.alias);\n }\n }\n\n const innerColumns = include.child.project\n .map((item: { alias: string; expr: ColumnRef | OperationExpr }) => {\n const expr = renderExpr(item.expr, contract);\n return `${expr} AS ${quoteIdentifier(item.alias)}`;\n })\n .join(', ');\n\n // For ORDER BY, use column aliases if the column is in the SELECT list\n const childOrderByWithAliases = include.child.orderBy?.length\n ? ` ORDER BY ${include.child.orderBy\n .map((order: { expr: ColumnRef | OperationExpr; dir: string }) => {\n if (order.expr.kind === 'col') {\n const columnKey = `${order.expr.table}.${order.expr.column}`;\n const alias = columnAliasMap.get(columnKey);\n if (alias) {\n return `${quoteIdentifier(alias)} ${order.dir.toUpperCase()}`;\n }\n }\n return `${renderExpr(order.expr, contract)} ${order.dir.toUpperCase()}`;\n })\n .join(', ')}`\n : '';\n\n const innerSelect = `SELECT ${innerColumns} FROM ${childTable}${whereClause}${childOrderByWithAliases}${childLimit}`;\n subquery = `(SELECT json_agg(row_to_json(sub.*)) AS ${quoteIdentifier(alias)} FROM (${innerSelect}) sub)`;\n } else if (childOrderBy) {\n // With ORDER BY but no LIMIT, ORDER BY goes inside json_agg()\n subquery = `(SELECT json_agg(${jsonBuildObject}${childOrderBy}) AS ${quoteIdentifier(alias)} FROM ${childTable}${whereClause})`;\n } else {\n // No ORDER BY or LIMIT\n subquery = `(SELECT json_agg(${jsonBuildObject}) AS ${quoteIdentifier(alias)} FROM ${childTable}${whereClause})`;\n }\n\n // Return the LATERAL join with ON true (the condition is in the WHERE clause)\n // The subquery returns a single column (the JSON array) with the alias\n // We use a different alias for the table to avoid ambiguity when selecting the column\n const tableAlias = `${alias}_lateral`;\n return `LEFT JOIN LATERAL ${subquery} AS ${quoteIdentifier(tableAlias)} ON true`;\n}\n\nfunction quoteIdentifier(identifier: string): string {\n return `\"${identifier.replace(/\"/g, '\"\"')}\"`;\n}\n\nfunction renderInsert(ast: InsertAst, contract: PostgresContract): string {\n const table = quoteIdentifier(ast.table.name);\n const columns = Object.keys(ast.values).map((col) => quoteIdentifier(col));\n const tableMeta = contract.storage.tables[ast.table.name];\n const values = Object.entries(ast.values).map(([colName, val]) => {\n if (val.kind === 'param') {\n const columnMeta = tableMeta?.columns[colName];\n return renderTypedParam(val.index, columnMeta?.codecId);\n }\n if (val.kind === 'col') {\n return `${quoteIdentifier(val.table)}.${quoteIdentifier(val.column)}`;\n }\n throw new Error(`Unsupported value kind in INSERT: ${(val as { kind: string }).kind}`);\n });\n\n const insertClause =\n columns.length === 0\n ? `INSERT INTO ${table} DEFAULT VALUES`\n : `INSERT INTO ${table} (${columns.join(', ')}) VALUES (${values.join(', ')})`;\n const returningClause = ast.returning?.length\n ? ` RETURNING ${ast.returning.map((col) => `${quoteIdentifier(col.table)}.${quoteIdentifier(col.column)}`).join(', ')}`\n : '';\n\n return `${insertClause}${returningClause}`;\n}\n\nfunction renderUpdate(ast: UpdateAst, contract: PostgresContract): string {\n const table = quoteIdentifier(ast.table.name);\n const tableMeta = contract.storage.tables[ast.table.name];\n const setClauses = Object.entries(ast.set).map(([col, val]) => {\n const column = quoteIdentifier(col);\n let value: string;\n if (val.kind === 'param') {\n const columnMeta = tableMeta?.columns[col];\n value = renderTypedParam(val.index, columnMeta?.codecId);\n } else if (val.kind === 'col') {\n value = `${quoteIdentifier(val.table)}.${quoteIdentifier(val.column)}`;\n } else {\n throw new Error(`Unsupported value kind in UPDATE: ${(val as { kind: string }).kind}`);\n }\n return `${column} = ${value}`;\n });\n\n const whereClause = ast.where ? ` WHERE ${renderWhere(ast.where, contract)}` : '';\n const returningClause = ast.returning?.length\n ? ` RETURNING ${ast.returning.map((col) => `${quoteIdentifier(col.table)}.${quoteIdentifier(col.column)}`).join(', ')}`\n : '';\n\n return `UPDATE ${table} SET ${setClauses.join(', ')}${whereClause}${returningClause}`;\n}\n\nfunction renderDelete(ast: DeleteAst, contract?: PostgresContract): string {\n const table = quoteIdentifier(ast.table.name);\n const whereClause = ast.where ? ` WHERE ${renderWhere(ast.where, contract)}` : '';\n const returningClause = ast.returning?.length\n ? ` RETURNING ${ast.returning.map((col) => `${quoteIdentifier(col.table)}.${quoteIdentifier(col.column)}`).join(', ')}`\n : '';\n\n return `DELETE FROM ${table}${whereClause}${returningClause}`;\n}\n\nexport function createPostgresAdapter(options?: PostgresAdapterOptions) {\n return Object.freeze(new PostgresAdapterImpl(options));\n}\n"],"mappings":";;;;;;;AA6BA,MAAM,kBAAkB;AAExB,SAAS,kBAAkB,SAAiD;AAC1E,KAAI,YAAY,gBACd,QAAO;AAET,KAAI,YAAY,iBACd,QAAO;AAET,KAAI,YAAY,kBACd,QAAO;;AAKX,SAAS,iBAAiB,OAAe,SAAqC;CAC5E,MAAM,OAAO,kBAAkB,QAAQ;AACvC,QAAO,OAAO,IAAI,MAAM,IAAI,SAAS,IAAI;;AAG3C,MAAM,sBAAsB,OAAO,OAAO;CACxC,UAAU;EACR,SAAS;EACT,OAAO;EACP,SAAS;EACT,SAAS;EACT,WAAW;EACZ;CACD,KAAK,EACH,OAAO,MACR;CACF,CAAC;AAOF,MAAMA,sBAA4D,OAAO,OAAO,iBAAiB,CAC9F,KAAK,eAAe,WAAW,MAAM,CACrC,QAAQ,YAAuCC,QAAM,iBAAiB,OAAU,CAChF,KAAK,YACJ,OAAO,OAAO;CACZ,SAASA,QAAM;CACf,cAAcA,QAAM;CACpB,GAAG,UAAU,QAAQA,QAAM,KAAK;CACjC,CAAC,CACH;AAEH,IAAM,sBAAN,MAAmG;CAGjG,AAAS,WAAW;CACpB,AAAS,WAAW;CAEpB,AAAS;CACT,AAAiB,uBAAuB;EACtC,MAAM,WAAW,qBAAqB;AACtC,OAAK,MAAM,cAAc,OAAO,OAAO,iBAAiB,CACtD,UAAS,SAAS,WAAW,MAAM;AAErC,SAAO;KACL;CAEJ,YAAY,SAAkC;AAC5C,OAAK,UAAU,OAAO,OAAO;GAC3B,IAAI,SAAS,aAAa;GAC1B,QAAQ;GACR,cAAc;GACd,cAAc,KAAK;GACpB,CAAC;;CAGJ,sBAA4D;AAC1D,SAAO;;CAGT,MAAM,KAAe,SAA2C;EAC9D,IAAIC;EACJ,MAAM,SAAS,QAAQ,SAAS,CAAC,GAAG,QAAQ,OAAO,GAAG,EAAE;AAExD,MAAI,IAAI,SAAS,SACf,OAAM,aAAa,KAAK,QAAQ,SAAS;WAChC,IAAI,SAAS,SACtB,OAAM,aAAa,KAAK,QAAQ,SAAS;WAChC,IAAI,SAAS,SACtB,OAAM,aAAa,KAAK,QAAQ,SAAS;WAChC,IAAI,SAAS,SACtB,OAAM,aAAa,KAAK,QAAQ,SAAS;MAEzC,OAAM,IAAI,MAAM,yBAA0B,IAAyB,OAAO;AAG5E,SAAO,OAAO,OAAO;GACnB,WAAW,KAAK,QAAQ;GACxB,MAAM,OAAO,OAAO;IAAE;IAAK;IAAQ,CAAC;GACrC,CAAC;;;AAIN,SAAS,aAAa,KAAgB,UAAqC;CACzE,MAAM,eAAe,UAAU,iBAAiB,KAAK,SAAS;CAC9D,MAAM,aAAa,QAAQ,gBAAgB,IAAI,KAAK,KAAK;CAEzD,MAAM,cAAc,IAAI,OAAO,SAC3B,IAAI,MAAM,KAAK,SAAS,WAAW,MAAM,SAAS,CAAC,CAAC,KAAK,IAAI,GAC7D;CACJ,MAAM,iBAAiB,IAAI,UAAU,SACjC,IAAI,SAAS,KAAK,YAAY,cAAc,SAAS,SAAS,CAAC,CAAC,KAAK,IAAI,GACzE;CAEJ,MAAM,cAAc,IAAI,QAAQ,UAAU,YAAY,IAAI,OAAO,SAAS,KAAK;CAC/E,MAAM,cAAc,IAAI,SAAS,SAC7B,aAAa,IAAI,QACd,KAAK,UAAU;AAEd,SAAO,GADM,WAAW,MAAM,MAAmC,SAAS,CAC3D,GAAG,MAAM,IAAI,aAAa;GACzC,CACD,KAAK,KAAK,KACb;CACJ,MAAM,cAAc,OAAO,IAAI,UAAU,WAAW,UAAU,IAAI,UAAU;CAE5E,MAAM,UAAU,CAAC,aAAa,eAAe,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI;AACvE,QAAO,GAAG,aAAa,GAAG,aAAa,UAAU,IAAI,YAAY,KAAK,cAAc,cAAc,cAAc,MAAM;;AAGxH,SAAS,iBAAiB,KAAgB,UAAqC;AAC7E,QAAO,IAAI,QACR,KAAK,SAAS;EACb,MAAM,OAAO,KAAK;AAClB,MAAI,KAAK,SAAS,aAMhB,QAAO,GAAG,gBADS,GAAG,KAAK,MAAM,UACI,CAAC,GAAG,gBAAgB,KAAK,MAAM,CAAC,MAAM,gBAAgB,KAAK,MAAM;AAExG,MAAI,KAAK,SAAS,YAGhB,QAAO,GAFW,gBAAgB,MAAM,SAAS,CAE7B,MADN,gBAAgB,KAAK,MAAM;AAG3C,MAAI,KAAK,SAAS,UAGhB,QAAO,GAFS,cAAc,KAAK,CAEjB,MADJ,gBAAgB,KAAK,MAAM;AAK3C,SAAO,GAFQ,aAAa,KAAkB,CAE7B,MADH,gBAAgB,KAAK,MAAM;GAEzC,CACD,KAAK,KAAK;;AAGf,SAAS,YAAY,MAAiB,UAAqC;AACzE,KAAI,KAAK,SAAS,SAGhB,QAAO,GAFY,KAAK,MAAM,SAAS,GAElB,UADJ,aAAa,KAAK,UAAU,SAAS,CACd;AAE1C,KAAI,KAAK,SAAS,YAChB,QAAO,gBAAgB,MAAM,SAAS;AAExC,KAAI,KAAK,SAAS,OAAO;AACvB,MAAI,KAAK,MAAM,WAAW,EACxB,QAAO;AAET,SAAO,IAAI,KAAK,MAAM,KAAK,SAAS,YAAY,MAAM,SAAS,CAAC,CAAC,KAAK,QAAQ,CAAC;;AAEjF,KAAI,KAAK,SAAS,MAAM;AACtB,MAAI,KAAK,MAAM,WAAW,EACxB,QAAO;AAET,SAAO,IAAI,KAAK,MAAM,KAAK,SAAS,YAAY,MAAM,SAAS,CAAC,CAAC,KAAK,OAAO,CAAC;;AAEhF,QAAO,aAAa,MAAM,SAAS;;AAGrC,SAAS,gBAAgB,MAAqB,UAAqC;CACjF,MAAM,WAAW,WAAW,KAAK,MAAmC,SAAS;CAE7E,MAAM,eAAe,gBAAgB,KAAK,KAAK,GAAG,IAAI,SAAS,KAAK;AACpE,QAAO,KAAK,SAAS,GAAG,aAAa,YAAY,GAAG,aAAa;;AAGnE,SAAS,aAAa,MAAkB,UAAqC;AAC3E,KAAI,KAAK,MAAM,SAAS,iBAAiB,KAAK,MAAM,OAAO,WAAW,GAAG;AACvE,MAAI,KAAK,OAAO,KACd,QAAO;AAET,MAAI,KAAK,OAAO,QACd,QAAO;;CAIX,MAAM,WAAW,KAAK;CACtB,MAAM,OAAO,WAAW,UAAU,SAAS;CAC3C,MAAM,eAAe,gBAAgB,SAAS,GAAG,IAAI,KAAK,KAAK;CAC/D,MAAM,UAAU,SAAS,SAAS,QAAQ,WAAW;CAErD,MAAM,YAAY,KAAK;CACvB,IAAIC;AACJ,KAAI,UAAU,SAAS,cACrB,SAAQ,kBACN,WACA,UACA,SAAS,OACT,SAAS,OACV;UACQ,UAAU,SAAS,UAC5B,SAAQ,cAAc,UAAU;UACvB,UAAU,SAAS,MAC5B,SAAQ,aAAa,UAAU;UACtB,UAAU,SAAS,QAC5B,SAAQ,YAAY,WAAW,UAAU,SAAS,OAAO,SAAS,OAAO;UAChE,UAAU,SAAS,YAC5B,SAAQ,gBAAgB,WAAW,SAAS;KAE5C,SAAQ,aAAa,UAAuB;AAgB9C,QAAO,GAAG,aAAa,GAb+B;EACpD,IAAI;EACJ,KAAK;EACL,IAAI;EACJ,IAAI;EACJ,KAAK;EACL,KAAK;EACL,MAAM;EACN,OAAO;EACP,IAAI;EACJ,OAAO;EACR,CAEqC,KAAK,IAAI,GAAG;;AAGpD,SAAS,kBACP,MACA,UACA,WACA,YACQ;AACR,KAAI,KAAK,OAAO,WAAW,EACzB,QAAO;AAOT,QAAO,IALQ,KAAK,OACjB,KAAK,MACJ,EAAE,SAAS,UAAU,YAAY,GAAG,UAAU,WAAW,WAAW,GAAG,cAAc,EAAE,CACxF,CACA,KAAK,KAAK,CACK;;AAGpB,SAAS,aAAa,KAAwB;AAC5C,QAAO,GAAG,gBAAgB,IAAI,MAAM,CAAC,GAAG,gBAAgB,IAAI,OAAO;;AAGrE,SAAS,WAAW,MAAiC,UAAqC;AACxF,KAAI,gBAAgB,KAAK,CACvB,QAAO,gBAAgB,MAAM,SAAS;AAExC,QAAO,aAAa,KAAK;;AAG3B,SAAS,YACP,KACA,UACA,WACA,YACQ;AACR,KAAI,YAAY,aAAa,YAAY;EAEvC,MAAM,aADY,SAAS,QAAQ,OAAO,YACZ,QAAQ;AACtC,SAAO,iBAAiB,IAAI,OAAO,YAAY,QAAQ;;AAEzD,QAAO,IAAI,IAAI;;AAGjB,SAAS,cAAc,MAA2B;AAChD,KAAI,OAAO,KAAK,UAAU,SACxB,QAAO,IAAI,cAAc,KAAK,MAAM,CAAC;AAEvC,KAAI,OAAO,KAAK,UAAU,YAAY,OAAO,KAAK,UAAU,UAC1D,QAAO,OAAO,KAAK,MAAM;AAE3B,KAAI,KAAK,UAAU,KACjB,QAAO;AAET,KAAI,MAAM,QAAQ,KAAK,MAAM,CAC3B,QAAO,SAAS,KAAK,MAAM,KAAK,MAAe,cAAc;EAAE,MAAM;EAAW,OAAO;EAAG,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC;AAE1G,QAAO,KAAK,UAAU,KAAK,MAAM;;AAGnC,SAAS,gBAAgB,MAAqB,UAAqC;CACjF,MAAM,OAAO,WAAW,KAAK,MAAM,SAAS;CAE5C,MAAM,oBAAoB,KAAK,cAAc;CAC7C,MAAM,OAAO,KAAK,KAAK,KAAK,QAA4D;AACtF,MAAI,IAAI,SAAS,MACf,QAAO,aAAa,IAAI;AAE1B,MAAI,IAAI,SAAS,QAEf,QAAO,oBAAoB,IAAI,IAAI,MAAM,YAAY,YAAY,KAAK,SAAS;AAEjF,MAAI,IAAI,SAAS,UACf,QAAO,cAAc,IAAI;AAE3B,MAAI,IAAI,SAAS,YACf,QAAO,gBAAgB,KAAK,SAAS;EAEvC,MAAMC,cAAqB;AAC3B,QAAM,IAAI,MAAM,8BAA+B,YAAiC,OAAO;GACvF;CAEF,IAAI,SAAS,KAAK,SAAS;AAC3B,UAAS,OAAO,QAAQ,eAAe,KAAK;AAC5C,MAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,IAC/B,UAAS,OAAO,QAAQ,IAAI,OAAO,YAAY,EAAE,MAAM,IAAI,EAAE,KAAK,MAAM,GAAG;AAG7E,KAAI,KAAK,SAAS,aAAa,WAC7B,QAAO;AAGT,QAAO;;AAGT,SAAS,WAAW,MAAe,UAAqC;AAItE,QAAO,GAHU,KAAK,SAAS,aAAa,CAGzB,QAFL,gBAAgB,KAAK,MAAM,KAAK,CAEb,MADhB,aAAa,KAAK,IAAI,SAAS;;AAIlD,SAAS,aAAa,IAAgB,UAAqC;AACzE,KAAI,GAAG,SAAS,QAGd,QAAO,GAFM,aAAa,GAAG,KAAK,CAEnB,KADD,aAAa,GAAG,MAAM;AAGtC,QAAO,YAAY,IAAI,SAAS;;AAGlC,SAAS,cACP,SACA,UACQ;CACR,MAAM,QAAQ,QAAQ;CAUtB,MAAM,kBAAkB,qBAPA,QAAQ,MAAM,QACnC,KAAK,SAA6D;EACjE,MAAM,OAAO,WAAW,KAAK,MAAM,SAAS;AAC5C,SAAO,IAAI,KAAK,MAAM,KAAK;GAC3B,CACD,KAAK,KAAK,CAEgD;CAM7D,IAAI,cAAc,UAHE,aAAa,QAAQ,MAAM,IAAI,SAAS;AAI5D,KAAI,QAAQ,MAAM,MAChB,gBAAe,QAAQ,YAAY,QAAQ,MAAM,OAAO,SAAS;CAInE,MAAM,eAAe,QAAQ,MAAM,SAAS,SACxC,aAAa,QAAQ,MAAM,QACxB,KACE,UACC,GAAG,WAAW,MAAM,MAAM,SAAS,CAAC,GAAG,MAAM,IAAI,aAAa,GACjE,CACA,KAAK,KAAK,KACb;CAGJ,MAAM,aAAa,OAAO,QAAQ,MAAM,UAAU,WAAW,UAAU,QAAQ,MAAM,UAAU;CAK/F,MAAM,aAAa,gBAAgB,QAAQ,MAAM,MAAM,KAAK;CAC5D,IAAIC;AACJ,KAAI,OAAO,QAAQ,MAAM,UAAU,UAAU;EAK3C,MAAM,iCAAiB,IAAI,KAAqB;AAChD,OAAK,MAAM,QAAQ,QAAQ,MAAM,QAC/B,KAAI,KAAK,KAAK,SAAS,OAAO;GAC5B,MAAM,YAAY,GAAG,KAAK,KAAK,MAAM,GAAG,KAAK,KAAK;AAClD,kBAAe,IAAI,WAAW,KAAK,MAAM;;EAI7C,MAAM,eAAe,QAAQ,MAAM,QAChC,KAAK,SAA6D;AAEjE,UAAO,GADM,WAAW,KAAK,MAAM,SAAS,CAC7B,MAAM,gBAAgB,KAAK,MAAM;IAChD,CACD,KAAK,KAAK;EAGb,MAAM,0BAA0B,QAAQ,MAAM,SAAS,SACnD,aAAa,QAAQ,MAAM,QACxB,KAAK,UAA4D;AAChE,OAAI,MAAM,KAAK,SAAS,OAAO;IAC7B,MAAM,YAAY,GAAG,MAAM,KAAK,MAAM,GAAG,MAAM,KAAK;IACpD,MAAMC,UAAQ,eAAe,IAAI,UAAU;AAC3C,QAAIA,QACF,QAAO,GAAG,gBAAgBA,QAAM,CAAC,GAAG,MAAM,IAAI,aAAa;;AAG/D,UAAO,GAAG,WAAW,MAAM,MAAM,SAAS,CAAC,GAAG,MAAM,IAAI,aAAa;IACrE,CACD,KAAK,KAAK,KACb;EAEJ,MAAM,cAAc,UAAU,aAAa,QAAQ,aAAa,cAAc,0BAA0B;AACxG,aAAW,2CAA2C,gBAAgB,MAAM,CAAC,SAAS,YAAY;YACzF,aAET,YAAW,oBAAoB,kBAAkB,aAAa,OAAO,gBAAgB,MAAM,CAAC,QAAQ,aAAa,YAAY;KAG7H,YAAW,oBAAoB,gBAAgB,OAAO,gBAAgB,MAAM,CAAC,QAAQ,aAAa,YAAY;CAMhH,MAAM,aAAa,GAAG,MAAM;AAC5B,QAAO,qBAAqB,SAAS,MAAM,gBAAgB,WAAW,CAAC;;AAGzE,SAAS,gBAAgB,YAA4B;AACnD,QAAO,IAAI,WAAW,QAAQ,MAAM,OAAK,CAAC;;AAG5C,SAAS,aAAa,KAAgB,UAAoC;CACxE,MAAM,QAAQ,gBAAgB,IAAI,MAAM,KAAK;CAC7C,MAAM,UAAU,OAAO,KAAK,IAAI,OAAO,CAAC,KAAK,QAAQ,gBAAgB,IAAI,CAAC;CAC1E,MAAM,YAAY,SAAS,QAAQ,OAAO,IAAI,MAAM;CACpD,MAAM,SAAS,OAAO,QAAQ,IAAI,OAAO,CAAC,KAAK,CAAC,SAAS,SAAS;AAChE,MAAI,IAAI,SAAS,SAAS;GACxB,MAAM,aAAa,WAAW,QAAQ;AACtC,UAAO,iBAAiB,IAAI,OAAO,YAAY,QAAQ;;AAEzD,MAAI,IAAI,SAAS,MACf,QAAO,GAAG,gBAAgB,IAAI,MAAM,CAAC,GAAG,gBAAgB,IAAI,OAAO;AAErE,QAAM,IAAI,MAAM,qCAAsC,IAAyB,OAAO;GACtF;AAUF,QAAO,GAPL,QAAQ,WAAW,IACf,eAAe,MAAM,mBACrB,eAAe,MAAM,IAAI,QAAQ,KAAK,KAAK,CAAC,YAAY,OAAO,KAAK,KAAK,CAAC,KACxD,IAAI,WAAW,SACnC,cAAc,IAAI,UAAU,KAAK,QAAQ,GAAG,gBAAgB,IAAI,MAAM,CAAC,GAAG,gBAAgB,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,KACnH;;AAKN,SAAS,aAAa,KAAgB,UAAoC;CACxE,MAAM,QAAQ,gBAAgB,IAAI,MAAM,KAAK;CAC7C,MAAM,YAAY,SAAS,QAAQ,OAAO,IAAI,MAAM;CACpD,MAAM,aAAa,OAAO,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,SAAS;EAC7D,MAAM,SAAS,gBAAgB,IAAI;EACnC,IAAIC;AACJ,MAAI,IAAI,SAAS,SAAS;GACxB,MAAM,aAAa,WAAW,QAAQ;AACtC,WAAQ,iBAAiB,IAAI,OAAO,YAAY,QAAQ;aAC/C,IAAI,SAAS,MACtB,SAAQ,GAAG,gBAAgB,IAAI,MAAM,CAAC,GAAG,gBAAgB,IAAI,OAAO;MAEpE,OAAM,IAAI,MAAM,qCAAsC,IAAyB,OAAO;AAExF,SAAO,GAAG,OAAO,KAAK;GACtB;CAEF,MAAM,cAAc,IAAI,QAAQ,UAAU,YAAY,IAAI,OAAO,SAAS,KAAK;CAC/E,MAAM,kBAAkB,IAAI,WAAW,SACnC,cAAc,IAAI,UAAU,KAAK,QAAQ,GAAG,gBAAgB,IAAI,MAAM,CAAC,GAAG,gBAAgB,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,KACnH;AAEJ,QAAO,UAAU,MAAM,OAAO,WAAW,KAAK,KAAK,GAAG,cAAc;;AAGtE,SAAS,aAAa,KAAgB,UAAqC;AAOzE,QAAO,eANO,gBAAgB,IAAI,MAAM,KAAK,GACzB,IAAI,QAAQ,UAAU,YAAY,IAAI,OAAO,SAAS,KAAK,KACvD,IAAI,WAAW,SACnC,cAAc,IAAI,UAAU,KAAK,QAAQ,GAAG,gBAAgB,IAAI,MAAM,CAAC,GAAG,gBAAgB,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,KACnH;;AAKN,SAAgB,sBAAsB,SAAkC;AACtE,QAAO,OAAO,OAAO,IAAI,oBAAoB,QAAQ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.d.mts","names":[],"sources":["../src/core/adapter.ts"],"sourcesContent":[],"mappings":";;;;cA4EM,mBAAA,YAA+B,QAAQ,UAAU,kBAAkB;;EAAnE,SAAA,QAAA,EAAA,UAAoB;EAAmB,SAAA,OAAA,EAMzB,cANyB,CAAA,UAAA,CAAA;EAAU,iBAAA,aAAA;EAAkB,WAAA,CAAA,OAAA,CAAA,EAejD,sBAfiD;EAMrD,mBAAA,CAAA,CAAA,EAkBK,aAlBL,CAkBmB,qBAlBnB,CAAA;EASI,KAAA,CAAA,GAAA,EAaX,QAbW,EAAA,OAAA,EAaQ,cAbR,CAauB,gBAbvB,CAAA,CAAA,EAawC,QAbxC,CAAA;IASe,SAAA,EAAA,MAAA;IAAd,IAAA,UAAA,CAAA;MAIZ,GAAA,EAAA,MAAA;MAAkC,MAAA,EAAA,OAAA,EAAA;IAAf,CAAA,CAAA;;;AA5BK,iBAsbrB,qBAAA,CAtbqB,OAAA,CAAA,EAsbW,sBAtbX,CAAA,EAsbiC,QAtbjC,CAsbiC,mBAtbjC,CAAA"}
1
+ {"version":3,"file":"adapter.d.mts","names":[],"sources":["../src/core/adapter.ts"],"sourcesContent":[],"mappings":";;;;cA8EM,mBAAA,YAA+B,QAAQ,UAAU,kBAAkB;;EAAnE,SAAA,QAAA,EAAA,UAAoB;EAAmB,SAAA,OAAA,EAMzB,cANyB,CAAA,UAAA,CAAA;EAAU,iBAAA,aAAA;EAAkB,WAAA,CAAA,OAAA,CAAA,EAejD,sBAfiD;EAMrD,mBAAA,CAAA,CAAA,EAkBK,aAlBL,CAkBmB,qBAlBnB,CAAA;EASI,KAAA,CAAA,GAAA,EAaX,QAbW,EAAA,OAAA,EAaQ,cAbR,CAauB,gBAbvB,CAAA,CAAA,EAawC,QAbxC,CAAA;IASe,SAAA,EAAA,MAAA;IAAd,IAAA,UAAA,CAAA;MAIZ,GAAA,EAAA,MAAA;MAAkC,MAAA,EAAA,OAAA,EAAA;IAAf,CAAA,CAAA;;;AA5BK,iBA2crB,qBAAA,CA3cqB,OAAA,CAAA,EA2cW,sBA3cX,CAAA,EA2ciC,QA3cjC,CA2ciC,mBA3cjC,CAAA"}
package/dist/adapter.mjs CHANGED
@@ -1,5 +1,3 @@
1
- import "./codec-ids-Bsm9c7ns.mjs";
2
- import "./codecs-BfC_5c-4.mjs";
3
- import { t as createPostgresAdapter } from "./adapter-B5uYhMy7.mjs";
1
+ import { t as createPostgresAdapter } from "./adapter-DtehReRR.mjs";
4
2
 
5
3
  export { createPostgresAdapter };
@@ -1,4 +1,3 @@
1
- import "./codec-ids-Bsm9c7ns.mjs";
2
1
  import { n as dataTypes } from "./codecs-BfC_5c-4.mjs";
3
2
 
4
3
  export { dataTypes };
@@ -1 +1 @@
1
- {"version":3,"file":"control.d.mts","names":[],"sources":["../src/core/default-normalizer.ts","../src/core/parameterized-types.ts","../src/core/sql-utils.ts","../src/core/control-adapter.ts","../src/exports/control.ts"],"sourcesContent":[],"mappings":";;;;;;;;AA0BA;;;;ACEA;AAiDA;;;iBDnDgB,oBAAA,4CAGb;;;;;;;AAHH;;;;ACEA;AAiDA;;;UAjDiB,qBAAA;ECjBJ,SAAA,UAAe,EAAA,MAAA;EA0BZ,SAAA,OAAA,CAAA,EAAe,MAAA;EAiCf,SAAA,UAAa,CAAA,EDvCL,MCuCK,CAAA,MAAA,EAAA,OAAA,CAAA;AAc7B;;;;ACsWA;;;;ACpbgG;;;;;;;iBHuEhF,6BAAA,QAAqC;;;;;;;ADnDrD;;;;ACEA;AAiDA;cClEa,cAAA,SAAuB,KAAA;;;EAAvB,WAAA,CAAA,OAAe,EAAA,MAAA,EAAQ,KAAA,EAAK,MAAA,EAAA,IAAA,EAAA,YAAA,GAAA,SAAA;AA0BzC;AAiCA;AAcA;;;;ACsWA;;;;ACpbgG;iBF+BhF,eAAA;;;;;;;;;;;;iBAiCA,aAAA;;;;iBAcA,WAAA;;;;;;;;;;iBCsWA,yBAAA;;;AHhahB,cIlBM,yBJqBH,EIrB8B,2BJqBjB,CAAA,UAAA,CAAA"}
1
+ {"version":3,"file":"control.d.mts","names":[],"sources":["../src/core/default-normalizer.ts","../src/core/parameterized-types.ts","../src/core/sql-utils.ts","../src/core/control-adapter.ts","../src/exports/control.ts"],"sourcesContent":[],"mappings":";;;;;;;;AA0BA;;;;ACEA;AAiDA;;;iBDnDgB,oBAAA,4CAGb;;;;;;;AAHH;;;;ACEA;AAiDA;;;UAjDiB,qBAAA;ECjBJ,SAAA,UAAe,EAAA,MAAA;EA0BZ,SAAA,OAAA,CAAA,EAAe,MAAA;EAiCf,SAAA,UAAa,CAAA,EDvCL,MCuCK,CAAA,MAAA,EAAA,OAAA,CAAA;AAc7B;;;;ACqYA;;;;ACndgG;;;;;;;iBHuEhF,6BAAA,QAAqC;;;;;;;ADnDrD;;;;ACEA;AAiDA;cClEa,cAAA,SAAuB,KAAA;;;EAAvB,WAAA,CAAA,OAAe,EAAA,MAAA,EAAQ,KAAA,EAAK,MAAA,EAAA,IAAA,EAAA,YAAA,GAAA,SAAA;AA0BzC;AAiCA;AAcA;;;;ACqYA;;;;ACndgG;iBF+BhF,eAAA;;;;;;;;;;;;iBAiCA,aAAA;;;;iBAcA,WAAA;;;;;;;;;;iBCqYA,yBAAA;;;AH/bhB,cIlBM,yBJqBH,EIrB8B,2BJqBjB,CAAA,UAAA,CAAA"}
package/dist/control.mjs CHANGED
@@ -1,4 +1,3 @@
1
- import "./codec-ids-Bsm9c7ns.mjs";
2
1
  import { i as quoteIdentifier, n as escapeLiteral, r as qualifyName, t as SqlEscapeError } from "./sql-utils-CSfAGEwF.mjs";
3
2
  import { n as expandParameterizedNativeType, r as pgEnumControlHooks, t as postgresAdapterDescriptorMeta } from "./descriptor-meta-ilnFI7bx.mjs";
4
3
  import { ifDefined } from "@prisma-next/utils/defined";
@@ -175,17 +174,31 @@ var PostgresControlAdapter = class {
175
174
  tc.constraint_name,
176
175
  kcu.column_name,
177
176
  kcu.ordinal_position,
178
- ccu.table_schema AS referenced_table_schema,
179
- ccu.table_name AS referenced_table_name,
180
- ccu.column_name AS referenced_column_name
177
+ ref_ns.nspname AS referenced_table_schema,
178
+ ref_cl.relname AS referenced_table_name,
179
+ ref_att.attname AS referenced_column_name,
180
+ rc.delete_rule,
181
+ rc.update_rule
181
182
  FROM information_schema.table_constraints tc
182
183
  JOIN information_schema.key_column_usage kcu
183
184
  ON tc.constraint_name = kcu.constraint_name
184
185
  AND tc.table_schema = kcu.table_schema
185
186
  AND tc.table_name = kcu.table_name
186
- JOIN information_schema.constraint_column_usage ccu
187
- ON ccu.constraint_name = tc.constraint_name
188
- AND ccu.table_schema = tc.table_schema
187
+ JOIN pg_catalog.pg_constraint pgc
188
+ ON pgc.conname = tc.constraint_name
189
+ AND pgc.connamespace = (
190
+ SELECT oid FROM pg_catalog.pg_namespace WHERE nspname = tc.table_schema
191
+ )
192
+ JOIN pg_catalog.pg_class ref_cl
193
+ ON ref_cl.oid = pgc.confrelid
194
+ JOIN pg_catalog.pg_namespace ref_ns
195
+ ON ref_ns.oid = ref_cl.relnamespace
196
+ JOIN pg_catalog.pg_attribute ref_att
197
+ ON ref_att.attrelid = pgc.confrelid
198
+ AND ref_att.attnum = pgc.confkey[kcu.ordinal_position]
199
+ JOIN information_schema.referential_constraints rc
200
+ ON rc.constraint_name = tc.constraint_name
201
+ AND rc.constraint_schema = tc.table_schema
189
202
  WHERE tc.table_schema = $1
190
203
  AND tc.constraint_type = 'FOREIGN KEY'
191
204
  ORDER BY tc.table_name, tc.constraint_name, kcu.ordinal_position`, [schema]),
@@ -279,14 +292,18 @@ var PostgresControlAdapter = class {
279
292
  columns: [fkRow.column_name],
280
293
  referencedTable: fkRow.referenced_table_name,
281
294
  referencedColumns: [fkRow.referenced_column_name],
282
- name: fkRow.constraint_name
295
+ name: fkRow.constraint_name,
296
+ deleteRule: fkRow.delete_rule,
297
+ updateRule: fkRow.update_rule
283
298
  });
284
299
  }
285
300
  const foreignKeys = Array.from(foreignKeysMap.values()).map((fk) => ({
286
301
  columns: Object.freeze([...fk.columns]),
287
302
  referencedTable: fk.referencedTable,
288
303
  referencedColumns: Object.freeze([...fk.referencedColumns]),
289
- name: fk.name
304
+ name: fk.name,
305
+ ...ifDefined("onDelete", mapReferentialAction(fk.deleteRule)),
306
+ ...ifDefined("onUpdate", mapReferentialAction(fk.updateRule))
290
307
  }));
291
308
  const pkConstraints = pkConstraintsByTable.get(tableName) ?? /* @__PURE__ */ new Set();
292
309
  const uniquesMap = /* @__PURE__ */ new Map();
@@ -393,6 +410,24 @@ function normalizeFormattedType(formattedType, dataType, udtName) {
393
410
  if (formattedType.startsWith("\"") && formattedType.endsWith("\"")) return formattedType.slice(1, -1);
394
411
  return formattedType;
395
412
  }
413
+ const PG_REFERENTIAL_ACTION_MAP = {
414
+ "NO ACTION": "noAction",
415
+ RESTRICT: "restrict",
416
+ CASCADE: "cascade",
417
+ "SET NULL": "setNull",
418
+ "SET DEFAULT": "setDefault"
419
+ };
420
+ /**
421
+ * Maps a Postgres referential action rule to the canonical SqlReferentialAction.
422
+ * Returns undefined for 'NO ACTION' (the database default) to keep the IR sparse.
423
+ * Throws for unrecognized rules to prevent silent data loss.
424
+ */
425
+ function mapReferentialAction(rule) {
426
+ const mapped = PG_REFERENTIAL_ACTION_MAP[rule];
427
+ if (mapped === void 0) throw new Error(`Unknown PostgreSQL referential action rule: "${rule}". Expected one of: NO ACTION, RESTRICT, CASCADE, SET NULL, SET DEFAULT.`);
428
+ if (mapped === "noAction") return void 0;
429
+ return mapped;
430
+ }
396
431
  /**
397
432
  * Groups an array of objects by a specified key.
398
433
  * Returns a Map for O(1) lookup by group key.
@@ -1 +1 @@
1
- {"version":3,"file":"control.mjs","names":["tables: Record<string, SqlTableIR>","columns: Record<string, SqlColumnIR>","primaryKey: PrimaryKey | undefined","foreignKeys: readonly SqlForeignKeyIR[]","uniques: readonly SqlUniqueIR[]","indexes: readonly SqlIndexIR[]","TYPE_PREFIX_MAP: ReadonlyMap<string, string>","postgresAdapterDescriptor: SqlControlAdapterDescriptor<'postgres'>"],"sources":["../src/core/default-normalizer.ts","../src/core/control-adapter.ts","../src/exports/control.ts"],"sourcesContent":["import type { ColumnDefault } from '@prisma-next/contract/types';\n\n/**\n * Pre-compiled regex patterns for performance.\n * These are compiled once at module load time rather than on each function call.\n */\nconst NEXTVAL_PATTERN = /^nextval\\s*\\(/i;\nconst TIMESTAMP_PATTERN = /^(now\\s*\\(\\s*\\)|CURRENT_TIMESTAMP|clock_timestamp\\s*\\(\\s*\\))$/i;\nconst UUID_PATTERN = /^gen_random_uuid\\s*\\(\\s*\\)$/i;\nconst UUID_OSSP_PATTERN = /^uuid_generate_v4\\s*\\(\\s*\\)$/i;\nconst TRUE_PATTERN = /^true$/i;\nconst FALSE_PATTERN = /^false$/i;\nconst NUMERIC_PATTERN = /^-?\\d+(\\.\\d+)?$/;\nconst STRING_LITERAL_PATTERN = /^'((?:[^']|'')*)'(?:::(?:\"[^\"]+\"|[\\w\\s]+)(?:\\(\\d+\\))?)?$/;\n\n/**\n * Parses a raw Postgres column default expression into a normalized ColumnDefault.\n * This enables semantic comparison between contract defaults and introspected schema defaults.\n *\n * Used by the migration diff layer to normalize raw database defaults during comparison,\n * keeping the introspection layer focused on faithful data capture.\n *\n * @param rawDefault - Raw default expression from information_schema.columns.column_default\n * @param _nativeType - Native column type (currently unused, reserved for future type-aware parsing)\n * @returns Normalized ColumnDefault or undefined if the expression cannot be parsed\n */\nexport function parsePostgresDefault(\n rawDefault: string,\n _nativeType?: string,\n): ColumnDefault | undefined {\n const trimmed = rawDefault.trim();\n const normalizedType = _nativeType?.toLowerCase();\n const isBigInt = normalizedType === 'bigint' || normalizedType === 'int8';\n\n // Autoincrement: nextval('tablename_column_seq'::regclass)\n if (NEXTVAL_PATTERN.test(trimmed)) {\n return { kind: 'function', expression: 'autoincrement()' };\n }\n\n // now() / CURRENT_TIMESTAMP / clock_timestamp()\n if (TIMESTAMP_PATTERN.test(trimmed)) {\n return { kind: 'function', expression: 'now()' };\n }\n\n // gen_random_uuid()\n if (UUID_PATTERN.test(trimmed)) {\n return { kind: 'function', expression: 'gen_random_uuid()' };\n }\n\n // uuid_generate_v4() from uuid-ossp extension\n if (UUID_OSSP_PATTERN.test(trimmed)) {\n return { kind: 'function', expression: 'gen_random_uuid()' };\n }\n\n // Boolean literals\n if (TRUE_PATTERN.test(trimmed)) {\n return { kind: 'literal', value: true };\n }\n if (FALSE_PATTERN.test(trimmed)) {\n return { kind: 'literal', value: false };\n }\n\n // Numeric literals (integer or decimal)\n if (NUMERIC_PATTERN.test(trimmed)) {\n if (isBigInt) {\n return { kind: 'literal', value: { $type: 'bigint', value: trimmed } };\n }\n return { kind: 'literal', value: Number(trimmed) };\n }\n\n // String literals: 'value'::type or just 'value'\n // Match: 'some text'::text, 'hello'::character varying, 'value', etc.\n // Strip the ::type cast so the normalized expression matches what contract authors write.\n const stringMatch = trimmed.match(STRING_LITERAL_PATTERN);\n if (stringMatch?.[1] !== undefined) {\n const unescaped = stringMatch[1].replace(/''/g, \"'\");\n if (normalizedType === 'json' || normalizedType === 'jsonb') {\n try {\n return { kind: 'literal', value: JSON.parse(unescaped) };\n } catch {\n // Keep legacy behavior for malformed/non-JSON string content.\n }\n }\n return { kind: 'literal', value: unescaped };\n }\n\n // Unrecognized expression - return as a function with the raw expression\n // This preserves the information for debugging while still being comparable\n return { kind: 'function', expression: trimmed };\n}\n","import type { ControlDriverInstance } from '@prisma-next/core-control-plane/types';\nimport type { SqlControlAdapter } from '@prisma-next/family-sql/control-adapter';\nimport type {\n PrimaryKey,\n SqlColumnIR,\n SqlForeignKeyIR,\n SqlIndexIR,\n SqlSchemaIR,\n SqlTableIR,\n SqlUniqueIR,\n} from '@prisma-next/sql-schema-ir/types';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { parsePostgresDefault } from './default-normalizer';\nimport { pgEnumControlHooks } from './enum-control-hooks';\n\n/**\n * Postgres control plane adapter for control-plane operations like introspection.\n * Provides target-specific implementations for control-plane domain actions.\n */\nexport class PostgresControlAdapter implements SqlControlAdapter<'postgres'> {\n readonly familyId = 'sql' as const;\n readonly targetId = 'postgres' as const;\n /**\n * @deprecated Use targetId instead\n */\n readonly target = 'postgres' as const;\n\n /**\n * Target-specific normalizer for raw Postgres default expressions.\n * Used by schema verification to normalize raw defaults before comparison.\n */\n readonly normalizeDefault = parsePostgresDefault;\n\n /**\n * Target-specific normalizer for Postgres schema native type names.\n * Used by schema verification to normalize introspected type names\n * before comparison with contract native types.\n */\n readonly normalizeNativeType = normalizeSchemaNativeType;\n\n /**\n * Introspects a Postgres database schema and returns a raw SqlSchemaIR.\n *\n * This is a pure schema discovery operation that queries the Postgres catalog\n * and returns the schema structure without type mapping or contract enrichment.\n * Type mapping and enrichment are handled separately by enrichment helpers.\n *\n * Uses batched queries to minimize database round trips (7 queries instead of 5T+3).\n *\n * @param driver - ControlDriverInstance<'sql', 'postgres'> instance for executing queries\n * @param contractIR - Optional contract IR for contract-guided introspection (filtering, optimization)\n * @param schema - Schema name to introspect (defaults to 'public')\n * @returns Promise resolving to SqlSchemaIR representing the live database schema\n */\n async introspect(\n driver: ControlDriverInstance<'sql', 'postgres'>,\n _contractIR?: unknown,\n schema = 'public',\n ): Promise<SqlSchemaIR> {\n // Execute all queries in parallel for efficiency (7 queries instead of 5T+3)\n const [\n tablesResult,\n columnsResult,\n pkResult,\n fkResult,\n uniqueResult,\n indexResult,\n extensionsResult,\n ] = await Promise.all([\n // Query all tables\n driver.query<{ table_name: string }>(\n `SELECT table_name\n FROM information_schema.tables\n WHERE table_schema = $1\n AND table_type = 'BASE TABLE'\n ORDER BY table_name`,\n [schema],\n ),\n // Query all columns for all tables in schema\n driver.query<{\n table_name: string;\n column_name: string;\n data_type: string;\n udt_name: string;\n is_nullable: string;\n character_maximum_length: number | null;\n numeric_precision: number | null;\n numeric_scale: number | null;\n column_default: string | null;\n formatted_type: string | null;\n }>(\n `SELECT\n c.table_name,\n column_name,\n data_type,\n udt_name,\n is_nullable,\n character_maximum_length,\n numeric_precision,\n numeric_scale,\n column_default,\n format_type(a.atttypid, a.atttypmod) AS formatted_type\n FROM information_schema.columns c\n JOIN pg_catalog.pg_class cl\n ON cl.relname = c.table_name\n JOIN pg_catalog.pg_namespace ns\n ON ns.nspname = c.table_schema\n AND ns.oid = cl.relnamespace\n JOIN pg_catalog.pg_attribute a\n ON a.attrelid = cl.oid\n AND a.attname = c.column_name\n AND a.attnum > 0\n AND NOT a.attisdropped\n WHERE c.table_schema = $1\n ORDER BY c.table_name, c.ordinal_position`,\n [schema],\n ),\n // Query all primary keys for all tables in schema\n driver.query<{\n table_name: string;\n constraint_name: string;\n column_name: string;\n ordinal_position: number;\n }>(\n `SELECT\n tc.table_name,\n tc.constraint_name,\n kcu.column_name,\n kcu.ordinal_position\n FROM information_schema.table_constraints tc\n JOIN information_schema.key_column_usage kcu\n ON tc.constraint_name = kcu.constraint_name\n AND tc.table_schema = kcu.table_schema\n AND tc.table_name = kcu.table_name\n WHERE tc.table_schema = $1\n AND tc.constraint_type = 'PRIMARY KEY'\n ORDER BY tc.table_name, kcu.ordinal_position`,\n [schema],\n ),\n // Query all foreign keys for all tables in schema\n driver.query<{\n table_name: string;\n constraint_name: string;\n column_name: string;\n ordinal_position: number;\n referenced_table_schema: string;\n referenced_table_name: string;\n referenced_column_name: string;\n }>(\n `SELECT\n tc.table_name,\n tc.constraint_name,\n kcu.column_name,\n kcu.ordinal_position,\n ccu.table_schema AS referenced_table_schema,\n ccu.table_name AS referenced_table_name,\n ccu.column_name AS referenced_column_name\n FROM information_schema.table_constraints tc\n JOIN information_schema.key_column_usage kcu\n ON tc.constraint_name = kcu.constraint_name\n AND tc.table_schema = kcu.table_schema\n AND tc.table_name = kcu.table_name\n JOIN information_schema.constraint_column_usage ccu\n ON ccu.constraint_name = tc.constraint_name\n AND ccu.table_schema = tc.table_schema\n WHERE tc.table_schema = $1\n AND tc.constraint_type = 'FOREIGN KEY'\n ORDER BY tc.table_name, tc.constraint_name, kcu.ordinal_position`,\n [schema],\n ),\n // Query all unique constraints for all tables in schema (excluding PKs)\n driver.query<{\n table_name: string;\n constraint_name: string;\n column_name: string;\n ordinal_position: number;\n }>(\n `SELECT\n tc.table_name,\n tc.constraint_name,\n kcu.column_name,\n kcu.ordinal_position\n FROM information_schema.table_constraints tc\n JOIN information_schema.key_column_usage kcu\n ON tc.constraint_name = kcu.constraint_name\n AND tc.table_schema = kcu.table_schema\n AND tc.table_name = kcu.table_name\n WHERE tc.table_schema = $1\n AND tc.constraint_type = 'UNIQUE'\n ORDER BY tc.table_name, tc.constraint_name, kcu.ordinal_position`,\n [schema],\n ),\n // Query all indexes for all tables in schema (excluding constraints)\n driver.query<{\n tablename: string;\n indexname: string;\n indisunique: boolean;\n attname: string;\n attnum: number;\n }>(\n `SELECT\n i.tablename,\n i.indexname,\n ix.indisunique,\n a.attname,\n a.attnum\n FROM pg_indexes i\n JOIN pg_class ic ON ic.relname = i.indexname\n JOIN pg_namespace ins ON ins.oid = ic.relnamespace AND ins.nspname = $1\n JOIN pg_index ix ON ix.indexrelid = ic.oid\n JOIN pg_class t ON t.oid = ix.indrelid\n JOIN pg_namespace tn ON tn.oid = t.relnamespace AND tn.nspname = $1\n LEFT JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = ANY(ix.indkey) AND a.attnum > 0\n WHERE i.schemaname = $1\n AND NOT EXISTS (\n SELECT 1\n FROM information_schema.table_constraints tc\n WHERE tc.table_schema = $1\n AND tc.table_name = i.tablename\n AND tc.constraint_name = i.indexname\n )\n ORDER BY i.tablename, i.indexname, a.attnum`,\n [schema],\n ),\n // Query extensions\n driver.query<{ extname: string }>(\n `SELECT extname\n FROM pg_extension\n ORDER BY extname`,\n [],\n ),\n ]);\n\n // Group results by table name for efficient lookup\n const columnsByTable = groupBy(columnsResult.rows, 'table_name');\n const pksByTable = groupBy(pkResult.rows, 'table_name');\n const fksByTable = groupBy(fkResult.rows, 'table_name');\n const uniquesByTable = groupBy(uniqueResult.rows, 'table_name');\n const indexesByTable = groupBy(indexResult.rows, 'tablename');\n\n // Get set of PK constraint names per table (to exclude from uniques)\n const pkConstraintsByTable = new Map<string, Set<string>>();\n for (const row of pkResult.rows) {\n let constraints = pkConstraintsByTable.get(row.table_name);\n if (!constraints) {\n constraints = new Set();\n pkConstraintsByTable.set(row.table_name, constraints);\n }\n constraints.add(row.constraint_name);\n }\n\n const tables: Record<string, SqlTableIR> = {};\n\n for (const tableRow of tablesResult.rows) {\n const tableName = tableRow.table_name;\n\n // Process columns for this table\n const columns: Record<string, SqlColumnIR> = {};\n for (const colRow of columnsByTable.get(tableName) ?? []) {\n let nativeType = colRow.udt_name;\n const formattedType = colRow.formatted_type\n ? normalizeFormattedType(colRow.formatted_type, colRow.data_type, colRow.udt_name)\n : null;\n if (formattedType) {\n nativeType = formattedType;\n } else if (colRow.data_type === 'character varying' || colRow.data_type === 'character') {\n if (colRow.character_maximum_length) {\n nativeType = `${colRow.data_type}(${colRow.character_maximum_length})`;\n } else {\n nativeType = colRow.data_type;\n }\n } else if (colRow.data_type === 'numeric' || colRow.data_type === 'decimal') {\n if (colRow.numeric_precision && colRow.numeric_scale !== null) {\n nativeType = `${colRow.data_type}(${colRow.numeric_precision},${colRow.numeric_scale})`;\n } else if (colRow.numeric_precision) {\n nativeType = `${colRow.data_type}(${colRow.numeric_precision})`;\n } else {\n nativeType = colRow.data_type;\n }\n } else {\n nativeType = colRow.udt_name || colRow.data_type;\n }\n\n columns[colRow.column_name] = {\n name: colRow.column_name,\n nativeType,\n nullable: colRow.is_nullable === 'YES',\n ...ifDefined('default', colRow.column_default ?? undefined),\n };\n }\n\n // Process primary key\n const pkRows = [...(pksByTable.get(tableName) ?? [])];\n const primaryKeyColumns = pkRows\n .sort((a, b) => a.ordinal_position - b.ordinal_position)\n .map((row) => row.column_name);\n const primaryKey: PrimaryKey | undefined =\n primaryKeyColumns.length > 0\n ? {\n columns: primaryKeyColumns,\n ...(pkRows[0]?.constraint_name ? { name: pkRows[0].constraint_name } : {}),\n }\n : undefined;\n\n // Process foreign keys\n const foreignKeysMap = new Map<\n string,\n { columns: string[]; referencedTable: string; referencedColumns: string[]; name: string }\n >();\n for (const fkRow of fksByTable.get(tableName) ?? []) {\n const existing = foreignKeysMap.get(fkRow.constraint_name);\n if (existing) {\n existing.columns.push(fkRow.column_name);\n existing.referencedColumns.push(fkRow.referenced_column_name);\n } else {\n foreignKeysMap.set(fkRow.constraint_name, {\n columns: [fkRow.column_name],\n referencedTable: fkRow.referenced_table_name,\n referencedColumns: [fkRow.referenced_column_name],\n name: fkRow.constraint_name,\n });\n }\n }\n const foreignKeys: readonly SqlForeignKeyIR[] = Array.from(foreignKeysMap.values()).map(\n (fk) => ({\n columns: Object.freeze([...fk.columns]) as readonly string[],\n referencedTable: fk.referencedTable,\n referencedColumns: Object.freeze([...fk.referencedColumns]) as readonly string[],\n name: fk.name,\n }),\n );\n\n // Process unique constraints (excluding those that are also PKs)\n const pkConstraints = pkConstraintsByTable.get(tableName) ?? new Set();\n const uniquesMap = new Map<string, { columns: string[]; name: string }>();\n for (const uniqueRow of uniquesByTable.get(tableName) ?? []) {\n // Skip if this constraint is also a primary key\n if (pkConstraints.has(uniqueRow.constraint_name)) {\n continue;\n }\n const existing = uniquesMap.get(uniqueRow.constraint_name);\n if (existing) {\n existing.columns.push(uniqueRow.column_name);\n } else {\n uniquesMap.set(uniqueRow.constraint_name, {\n columns: [uniqueRow.column_name],\n name: uniqueRow.constraint_name,\n });\n }\n }\n const uniques: readonly SqlUniqueIR[] = Array.from(uniquesMap.values()).map((uq) => ({\n columns: Object.freeze([...uq.columns]) as readonly string[],\n name: uq.name,\n }));\n\n // Process indexes\n const indexesMap = new Map<string, { columns: string[]; name: string; unique: boolean }>();\n for (const idxRow of indexesByTable.get(tableName) ?? []) {\n if (!idxRow.attname) {\n continue;\n }\n const existing = indexesMap.get(idxRow.indexname);\n if (existing) {\n existing.columns.push(idxRow.attname);\n } else {\n indexesMap.set(idxRow.indexname, {\n columns: [idxRow.attname],\n name: idxRow.indexname,\n unique: idxRow.indisunique,\n });\n }\n }\n const indexes: readonly SqlIndexIR[] = Array.from(indexesMap.values()).map((idx) => ({\n columns: Object.freeze([...idx.columns]) as readonly string[],\n name: idx.name,\n unique: idx.unique,\n }));\n\n tables[tableName] = {\n name: tableName,\n columns,\n ...ifDefined('primaryKey', primaryKey),\n foreignKeys,\n uniques,\n indexes,\n };\n }\n\n const extensions = extensionsResult.rows.map((row) => row.extname);\n\n const storageTypes =\n (await pgEnumControlHooks.introspectTypes?.({ driver, schemaName: schema })) ?? {};\n\n const annotations = {\n pg: {\n schema,\n version: await this.getPostgresVersion(driver),\n ...ifDefined(\n 'storageTypes',\n Object.keys(storageTypes).length > 0 ? storageTypes : undefined,\n ),\n },\n };\n\n return {\n tables,\n extensions,\n annotations,\n };\n }\n\n /**\n * Gets the Postgres version from the database.\n */\n private async getPostgresVersion(\n driver: ControlDriverInstance<'sql', 'postgres'>,\n ): Promise<string> {\n const result = await driver.query<{ version: string }>('SELECT version() AS version', []);\n const versionString = result.rows[0]?.version ?? '';\n // Extract version number from \"PostgreSQL 15.1 ...\" format\n const match = versionString.match(/PostgreSQL (\\d+\\.\\d+)/);\n return match?.[1] ?? 'unknown';\n }\n}\n\n/**\n * Pre-computed lookup map for simple prefix-based type normalization.\n * Maps short Postgres type names to their canonical SQL names.\n * Using a Map for O(1) lookup instead of multiple startsWith checks.\n */\nconst TYPE_PREFIX_MAP: ReadonlyMap<string, string> = new Map([\n ['varchar', 'character varying'],\n ['bpchar', 'character'],\n ['varbit', 'bit varying'],\n]);\n\n/**\n * Normalizes a Postgres schema native type to its canonical form for comparison.\n *\n * Uses a pre-computed lookup map for simple prefix replacements (O(1))\n * and handles complex temporal type normalization separately.\n */\nexport function normalizeSchemaNativeType(nativeType: string): string {\n const trimmed = nativeType.trim();\n\n // Fast path: check simple prefix replacements using the lookup map\n for (const [prefix, replacement] of TYPE_PREFIX_MAP) {\n if (trimmed.startsWith(prefix)) {\n return replacement + trimmed.slice(prefix.length);\n }\n }\n\n // Temporal types with time zone handling\n // Check for 'with time zone' suffix first (more specific)\n if (trimmed.includes(' with time zone')) {\n if (trimmed.startsWith('timestamp')) {\n return `timestamptz${trimmed.slice(9).replace(' with time zone', '')}`;\n }\n if (trimmed.startsWith('time')) {\n return `timetz${trimmed.slice(4).replace(' with time zone', '')}`;\n }\n }\n\n // Handle 'without time zone' suffix - just strip it\n if (trimmed.includes(' without time zone')) {\n return trimmed.replace(' without time zone', '');\n }\n\n return trimmed;\n}\n\nfunction normalizeFormattedType(formattedType: string, dataType: string, udtName: string): string {\n if (formattedType === 'integer') {\n return 'int4';\n }\n if (formattedType === 'smallint') {\n return 'int2';\n }\n if (formattedType === 'bigint') {\n return 'int8';\n }\n if (formattedType === 'real') {\n return 'float4';\n }\n if (formattedType === 'double precision') {\n return 'float8';\n }\n if (formattedType === 'boolean') {\n return 'bool';\n }\n if (formattedType.startsWith('varchar')) {\n return formattedType.replace('varchar', 'character varying');\n }\n if (formattedType.startsWith('bpchar')) {\n return formattedType.replace('bpchar', 'character');\n }\n if (formattedType.startsWith('varbit')) {\n return formattedType.replace('varbit', 'bit varying');\n }\n if (dataType === 'timestamp with time zone' || udtName === 'timestamptz') {\n return formattedType.replace('timestamp', 'timestamptz').replace(' with time zone', '').trim();\n }\n if (dataType === 'timestamp without time zone' || udtName === 'timestamp') {\n return formattedType.replace(' without time zone', '').trim();\n }\n if (dataType === 'time with time zone' || udtName === 'timetz') {\n return formattedType.replace('time', 'timetz').replace(' with time zone', '').trim();\n }\n if (dataType === 'time without time zone' || udtName === 'time') {\n return formattedType.replace(' without time zone', '').trim();\n }\n // Only dataType === 'USER-DEFINED' should ever be quoted, but this should be safe without\n // checking that explicitly either way\n if (formattedType.startsWith('\"') && formattedType.endsWith('\"')) {\n return formattedType.slice(1, -1);\n }\n return formattedType;\n}\n\n/**\n * Groups an array of objects by a specified key.\n * Returns a Map for O(1) lookup by group key.\n */\nfunction groupBy<T, K extends keyof T>(items: readonly T[], key: K): Map<T[K], T[]> {\n const map = new Map<T[K], T[]>();\n for (const item of items) {\n const groupKey = item[key];\n let group = map.get(groupKey);\n if (!group) {\n group = [];\n map.set(groupKey, group);\n }\n group.push(item);\n }\n return map;\n}\n","import type { SqlControlAdapterDescriptor } from '@prisma-next/family-sql/control';\nimport type { SqlControlAdapter } from '@prisma-next/family-sql/control-adapter';\nimport { PostgresControlAdapter } from '../core/control-adapter';\nimport { parsePostgresDefault } from '../core/default-normalizer';\nimport { postgresAdapterDescriptorMeta } from '../core/descriptor-meta';\nimport { expandParameterizedNativeType } from '../core/parameterized-types';\nimport { escapeLiteral, qualifyName, quoteIdentifier, SqlEscapeError } from '../core/sql-utils';\n\nconst postgresAdapterDescriptor: SqlControlAdapterDescriptor<'postgres'> = {\n ...postgresAdapterDescriptorMeta,\n operationSignatures: () => [],\n create(): SqlControlAdapter<'postgres'> {\n return new PostgresControlAdapter();\n },\n};\n\nexport default postgresAdapterDescriptor;\n\nexport { normalizeSchemaNativeType } from '../core/control-adapter';\nexport {\n escapeLiteral,\n expandParameterizedNativeType,\n parsePostgresDefault,\n qualifyName,\n quoteIdentifier,\n SqlEscapeError,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"control.mjs","names":["tables: Record<string, SqlTableIR>","columns: Record<string, SqlColumnIR>","primaryKey: PrimaryKey | undefined","foreignKeys: readonly SqlForeignKeyIR[]","uniques: readonly SqlUniqueIR[]","indexes: readonly SqlIndexIR[]","TYPE_PREFIX_MAP: ReadonlyMap<string, string>","PG_REFERENTIAL_ACTION_MAP: Record<PgReferentialActionRule, SqlReferentialAction>","postgresAdapterDescriptor: SqlControlAdapterDescriptor<'postgres'>"],"sources":["../src/core/default-normalizer.ts","../src/core/control-adapter.ts","../src/exports/control.ts"],"sourcesContent":["import type { ColumnDefault } from '@prisma-next/contract/types';\n\n/**\n * Pre-compiled regex patterns for performance.\n * These are compiled once at module load time rather than on each function call.\n */\nconst NEXTVAL_PATTERN = /^nextval\\s*\\(/i;\nconst TIMESTAMP_PATTERN = /^(now\\s*\\(\\s*\\)|CURRENT_TIMESTAMP|clock_timestamp\\s*\\(\\s*\\))$/i;\nconst UUID_PATTERN = /^gen_random_uuid\\s*\\(\\s*\\)$/i;\nconst UUID_OSSP_PATTERN = /^uuid_generate_v4\\s*\\(\\s*\\)$/i;\nconst TRUE_PATTERN = /^true$/i;\nconst FALSE_PATTERN = /^false$/i;\nconst NUMERIC_PATTERN = /^-?\\d+(\\.\\d+)?$/;\nconst STRING_LITERAL_PATTERN = /^'((?:[^']|'')*)'(?:::(?:\"[^\"]+\"|[\\w\\s]+)(?:\\(\\d+\\))?)?$/;\n\n/**\n * Parses a raw Postgres column default expression into a normalized ColumnDefault.\n * This enables semantic comparison between contract defaults and introspected schema defaults.\n *\n * Used by the migration diff layer to normalize raw database defaults during comparison,\n * keeping the introspection layer focused on faithful data capture.\n *\n * @param rawDefault - Raw default expression from information_schema.columns.column_default\n * @param _nativeType - Native column type (currently unused, reserved for future type-aware parsing)\n * @returns Normalized ColumnDefault or undefined if the expression cannot be parsed\n */\nexport function parsePostgresDefault(\n rawDefault: string,\n _nativeType?: string,\n): ColumnDefault | undefined {\n const trimmed = rawDefault.trim();\n const normalizedType = _nativeType?.toLowerCase();\n const isBigInt = normalizedType === 'bigint' || normalizedType === 'int8';\n\n // Autoincrement: nextval('tablename_column_seq'::regclass)\n if (NEXTVAL_PATTERN.test(trimmed)) {\n return { kind: 'function', expression: 'autoincrement()' };\n }\n\n // now() / CURRENT_TIMESTAMP / clock_timestamp()\n if (TIMESTAMP_PATTERN.test(trimmed)) {\n return { kind: 'function', expression: 'now()' };\n }\n\n // gen_random_uuid()\n if (UUID_PATTERN.test(trimmed)) {\n return { kind: 'function', expression: 'gen_random_uuid()' };\n }\n\n // uuid_generate_v4() from uuid-ossp extension\n if (UUID_OSSP_PATTERN.test(trimmed)) {\n return { kind: 'function', expression: 'gen_random_uuid()' };\n }\n\n // Boolean literals\n if (TRUE_PATTERN.test(trimmed)) {\n return { kind: 'literal', value: true };\n }\n if (FALSE_PATTERN.test(trimmed)) {\n return { kind: 'literal', value: false };\n }\n\n // Numeric literals (integer or decimal)\n if (NUMERIC_PATTERN.test(trimmed)) {\n if (isBigInt) {\n return { kind: 'literal', value: { $type: 'bigint', value: trimmed } };\n }\n return { kind: 'literal', value: Number(trimmed) };\n }\n\n // String literals: 'value'::type or just 'value'\n // Match: 'some text'::text, 'hello'::character varying, 'value', etc.\n // Strip the ::type cast so the normalized expression matches what contract authors write.\n const stringMatch = trimmed.match(STRING_LITERAL_PATTERN);\n if (stringMatch?.[1] !== undefined) {\n const unescaped = stringMatch[1].replace(/''/g, \"'\");\n if (normalizedType === 'json' || normalizedType === 'jsonb') {\n try {\n return { kind: 'literal', value: JSON.parse(unescaped) };\n } catch {\n // Keep legacy behavior for malformed/non-JSON string content.\n }\n }\n return { kind: 'literal', value: unescaped };\n }\n\n // Unrecognized expression - return as a function with the raw expression\n // This preserves the information for debugging while still being comparable\n return { kind: 'function', expression: trimmed };\n}\n","import type { ControlDriverInstance } from '@prisma-next/core-control-plane/types';\nimport type { SqlControlAdapter } from '@prisma-next/family-sql/control-adapter';\nimport type {\n PrimaryKey,\n SqlColumnIR,\n SqlForeignKeyIR,\n SqlIndexIR,\n SqlReferentialAction,\n SqlSchemaIR,\n SqlTableIR,\n SqlUniqueIR,\n} from '@prisma-next/sql-schema-ir/types';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { parsePostgresDefault } from './default-normalizer';\nimport { pgEnumControlHooks } from './enum-control-hooks';\n\n/**\n * Postgres control plane adapter for control-plane operations like introspection.\n * Provides target-specific implementations for control-plane domain actions.\n */\nexport class PostgresControlAdapter implements SqlControlAdapter<'postgres'> {\n readonly familyId = 'sql' as const;\n readonly targetId = 'postgres' as const;\n /**\n * @deprecated Use targetId instead\n */\n readonly target = 'postgres' as const;\n\n /**\n * Target-specific normalizer for raw Postgres default expressions.\n * Used by schema verification to normalize raw defaults before comparison.\n */\n readonly normalizeDefault = parsePostgresDefault;\n\n /**\n * Target-specific normalizer for Postgres schema native type names.\n * Used by schema verification to normalize introspected type names\n * before comparison with contract native types.\n */\n readonly normalizeNativeType = normalizeSchemaNativeType;\n\n /**\n * Introspects a Postgres database schema and returns a raw SqlSchemaIR.\n *\n * This is a pure schema discovery operation that queries the Postgres catalog\n * and returns the schema structure without type mapping or contract enrichment.\n * Type mapping and enrichment are handled separately by enrichment helpers.\n *\n * Uses batched queries to minimize database round trips (7 queries instead of 5T+3).\n *\n * @param driver - ControlDriverInstance<'sql', 'postgres'> instance for executing queries\n * @param contractIR - Optional contract IR for contract-guided introspection (filtering, optimization)\n * @param schema - Schema name to introspect (defaults to 'public')\n * @returns Promise resolving to SqlSchemaIR representing the live database schema\n */\n async introspect(\n driver: ControlDriverInstance<'sql', 'postgres'>,\n _contractIR?: unknown,\n schema = 'public',\n ): Promise<SqlSchemaIR> {\n // Execute all queries in parallel for efficiency (7 queries instead of 5T+3)\n const [\n tablesResult,\n columnsResult,\n pkResult,\n fkResult,\n uniqueResult,\n indexResult,\n extensionsResult,\n ] = await Promise.all([\n // Query all tables\n driver.query<{ table_name: string }>(\n `SELECT table_name\n FROM information_schema.tables\n WHERE table_schema = $1\n AND table_type = 'BASE TABLE'\n ORDER BY table_name`,\n [schema],\n ),\n // Query all columns for all tables in schema\n driver.query<{\n table_name: string;\n column_name: string;\n data_type: string;\n udt_name: string;\n is_nullable: string;\n character_maximum_length: number | null;\n numeric_precision: number | null;\n numeric_scale: number | null;\n column_default: string | null;\n formatted_type: string | null;\n }>(\n `SELECT\n c.table_name,\n column_name,\n data_type,\n udt_name,\n is_nullable,\n character_maximum_length,\n numeric_precision,\n numeric_scale,\n column_default,\n format_type(a.atttypid, a.atttypmod) AS formatted_type\n FROM information_schema.columns c\n JOIN pg_catalog.pg_class cl\n ON cl.relname = c.table_name\n JOIN pg_catalog.pg_namespace ns\n ON ns.nspname = c.table_schema\n AND ns.oid = cl.relnamespace\n JOIN pg_catalog.pg_attribute a\n ON a.attrelid = cl.oid\n AND a.attname = c.column_name\n AND a.attnum > 0\n AND NOT a.attisdropped\n WHERE c.table_schema = $1\n ORDER BY c.table_name, c.ordinal_position`,\n [schema],\n ),\n // Query all primary keys for all tables in schema\n driver.query<{\n table_name: string;\n constraint_name: string;\n column_name: string;\n ordinal_position: number;\n }>(\n `SELECT\n tc.table_name,\n tc.constraint_name,\n kcu.column_name,\n kcu.ordinal_position\n FROM information_schema.table_constraints tc\n JOIN information_schema.key_column_usage kcu\n ON tc.constraint_name = kcu.constraint_name\n AND tc.table_schema = kcu.table_schema\n AND tc.table_name = kcu.table_name\n WHERE tc.table_schema = $1\n AND tc.constraint_type = 'PRIMARY KEY'\n ORDER BY tc.table_name, kcu.ordinal_position`,\n [schema],\n ),\n // Query all foreign keys for all tables in schema, including referential actions.\n // Uses pg_catalog for correct positional pairing of composite FK columns\n // (information_schema.constraint_column_usage lacks ordinal_position,\n // which causes Cartesian products for multi-column FKs).\n driver.query<{\n table_name: string;\n constraint_name: string;\n column_name: string;\n ordinal_position: number;\n referenced_table_schema: string;\n referenced_table_name: string;\n referenced_column_name: string;\n delete_rule: string;\n update_rule: string;\n }>(\n `SELECT\n tc.table_name,\n tc.constraint_name,\n kcu.column_name,\n kcu.ordinal_position,\n ref_ns.nspname AS referenced_table_schema,\n ref_cl.relname AS referenced_table_name,\n ref_att.attname AS referenced_column_name,\n rc.delete_rule,\n rc.update_rule\n FROM information_schema.table_constraints tc\n JOIN information_schema.key_column_usage kcu\n ON tc.constraint_name = kcu.constraint_name\n AND tc.table_schema = kcu.table_schema\n AND tc.table_name = kcu.table_name\n JOIN pg_catalog.pg_constraint pgc\n ON pgc.conname = tc.constraint_name\n AND pgc.connamespace = (\n SELECT oid FROM pg_catalog.pg_namespace WHERE nspname = tc.table_schema\n )\n JOIN pg_catalog.pg_class ref_cl\n ON ref_cl.oid = pgc.confrelid\n JOIN pg_catalog.pg_namespace ref_ns\n ON ref_ns.oid = ref_cl.relnamespace\n JOIN pg_catalog.pg_attribute ref_att\n ON ref_att.attrelid = pgc.confrelid\n AND ref_att.attnum = pgc.confkey[kcu.ordinal_position]\n JOIN information_schema.referential_constraints rc\n ON rc.constraint_name = tc.constraint_name\n AND rc.constraint_schema = tc.table_schema\n WHERE tc.table_schema = $1\n AND tc.constraint_type = 'FOREIGN KEY'\n ORDER BY tc.table_name, tc.constraint_name, kcu.ordinal_position`,\n [schema],\n ),\n // Query all unique constraints for all tables in schema (excluding PKs)\n driver.query<{\n table_name: string;\n constraint_name: string;\n column_name: string;\n ordinal_position: number;\n }>(\n `SELECT\n tc.table_name,\n tc.constraint_name,\n kcu.column_name,\n kcu.ordinal_position\n FROM information_schema.table_constraints tc\n JOIN information_schema.key_column_usage kcu\n ON tc.constraint_name = kcu.constraint_name\n AND tc.table_schema = kcu.table_schema\n AND tc.table_name = kcu.table_name\n WHERE tc.table_schema = $1\n AND tc.constraint_type = 'UNIQUE'\n ORDER BY tc.table_name, tc.constraint_name, kcu.ordinal_position`,\n [schema],\n ),\n // Query all indexes for all tables in schema (excluding constraints)\n driver.query<{\n tablename: string;\n indexname: string;\n indisunique: boolean;\n attname: string;\n attnum: number;\n }>(\n `SELECT\n i.tablename,\n i.indexname,\n ix.indisunique,\n a.attname,\n a.attnum\n FROM pg_indexes i\n JOIN pg_class ic ON ic.relname = i.indexname\n JOIN pg_namespace ins ON ins.oid = ic.relnamespace AND ins.nspname = $1\n JOIN pg_index ix ON ix.indexrelid = ic.oid\n JOIN pg_class t ON t.oid = ix.indrelid\n JOIN pg_namespace tn ON tn.oid = t.relnamespace AND tn.nspname = $1\n LEFT JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = ANY(ix.indkey) AND a.attnum > 0\n WHERE i.schemaname = $1\n AND NOT EXISTS (\n SELECT 1\n FROM information_schema.table_constraints tc\n WHERE tc.table_schema = $1\n AND tc.table_name = i.tablename\n AND tc.constraint_name = i.indexname\n )\n ORDER BY i.tablename, i.indexname, a.attnum`,\n [schema],\n ),\n // Query extensions\n driver.query<{ extname: string }>(\n `SELECT extname\n FROM pg_extension\n ORDER BY extname`,\n [],\n ),\n ]);\n\n // Group results by table name for efficient lookup\n const columnsByTable = groupBy(columnsResult.rows, 'table_name');\n const pksByTable = groupBy(pkResult.rows, 'table_name');\n const fksByTable = groupBy(fkResult.rows, 'table_name');\n const uniquesByTable = groupBy(uniqueResult.rows, 'table_name');\n const indexesByTable = groupBy(indexResult.rows, 'tablename');\n\n // Get set of PK constraint names per table (to exclude from uniques)\n const pkConstraintsByTable = new Map<string, Set<string>>();\n for (const row of pkResult.rows) {\n let constraints = pkConstraintsByTable.get(row.table_name);\n if (!constraints) {\n constraints = new Set();\n pkConstraintsByTable.set(row.table_name, constraints);\n }\n constraints.add(row.constraint_name);\n }\n\n const tables: Record<string, SqlTableIR> = {};\n\n for (const tableRow of tablesResult.rows) {\n const tableName = tableRow.table_name;\n\n // Process columns for this table\n const columns: Record<string, SqlColumnIR> = {};\n for (const colRow of columnsByTable.get(tableName) ?? []) {\n let nativeType = colRow.udt_name;\n const formattedType = colRow.formatted_type\n ? normalizeFormattedType(colRow.formatted_type, colRow.data_type, colRow.udt_name)\n : null;\n if (formattedType) {\n nativeType = formattedType;\n } else if (colRow.data_type === 'character varying' || colRow.data_type === 'character') {\n if (colRow.character_maximum_length) {\n nativeType = `${colRow.data_type}(${colRow.character_maximum_length})`;\n } else {\n nativeType = colRow.data_type;\n }\n } else if (colRow.data_type === 'numeric' || colRow.data_type === 'decimal') {\n if (colRow.numeric_precision && colRow.numeric_scale !== null) {\n nativeType = `${colRow.data_type}(${colRow.numeric_precision},${colRow.numeric_scale})`;\n } else if (colRow.numeric_precision) {\n nativeType = `${colRow.data_type}(${colRow.numeric_precision})`;\n } else {\n nativeType = colRow.data_type;\n }\n } else {\n nativeType = colRow.udt_name || colRow.data_type;\n }\n\n columns[colRow.column_name] = {\n name: colRow.column_name,\n nativeType,\n nullable: colRow.is_nullable === 'YES',\n ...ifDefined('default', colRow.column_default ?? undefined),\n };\n }\n\n // Process primary key\n const pkRows = [...(pksByTable.get(tableName) ?? [])];\n const primaryKeyColumns = pkRows\n .sort((a, b) => a.ordinal_position - b.ordinal_position)\n .map((row) => row.column_name);\n const primaryKey: PrimaryKey | undefined =\n primaryKeyColumns.length > 0\n ? {\n columns: primaryKeyColumns,\n ...(pkRows[0]?.constraint_name ? { name: pkRows[0].constraint_name } : {}),\n }\n : undefined;\n\n // Process foreign keys\n const foreignKeysMap = new Map<\n string,\n {\n columns: string[];\n referencedTable: string;\n referencedColumns: string[];\n name: string;\n deleteRule: string;\n updateRule: string;\n }\n >();\n for (const fkRow of fksByTable.get(tableName) ?? []) {\n const existing = foreignKeysMap.get(fkRow.constraint_name);\n if (existing) {\n existing.columns.push(fkRow.column_name);\n existing.referencedColumns.push(fkRow.referenced_column_name);\n } else {\n foreignKeysMap.set(fkRow.constraint_name, {\n columns: [fkRow.column_name],\n referencedTable: fkRow.referenced_table_name,\n referencedColumns: [fkRow.referenced_column_name],\n name: fkRow.constraint_name,\n deleteRule: fkRow.delete_rule,\n updateRule: fkRow.update_rule,\n });\n }\n }\n const foreignKeys: readonly SqlForeignKeyIR[] = Array.from(foreignKeysMap.values()).map(\n (fk) => ({\n columns: Object.freeze([...fk.columns]) as readonly string[],\n referencedTable: fk.referencedTable,\n referencedColumns: Object.freeze([...fk.referencedColumns]) as readonly string[],\n name: fk.name,\n ...ifDefined('onDelete', mapReferentialAction(fk.deleteRule)),\n ...ifDefined('onUpdate', mapReferentialAction(fk.updateRule)),\n }),\n );\n\n // Process unique constraints (excluding those that are also PKs)\n const pkConstraints = pkConstraintsByTable.get(tableName) ?? new Set();\n const uniquesMap = new Map<string, { columns: string[]; name: string }>();\n for (const uniqueRow of uniquesByTable.get(tableName) ?? []) {\n // Skip if this constraint is also a primary key\n if (pkConstraints.has(uniqueRow.constraint_name)) {\n continue;\n }\n const existing = uniquesMap.get(uniqueRow.constraint_name);\n if (existing) {\n existing.columns.push(uniqueRow.column_name);\n } else {\n uniquesMap.set(uniqueRow.constraint_name, {\n columns: [uniqueRow.column_name],\n name: uniqueRow.constraint_name,\n });\n }\n }\n const uniques: readonly SqlUniqueIR[] = Array.from(uniquesMap.values()).map((uq) => ({\n columns: Object.freeze([...uq.columns]) as readonly string[],\n name: uq.name,\n }));\n\n // Process indexes\n const indexesMap = new Map<string, { columns: string[]; name: string; unique: boolean }>();\n for (const idxRow of indexesByTable.get(tableName) ?? []) {\n if (!idxRow.attname) {\n continue;\n }\n const existing = indexesMap.get(idxRow.indexname);\n if (existing) {\n existing.columns.push(idxRow.attname);\n } else {\n indexesMap.set(idxRow.indexname, {\n columns: [idxRow.attname],\n name: idxRow.indexname,\n unique: idxRow.indisunique,\n });\n }\n }\n const indexes: readonly SqlIndexIR[] = Array.from(indexesMap.values()).map((idx) => ({\n columns: Object.freeze([...idx.columns]) as readonly string[],\n name: idx.name,\n unique: idx.unique,\n }));\n\n tables[tableName] = {\n name: tableName,\n columns,\n ...ifDefined('primaryKey', primaryKey),\n foreignKeys,\n uniques,\n indexes,\n };\n }\n\n const extensions = extensionsResult.rows.map((row) => row.extname);\n\n const storageTypes =\n (await pgEnumControlHooks.introspectTypes?.({ driver, schemaName: schema })) ?? {};\n\n const annotations = {\n pg: {\n schema,\n version: await this.getPostgresVersion(driver),\n ...ifDefined(\n 'storageTypes',\n Object.keys(storageTypes).length > 0 ? storageTypes : undefined,\n ),\n },\n };\n\n return {\n tables,\n extensions,\n annotations,\n };\n }\n\n /**\n * Gets the Postgres version from the database.\n */\n private async getPostgresVersion(\n driver: ControlDriverInstance<'sql', 'postgres'>,\n ): Promise<string> {\n const result = await driver.query<{ version: string }>('SELECT version() AS version', []);\n const versionString = result.rows[0]?.version ?? '';\n // Extract version number from \"PostgreSQL 15.1 ...\" format\n const match = versionString.match(/PostgreSQL (\\d+\\.\\d+)/);\n return match?.[1] ?? 'unknown';\n }\n}\n\n/**\n * Pre-computed lookup map for simple prefix-based type normalization.\n * Maps short Postgres type names to their canonical SQL names.\n * Using a Map for O(1) lookup instead of multiple startsWith checks.\n */\nconst TYPE_PREFIX_MAP: ReadonlyMap<string, string> = new Map([\n ['varchar', 'character varying'],\n ['bpchar', 'character'],\n ['varbit', 'bit varying'],\n]);\n\n/**\n * Normalizes a Postgres schema native type to its canonical form for comparison.\n *\n * Uses a pre-computed lookup map for simple prefix replacements (O(1))\n * and handles complex temporal type normalization separately.\n */\nexport function normalizeSchemaNativeType(nativeType: string): string {\n const trimmed = nativeType.trim();\n\n // Fast path: check simple prefix replacements using the lookup map\n for (const [prefix, replacement] of TYPE_PREFIX_MAP) {\n if (trimmed.startsWith(prefix)) {\n return replacement + trimmed.slice(prefix.length);\n }\n }\n\n // Temporal types with time zone handling\n // Check for 'with time zone' suffix first (more specific)\n if (trimmed.includes(' with time zone')) {\n if (trimmed.startsWith('timestamp')) {\n return `timestamptz${trimmed.slice(9).replace(' with time zone', '')}`;\n }\n if (trimmed.startsWith('time')) {\n return `timetz${trimmed.slice(4).replace(' with time zone', '')}`;\n }\n }\n\n // Handle 'without time zone' suffix - just strip it\n if (trimmed.includes(' without time zone')) {\n return trimmed.replace(' without time zone', '');\n }\n\n return trimmed;\n}\n\nfunction normalizeFormattedType(formattedType: string, dataType: string, udtName: string): string {\n if (formattedType === 'integer') {\n return 'int4';\n }\n if (formattedType === 'smallint') {\n return 'int2';\n }\n if (formattedType === 'bigint') {\n return 'int8';\n }\n if (formattedType === 'real') {\n return 'float4';\n }\n if (formattedType === 'double precision') {\n return 'float8';\n }\n if (formattedType === 'boolean') {\n return 'bool';\n }\n if (formattedType.startsWith('varchar')) {\n return formattedType.replace('varchar', 'character varying');\n }\n if (formattedType.startsWith('bpchar')) {\n return formattedType.replace('bpchar', 'character');\n }\n if (formattedType.startsWith('varbit')) {\n return formattedType.replace('varbit', 'bit varying');\n }\n if (dataType === 'timestamp with time zone' || udtName === 'timestamptz') {\n return formattedType.replace('timestamp', 'timestamptz').replace(' with time zone', '').trim();\n }\n if (dataType === 'timestamp without time zone' || udtName === 'timestamp') {\n return formattedType.replace(' without time zone', '').trim();\n }\n if (dataType === 'time with time zone' || udtName === 'timetz') {\n return formattedType.replace('time', 'timetz').replace(' with time zone', '').trim();\n }\n if (dataType === 'time without time zone' || udtName === 'time') {\n return formattedType.replace(' without time zone', '').trim();\n }\n // Only dataType === 'USER-DEFINED' should ever be quoted, but this should be safe without\n // checking that explicitly either way\n if (formattedType.startsWith('\"') && formattedType.endsWith('\"')) {\n return formattedType.slice(1, -1);\n }\n return formattedType;\n}\n\n/**\n * The five standard PostgreSQL referential action rules as returned by\n * `information_schema.referential_constraints.delete_rule` / `update_rule`.\n */\ntype PgReferentialActionRule = 'NO ACTION' | 'RESTRICT' | 'CASCADE' | 'SET NULL' | 'SET DEFAULT';\n\nconst PG_REFERENTIAL_ACTION_MAP: Record<PgReferentialActionRule, SqlReferentialAction> = {\n 'NO ACTION': 'noAction',\n RESTRICT: 'restrict',\n CASCADE: 'cascade',\n 'SET NULL': 'setNull',\n 'SET DEFAULT': 'setDefault',\n};\n\n/**\n * Maps a Postgres referential action rule to the canonical SqlReferentialAction.\n * Returns undefined for 'NO ACTION' (the database default) to keep the IR sparse.\n * Throws for unrecognized rules to prevent silent data loss.\n */\nfunction mapReferentialAction(rule: string): SqlReferentialAction | undefined {\n const mapped = PG_REFERENTIAL_ACTION_MAP[rule as PgReferentialActionRule];\n if (mapped === undefined) {\n throw new Error(\n `Unknown PostgreSQL referential action rule: \"${rule}\". Expected one of: NO ACTION, RESTRICT, CASCADE, SET NULL, SET DEFAULT.`,\n );\n }\n if (mapped === 'noAction') return undefined;\n return mapped;\n}\n\n/**\n * Groups an array of objects by a specified key.\n * Returns a Map for O(1) lookup by group key.\n */\nfunction groupBy<T, K extends keyof T>(items: readonly T[], key: K): Map<T[K], T[]> {\n const map = new Map<T[K], T[]>();\n for (const item of items) {\n const groupKey = item[key];\n let group = map.get(groupKey);\n if (!group) {\n group = [];\n map.set(groupKey, group);\n }\n group.push(item);\n }\n return map;\n}\n","import type { SqlControlAdapterDescriptor } from '@prisma-next/family-sql/control';\nimport type { SqlControlAdapter } from '@prisma-next/family-sql/control-adapter';\nimport { PostgresControlAdapter } from '../core/control-adapter';\nimport { parsePostgresDefault } from '../core/default-normalizer';\nimport { postgresAdapterDescriptorMeta } from '../core/descriptor-meta';\nimport { expandParameterizedNativeType } from '../core/parameterized-types';\nimport { escapeLiteral, qualifyName, quoteIdentifier, SqlEscapeError } from '../core/sql-utils';\n\nconst postgresAdapterDescriptor: SqlControlAdapterDescriptor<'postgres'> = {\n ...postgresAdapterDescriptorMeta,\n operationSignatures: () => [],\n create(): SqlControlAdapter<'postgres'> {\n return new PostgresControlAdapter();\n },\n};\n\nexport default postgresAdapterDescriptor;\n\nexport { normalizeSchemaNativeType } from '../core/control-adapter';\nexport {\n escapeLiteral,\n expandParameterizedNativeType,\n parsePostgresDefault,\n qualifyName,\n quoteIdentifier,\n SqlEscapeError,\n};\n"],"mappings":"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"}
package/dist/runtime.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { m as PG_JSON_CODEC_ID, p as PG_JSONB_CODEC_ID } from "./codec-ids-Bsm9c7ns.mjs";
2
2
  import { t as codecDefinitions } from "./codecs-BfC_5c-4.mjs";
3
- import { t as createPostgresAdapter } from "./adapter-B5uYhMy7.mjs";
3
+ import { t as createPostgresAdapter } from "./adapter-DtehReRR.mjs";
4
4
  import { t as postgresAdapterDescriptorMeta } from "./descriptor-meta-ilnFI7bx.mjs";
5
5
  import { createCodecRegistry } from "@prisma-next/sql-relational-core/ast";
6
6
  import { type } from "arktype";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prisma-next/adapter-postgres",
3
- "version": "0.3.0-dev.41",
3
+ "version": "0.3.0-dev.44",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "files": [
@@ -10,19 +10,19 @@
10
10
  "dependencies": {
11
11
  "ajv": "^8.17.1",
12
12
  "arktype": "^2.0.0",
13
- "@prisma-next/contract": "0.3.0-dev.41",
14
- "@prisma-next/cli": "0.3.0-dev.41",
15
- "@prisma-next/contract-authoring": "0.3.0-dev.41",
16
- "@prisma-next/core-control-plane": "0.3.0-dev.41",
17
- "@prisma-next/core-execution-plane": "0.3.0-dev.41",
18
- "@prisma-next/family-sql": "0.3.0-dev.41",
19
- "@prisma-next/sql-contract": "0.3.0-dev.41",
20
- "@prisma-next/sql-contract-ts": "0.3.0-dev.41",
21
- "@prisma-next/sql-operations": "0.3.0-dev.41",
22
- "@prisma-next/sql-relational-core": "0.3.0-dev.41",
23
- "@prisma-next/sql-runtime": "0.3.0-dev.41",
24
- "@prisma-next/sql-schema-ir": "0.3.0-dev.41",
25
- "@prisma-next/utils": "0.3.0-dev.41"
13
+ "@prisma-next/cli": "0.3.0-dev.44",
14
+ "@prisma-next/contract": "0.3.0-dev.44",
15
+ "@prisma-next/contract-authoring": "0.3.0-dev.44",
16
+ "@prisma-next/core-control-plane": "0.3.0-dev.44",
17
+ "@prisma-next/core-execution-plane": "0.3.0-dev.44",
18
+ "@prisma-next/family-sql": "0.3.0-dev.44",
19
+ "@prisma-next/sql-contract": "0.3.0-dev.44",
20
+ "@prisma-next/sql-contract-ts": "0.3.0-dev.44",
21
+ "@prisma-next/sql-operations": "0.3.0-dev.44",
22
+ "@prisma-next/sql-runtime": "0.3.0-dev.44",
23
+ "@prisma-next/sql-schema-ir": "0.3.0-dev.44",
24
+ "@prisma-next/utils": "0.3.0-dev.44",
25
+ "@prisma-next/sql-relational-core": "0.3.0-dev.44"
26
26
  },
27
27
  "devDependencies": {
28
28
  "tsdown": "0.18.4",
@@ -8,6 +8,8 @@ import type {
8
8
  IncludeRef,
9
9
  InsertAst,
10
10
  JoinAst,
11
+ JoinOnExpr,
12
+ ListLiteralExpr,
11
13
  LiteralExpr,
12
14
  LowererContext,
13
15
  NullCheckExpr,
@@ -212,11 +214,41 @@ function renderNullCheck(expr: NullCheckExpr, contract?: PostgresContract): stri
212
214
  }
213
215
 
214
216
  function renderBinary(expr: BinaryExpr, contract?: PostgresContract): string {
217
+ if (expr.right.kind === 'listLiteral' && expr.right.values.length === 0) {
218
+ if (expr.op === 'in') {
219
+ return 'FALSE';
220
+ }
221
+ if (expr.op === 'notIn') {
222
+ return 'TRUE';
223
+ }
224
+ }
225
+
215
226
  const leftExpr = expr.left as ColumnRef | OperationExpr;
216
227
  const left = renderExpr(leftExpr, contract);
217
- // Only wrap in parentheses if it's an operation expression
218
228
  const leftRendered = isOperationExpr(leftExpr) ? `(${left})` : left;
219
- const right = renderBinaryRight(expr.right, contract);
229
+ const leftCol = leftExpr.kind === 'col' ? leftExpr : undefined;
230
+
231
+ const rightExpr = expr.right;
232
+ let right: string;
233
+ if (rightExpr.kind === 'listLiteral') {
234
+ right = renderListLiteral(
235
+ rightExpr as ListLiteralExpr,
236
+ contract,
237
+ leftCol?.table,
238
+ leftCol?.column,
239
+ );
240
+ } else if (rightExpr.kind === 'literal') {
241
+ right = renderLiteral(rightExpr);
242
+ } else if (rightExpr.kind === 'col') {
243
+ right = renderColumn(rightExpr);
244
+ } else if (rightExpr.kind === 'param') {
245
+ right = renderParam(rightExpr, contract, leftCol?.table, leftCol?.column);
246
+ } else if (rightExpr.kind === 'operation') {
247
+ right = renderOperation(rightExpr, contract);
248
+ } else {
249
+ right = renderColumn(rightExpr as ColumnRef);
250
+ }
251
+
220
252
  const operatorMap: Record<BinaryExpr['op'], string> = {
221
253
  eq: '=',
222
254
  neq: '!=',
@@ -233,30 +265,21 @@ function renderBinary(expr: BinaryExpr, contract?: PostgresContract): string {
233
265
  return `${leftRendered} ${operatorMap[expr.op]} ${right}`;
234
266
  }
235
267
 
236
- function renderBinaryRight(right: BinaryExpr['right'], contract?: PostgresContract): string {
237
- if (right.kind === 'col') {
238
- return renderColumn(right);
239
- }
240
- if (right.kind === 'param') {
241
- return renderParam(right, contract);
242
- }
243
- if (right.kind === 'literal') {
244
- return renderLiteral(right);
245
- }
246
- if (right.kind === 'operation') {
247
- return renderExpr(right, contract);
248
- }
249
- if (right.kind === 'listLiteral') {
250
- if (right.values.length === 0) {
251
- return '(NULL)';
252
- }
253
- const values = right.values.map((value) =>
254
- value.kind === 'param' ? renderParam(value, contract) : renderLiteral(value),
255
- );
256
- return `(${values.join(', ')})`;
268
+ function renderListLiteral(
269
+ expr: ListLiteralExpr,
270
+ contract?: PostgresContract,
271
+ tableName?: string,
272
+ columnName?: string,
273
+ ): string {
274
+ if (expr.values.length === 0) {
275
+ return '(NULL)';
257
276
  }
258
-
259
- throw new Error(`Unsupported binary right expression kind: ${(right as { kind: string }).kind}`);
277
+ const values = expr.values
278
+ .map((v) =>
279
+ v.kind === 'param' ? renderParam(v, contract, tableName, columnName) : renderLiteral(v),
280
+ )
281
+ .join(', ');
282
+ return `(${values})`;
260
283
  }
261
284
 
262
285
  function renderColumn(ref: ColumnRef): string {
@@ -335,20 +358,20 @@ function renderOperation(expr: OperationExpr, contract?: PostgresContract): stri
335
358
  return result;
336
359
  }
337
360
 
338
- function renderJoin(join: JoinAst, _contract?: PostgresContract): string {
361
+ function renderJoin(join: JoinAst, contract?: PostgresContract): string {
339
362
  const joinType = join.joinType.toUpperCase();
340
363
  const table = quoteIdentifier(join.table.name);
341
- const onClause = renderJoinOn(join.on);
364
+ const onClause = renderJoinOn(join.on, contract);
342
365
  return `${joinType} JOIN ${table} ON ${onClause}`;
343
366
  }
344
367
 
345
- function renderJoinOn(on: JoinAst['on']): string {
368
+ function renderJoinOn(on: JoinOnExpr, contract?: PostgresContract): string {
346
369
  if (on.kind === 'eqCol') {
347
370
  const left = renderColumn(on.left);
348
371
  const right = renderColumn(on.right);
349
372
  return `${left} = ${right}`;
350
373
  }
351
- throw new Error(`Unsupported join ON expression kind: ${on.kind}`);
374
+ return renderWhere(on, contract);
352
375
  }
353
376
 
354
377
  function renderInclude(
@@ -368,7 +391,7 @@ function renderInclude(
368
391
  const jsonBuildObject = `json_build_object(${childProjection})`;
369
392
 
370
393
  // Build the ON condition from the include's ON clause - this goes in the WHERE clause
371
- const onCondition = renderJoinOn(include.child.on);
394
+ const onCondition = renderJoinOn(include.child.on, contract);
372
395
 
373
396
  // Build WHERE clause: combine ON condition with any additional WHERE clauses
374
397
  let whereClause = ` WHERE ${onCondition}`;
@@ -494,7 +517,7 @@ function renderUpdate(ast: UpdateAst, contract: PostgresContract): string {
494
517
  return `${column} = ${value}`;
495
518
  });
496
519
 
497
- const whereClause = ` WHERE ${renderWhere(ast.where, contract)}`;
520
+ const whereClause = ast.where ? ` WHERE ${renderWhere(ast.where, contract)}` : '';
498
521
  const returningClause = ast.returning?.length
499
522
  ? ` RETURNING ${ast.returning.map((col) => `${quoteIdentifier(col.table)}.${quoteIdentifier(col.column)}`).join(', ')}`
500
523
  : '';
@@ -504,7 +527,7 @@ function renderUpdate(ast: UpdateAst, contract: PostgresContract): string {
504
527
 
505
528
  function renderDelete(ast: DeleteAst, contract?: PostgresContract): string {
506
529
  const table = quoteIdentifier(ast.table.name);
507
- const whereClause = ` WHERE ${renderWhere(ast.where, contract)}`;
530
+ const whereClause = ast.where ? ` WHERE ${renderWhere(ast.where, contract)}` : '';
508
531
  const returningClause = ast.returning?.length
509
532
  ? ` RETURNING ${ast.returning.map((col) => `${quoteIdentifier(col.table)}.${quoteIdentifier(col.column)}`).join(', ')}`
510
533
  : '';
@@ -5,6 +5,7 @@ import type {
5
5
  SqlColumnIR,
6
6
  SqlForeignKeyIR,
7
7
  SqlIndexIR,
8
+ SqlReferentialAction,
8
9
  SqlSchemaIR,
9
10
  SqlTableIR,
10
11
  SqlUniqueIR,
@@ -137,7 +138,10 @@ export class PostgresControlAdapter implements SqlControlAdapter<'postgres'> {
137
138
  ORDER BY tc.table_name, kcu.ordinal_position`,
138
139
  [schema],
139
140
  ),
140
- // Query all foreign keys for all tables in schema
141
+ // Query all foreign keys for all tables in schema, including referential actions.
142
+ // Uses pg_catalog for correct positional pairing of composite FK columns
143
+ // (information_schema.constraint_column_usage lacks ordinal_position,
144
+ // which causes Cartesian products for multi-column FKs).
141
145
  driver.query<{
142
146
  table_name: string;
143
147
  constraint_name: string;
@@ -146,23 +150,39 @@ export class PostgresControlAdapter implements SqlControlAdapter<'postgres'> {
146
150
  referenced_table_schema: string;
147
151
  referenced_table_name: string;
148
152
  referenced_column_name: string;
153
+ delete_rule: string;
154
+ update_rule: string;
149
155
  }>(
150
156
  `SELECT
151
157
  tc.table_name,
152
158
  tc.constraint_name,
153
159
  kcu.column_name,
154
160
  kcu.ordinal_position,
155
- ccu.table_schema AS referenced_table_schema,
156
- ccu.table_name AS referenced_table_name,
157
- ccu.column_name AS referenced_column_name
161
+ ref_ns.nspname AS referenced_table_schema,
162
+ ref_cl.relname AS referenced_table_name,
163
+ ref_att.attname AS referenced_column_name,
164
+ rc.delete_rule,
165
+ rc.update_rule
158
166
  FROM information_schema.table_constraints tc
159
167
  JOIN information_schema.key_column_usage kcu
160
168
  ON tc.constraint_name = kcu.constraint_name
161
169
  AND tc.table_schema = kcu.table_schema
162
170
  AND tc.table_name = kcu.table_name
163
- JOIN information_schema.constraint_column_usage ccu
164
- ON ccu.constraint_name = tc.constraint_name
165
- AND ccu.table_schema = tc.table_schema
171
+ JOIN pg_catalog.pg_constraint pgc
172
+ ON pgc.conname = tc.constraint_name
173
+ AND pgc.connamespace = (
174
+ SELECT oid FROM pg_catalog.pg_namespace WHERE nspname = tc.table_schema
175
+ )
176
+ JOIN pg_catalog.pg_class ref_cl
177
+ ON ref_cl.oid = pgc.confrelid
178
+ JOIN pg_catalog.pg_namespace ref_ns
179
+ ON ref_ns.oid = ref_cl.relnamespace
180
+ JOIN pg_catalog.pg_attribute ref_att
181
+ ON ref_att.attrelid = pgc.confrelid
182
+ AND ref_att.attnum = pgc.confkey[kcu.ordinal_position]
183
+ JOIN information_schema.referential_constraints rc
184
+ ON rc.constraint_name = tc.constraint_name
185
+ AND rc.constraint_schema = tc.table_schema
166
186
  WHERE tc.table_schema = $1
167
187
  AND tc.constraint_type = 'FOREIGN KEY'
168
188
  ORDER BY tc.table_name, tc.constraint_name, kcu.ordinal_position`,
@@ -305,7 +325,14 @@ export class PostgresControlAdapter implements SqlControlAdapter<'postgres'> {
305
325
  // Process foreign keys
306
326
  const foreignKeysMap = new Map<
307
327
  string,
308
- { columns: string[]; referencedTable: string; referencedColumns: string[]; name: string }
328
+ {
329
+ columns: string[];
330
+ referencedTable: string;
331
+ referencedColumns: string[];
332
+ name: string;
333
+ deleteRule: string;
334
+ updateRule: string;
335
+ }
309
336
  >();
310
337
  for (const fkRow of fksByTable.get(tableName) ?? []) {
311
338
  const existing = foreignKeysMap.get(fkRow.constraint_name);
@@ -318,6 +345,8 @@ export class PostgresControlAdapter implements SqlControlAdapter<'postgres'> {
318
345
  referencedTable: fkRow.referenced_table_name,
319
346
  referencedColumns: [fkRow.referenced_column_name],
320
347
  name: fkRow.constraint_name,
348
+ deleteRule: fkRow.delete_rule,
349
+ updateRule: fkRow.update_rule,
321
350
  });
322
351
  }
323
352
  }
@@ -327,6 +356,8 @@ export class PostgresControlAdapter implements SqlControlAdapter<'postgres'> {
327
356
  referencedTable: fk.referencedTable,
328
357
  referencedColumns: Object.freeze([...fk.referencedColumns]) as readonly string[],
329
358
  name: fk.name,
359
+ ...ifDefined('onDelete', mapReferentialAction(fk.deleteRule)),
360
+ ...ifDefined('onUpdate', mapReferentialAction(fk.updateRule)),
330
361
  }),
331
362
  );
332
363
 
@@ -517,6 +548,36 @@ function normalizeFormattedType(formattedType: string, dataType: string, udtName
517
548
  return formattedType;
518
549
  }
519
550
 
551
+ /**
552
+ * The five standard PostgreSQL referential action rules as returned by
553
+ * `information_schema.referential_constraints.delete_rule` / `update_rule`.
554
+ */
555
+ type PgReferentialActionRule = 'NO ACTION' | 'RESTRICT' | 'CASCADE' | 'SET NULL' | 'SET DEFAULT';
556
+
557
+ const PG_REFERENTIAL_ACTION_MAP: Record<PgReferentialActionRule, SqlReferentialAction> = {
558
+ 'NO ACTION': 'noAction',
559
+ RESTRICT: 'restrict',
560
+ CASCADE: 'cascade',
561
+ 'SET NULL': 'setNull',
562
+ 'SET DEFAULT': 'setDefault',
563
+ };
564
+
565
+ /**
566
+ * Maps a Postgres referential action rule to the canonical SqlReferentialAction.
567
+ * Returns undefined for 'NO ACTION' (the database default) to keep the IR sparse.
568
+ * Throws for unrecognized rules to prevent silent data loss.
569
+ */
570
+ function mapReferentialAction(rule: string): SqlReferentialAction | undefined {
571
+ const mapped = PG_REFERENTIAL_ACTION_MAP[rule as PgReferentialActionRule];
572
+ if (mapped === undefined) {
573
+ throw new Error(
574
+ `Unknown PostgreSQL referential action rule: "${rule}". Expected one of: NO ACTION, RESTRICT, CASCADE, SET NULL, SET DEFAULT.`,
575
+ );
576
+ }
577
+ if (mapped === 'noAction') return undefined;
578
+ return mapped;
579
+ }
580
+
520
581
  /**
521
582
  * Groups an array of objects by a specified key.
522
583
  * Returns a Map for O(1) lookup by group key.
@@ -1 +0,0 @@
1
- {"version":3,"file":"adapter-B5uYhMy7.mjs","names":["parameterizedCodecs: ReadonlyArray<CodecParamsDescriptor>","codec","sql: string","_exhaustive: never","subquery: string","alias","value: string"],"sources":["../src/core/adapter.ts"],"sourcesContent":["import type {\n Adapter,\n AdapterProfile,\n BinaryExpr,\n CodecParamsDescriptor,\n ColumnRef,\n DeleteAst,\n IncludeRef,\n InsertAst,\n JoinAst,\n LiteralExpr,\n LowererContext,\n NullCheckExpr,\n OperationExpr,\n ParamRef,\n QueryAst,\n SelectAst,\n UpdateAst,\n WhereExpr,\n} from '@prisma-next/sql-relational-core/ast';\nimport { createCodecRegistry, isOperationExpr } from '@prisma-next/sql-relational-core/ast';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { PG_JSON_CODEC_ID, PG_JSONB_CODEC_ID } from './codec-ids';\nimport { codecDefinitions } from './codecs';\nimport { escapeLiteral } from './sql-utils';\nimport type { PostgresAdapterOptions, PostgresContract, PostgresLoweredStatement } from './types';\n\nconst VECTOR_CODEC_ID = 'pg/vector@1' as const;\n\nfunction getCodecParamCast(codecId: string | undefined): string | undefined {\n if (codecId === VECTOR_CODEC_ID) {\n return 'vector';\n }\n if (codecId === PG_JSON_CODEC_ID) {\n return 'json';\n }\n if (codecId === PG_JSONB_CODEC_ID) {\n return 'jsonb';\n }\n return undefined;\n}\n\nfunction renderTypedParam(index: number, codecId: string | undefined): string {\n const cast = getCodecParamCast(codecId);\n return cast ? `$${index}::${cast}` : `$${index}`;\n}\n\nconst defaultCapabilities = Object.freeze({\n postgres: {\n orderBy: true,\n limit: true,\n lateral: true,\n jsonAgg: true,\n returning: true,\n },\n sql: {\n enums: true,\n },\n});\n\ntype AdapterCodec = (typeof codecDefinitions)[keyof typeof codecDefinitions]['codec'];\ntype ParameterizedCodec = AdapterCodec & {\n readonly paramsSchema: NonNullable<AdapterCodec['paramsSchema']>;\n};\n\nconst parameterizedCodecs: ReadonlyArray<CodecParamsDescriptor> = Object.values(codecDefinitions)\n .map((definition) => definition.codec)\n .filter((codec): codec is ParameterizedCodec => codec.paramsSchema !== undefined)\n .map((codec) =>\n Object.freeze({\n codecId: codec.id,\n paramsSchema: codec.paramsSchema,\n ...ifDefined('init', codec.init),\n }),\n );\n\nclass PostgresAdapterImpl implements Adapter<QueryAst, PostgresContract, PostgresLoweredStatement> {\n // These fields make the adapter instance structurally compatible with\n // RuntimeAdapterInstance<'sql', 'postgres'> without introducing a runtime-plane dependency.\n readonly familyId = 'sql' as const;\n readonly targetId = 'postgres' as const;\n\n readonly profile: AdapterProfile<'postgres'>;\n private readonly codecRegistry = (() => {\n const registry = createCodecRegistry();\n for (const definition of Object.values(codecDefinitions)) {\n registry.register(definition.codec);\n }\n return registry;\n })();\n\n constructor(options?: PostgresAdapterOptions) {\n this.profile = Object.freeze({\n id: options?.profileId ?? 'postgres/default@1',\n target: 'postgres',\n capabilities: defaultCapabilities,\n codecs: () => this.codecRegistry,\n });\n }\n\n parameterizedCodecs(): ReadonlyArray<CodecParamsDescriptor> {\n return parameterizedCodecs;\n }\n\n lower(ast: QueryAst, context: LowererContext<PostgresContract>) {\n let sql: string;\n const params = context.params ? [...context.params] : [];\n\n if (ast.kind === 'select') {\n sql = renderSelect(ast, context.contract);\n } else if (ast.kind === 'insert') {\n sql = renderInsert(ast, context.contract);\n } else if (ast.kind === 'update') {\n sql = renderUpdate(ast, context.contract);\n } else if (ast.kind === 'delete') {\n sql = renderDelete(ast, context.contract);\n } else {\n throw new Error(`Unsupported AST kind: ${(ast as { kind: string }).kind}`);\n }\n\n return Object.freeze({\n profileId: this.profile.id,\n body: Object.freeze({ sql, params }),\n });\n }\n}\n\nfunction renderSelect(ast: SelectAst, contract?: PostgresContract): string {\n const selectClause = `SELECT ${renderProjection(ast, contract)}`;\n const fromClause = `FROM ${quoteIdentifier(ast.from.name)}`;\n\n const joinsClause = ast.joins?.length\n ? ast.joins.map((join) => renderJoin(join, contract)).join(' ')\n : '';\n const includesClause = ast.includes?.length\n ? ast.includes.map((include) => renderInclude(include, contract)).join(' ')\n : '';\n\n const whereClause = ast.where ? ` WHERE ${renderWhere(ast.where, contract)}` : '';\n const orderClause = ast.orderBy?.length\n ? ` ORDER BY ${ast.orderBy\n .map((order) => {\n const expr = renderExpr(order.expr as ColumnRef | OperationExpr, contract);\n return `${expr} ${order.dir.toUpperCase()}`;\n })\n .join(', ')}`\n : '';\n const limitClause = typeof ast.limit === 'number' ? ` LIMIT ${ast.limit}` : '';\n\n const clauses = [joinsClause, includesClause].filter(Boolean).join(' ');\n return `${selectClause} ${fromClause}${clauses ? ` ${clauses}` : ''}${whereClause}${orderClause}${limitClause}`.trim();\n}\n\nfunction renderProjection(ast: SelectAst, contract?: PostgresContract): string {\n return ast.project\n .map((item) => {\n const expr = item.expr as ColumnRef | IncludeRef | OperationExpr | LiteralExpr;\n if (expr.kind === 'includeRef') {\n // For include references, select the column from the LATERAL join alias\n // The LATERAL subquery returns a single column (the JSON array) with the alias\n // The table is aliased as {alias}_lateral, and the column inside is aliased as the include alias\n // We select it using table_alias.column_alias\n const tableAlias = `${expr.alias}_lateral`;\n return `${quoteIdentifier(tableAlias)}.${quoteIdentifier(expr.alias)} AS ${quoteIdentifier(item.alias)}`;\n }\n if (expr.kind === 'operation') {\n const operation = renderOperation(expr, contract);\n const alias = quoteIdentifier(item.alias);\n return `${operation} AS ${alias}`;\n }\n if (expr.kind === 'literal') {\n const literal = renderLiteral(expr);\n const alias = quoteIdentifier(item.alias);\n return `${literal} AS ${alias}`;\n }\n const column = renderColumn(expr as ColumnRef);\n const alias = quoteIdentifier(item.alias);\n return `${column} AS ${alias}`;\n })\n .join(', ');\n}\n\nfunction renderWhere(expr: WhereExpr, contract?: PostgresContract): string {\n if (expr.kind === 'exists') {\n const notKeyword = expr.not ? 'NOT ' : '';\n const subquery = renderSelect(expr.subquery, contract);\n return `${notKeyword}EXISTS (${subquery})`;\n }\n if (expr.kind === 'nullCheck') {\n return renderNullCheck(expr, contract);\n }\n if (expr.kind === 'and') {\n if (expr.exprs.length === 0) {\n return 'TRUE';\n }\n return `(${expr.exprs.map((part) => renderWhere(part, contract)).join(' AND ')})`;\n }\n if (expr.kind === 'or') {\n if (expr.exprs.length === 0) {\n return 'FALSE';\n }\n return `(${expr.exprs.map((part) => renderWhere(part, contract)).join(' OR ')})`;\n }\n return renderBinary(expr, contract);\n}\n\nfunction renderNullCheck(expr: NullCheckExpr, contract?: PostgresContract): string {\n const rendered = renderExpr(expr.expr as ColumnRef | OperationExpr, contract);\n // Only wrap in parentheses if it's an operation expression\n const renderedExpr = isOperationExpr(expr.expr) ? `(${rendered})` : rendered;\n return expr.isNull ? `${renderedExpr} IS NULL` : `${renderedExpr} IS NOT NULL`;\n}\n\nfunction renderBinary(expr: BinaryExpr, contract?: PostgresContract): string {\n const leftExpr = expr.left as ColumnRef | OperationExpr;\n const left = renderExpr(leftExpr, contract);\n // Only wrap in parentheses if it's an operation expression\n const leftRendered = isOperationExpr(leftExpr) ? `(${left})` : left;\n const right = renderBinaryRight(expr.right, contract);\n const operatorMap: Record<BinaryExpr['op'], string> = {\n eq: '=',\n neq: '!=',\n gt: '>',\n lt: '<',\n gte: '>=',\n lte: '<=',\n like: 'LIKE',\n ilike: 'ILIKE',\n in: 'IN',\n notIn: 'NOT IN',\n };\n\n return `${leftRendered} ${operatorMap[expr.op]} ${right}`;\n}\n\nfunction renderBinaryRight(right: BinaryExpr['right'], contract?: PostgresContract): string {\n if (right.kind === 'col') {\n return renderColumn(right);\n }\n if (right.kind === 'param') {\n return renderParam(right, contract);\n }\n if (right.kind === 'literal') {\n return renderLiteral(right);\n }\n if (right.kind === 'operation') {\n return renderExpr(right, contract);\n }\n if (right.kind === 'listLiteral') {\n if (right.values.length === 0) {\n return '(NULL)';\n }\n const values = right.values.map((value) =>\n value.kind === 'param' ? renderParam(value, contract) : renderLiteral(value),\n );\n return `(${values.join(', ')})`;\n }\n\n throw new Error(`Unsupported binary right expression kind: ${(right as { kind: string }).kind}`);\n}\n\nfunction renderColumn(ref: ColumnRef): string {\n return `${quoteIdentifier(ref.table)}.${quoteIdentifier(ref.column)}`;\n}\n\nfunction renderExpr(expr: ColumnRef | OperationExpr, contract?: PostgresContract): string {\n if (isOperationExpr(expr)) {\n return renderOperation(expr, contract);\n }\n return renderColumn(expr);\n}\n\nfunction renderParam(\n ref: ParamRef,\n contract?: PostgresContract,\n tableName?: string,\n columnName?: string,\n): string {\n if (contract && tableName && columnName) {\n const tableMeta = contract.storage.tables[tableName];\n const columnMeta = tableMeta?.columns[columnName];\n return renderTypedParam(ref.index, columnMeta?.codecId);\n }\n return `$${ref.index}`;\n}\n\nfunction renderLiteral(expr: LiteralExpr): string {\n if (typeof expr.value === 'string') {\n return `'${escapeLiteral(expr.value)}'`;\n }\n if (typeof expr.value === 'number' || typeof expr.value === 'boolean') {\n return String(expr.value);\n }\n if (expr.value === null) {\n return 'NULL';\n }\n if (Array.isArray(expr.value)) {\n return `ARRAY[${expr.value.map((v: unknown) => renderLiteral({ kind: 'literal', value: v })).join(', ')}]`;\n }\n return JSON.stringify(expr.value);\n}\n\nfunction renderOperation(expr: OperationExpr, contract?: PostgresContract): string {\n const self = renderExpr(expr.self, contract);\n // For vector operations, cast param arguments to vector type\n const isVectorOperation = expr.forTypeId === VECTOR_CODEC_ID;\n const args = expr.args.map((arg: ColumnRef | ParamRef | LiteralExpr | OperationExpr) => {\n if (arg.kind === 'col') {\n return renderColumn(arg);\n }\n if (arg.kind === 'param') {\n // Cast vector operation parameters to vector type\n return isVectorOperation ? `$${arg.index}::vector` : renderParam(arg, contract);\n }\n if (arg.kind === 'literal') {\n return renderLiteral(arg);\n }\n if (arg.kind === 'operation') {\n return renderOperation(arg, contract);\n }\n const _exhaustive: never = arg;\n throw new Error(`Unsupported argument kind: ${(_exhaustive as { kind: string }).kind}`);\n });\n\n let result = expr.lowering.template;\n result = result.replace(/\\$\\{self\\}/g, self);\n for (let i = 0; i < args.length; i++) {\n result = result.replace(new RegExp(`\\\\$\\\\{arg${i}\\\\}`, 'g'), args[i] ?? '');\n }\n\n if (expr.lowering.strategy === 'function') {\n return result;\n }\n\n return result;\n}\n\nfunction renderJoin(join: JoinAst, _contract?: PostgresContract): string {\n const joinType = join.joinType.toUpperCase();\n const table = quoteIdentifier(join.table.name);\n const onClause = renderJoinOn(join.on);\n return `${joinType} JOIN ${table} ON ${onClause}`;\n}\n\nfunction renderJoinOn(on: JoinAst['on']): string {\n if (on.kind === 'eqCol') {\n const left = renderColumn(on.left);\n const right = renderColumn(on.right);\n return `${left} = ${right}`;\n }\n throw new Error(`Unsupported join ON expression kind: ${on.kind}`);\n}\n\nfunction renderInclude(\n include: NonNullable<SelectAst['includes']>[number],\n contract?: PostgresContract,\n): string {\n const alias = include.alias;\n\n // Build the lateral subquery\n const childProjection = include.child.project\n .map((item: { alias: string; expr: ColumnRef | OperationExpr }) => {\n const expr = renderExpr(item.expr, contract);\n return `'${item.alias}', ${expr}`;\n })\n .join(', ');\n\n const jsonBuildObject = `json_build_object(${childProjection})`;\n\n // Build the ON condition from the include's ON clause - this goes in the WHERE clause\n const onCondition = renderJoinOn(include.child.on);\n\n // Build WHERE clause: combine ON condition with any additional WHERE clauses\n let whereClause = ` WHERE ${onCondition}`;\n if (include.child.where) {\n whereClause += ` AND ${renderWhere(include.child.where, contract)}`;\n }\n\n // Add ORDER BY if present - it goes inside json_agg() call\n const childOrderBy = include.child.orderBy?.length\n ? ` ORDER BY ${include.child.orderBy\n .map(\n (order: { expr: ColumnRef | OperationExpr; dir: string }) =>\n `${renderExpr(order.expr, contract)} ${order.dir.toUpperCase()}`,\n )\n .join(', ')}`\n : '';\n\n // Add LIMIT if present\n const childLimit = typeof include.child.limit === 'number' ? ` LIMIT ${include.child.limit}` : '';\n\n // Build the lateral subquery\n // When ORDER BY is present without LIMIT, it goes inside json_agg() call: json_agg(expr ORDER BY ...)\n // When LIMIT is present (with or without ORDER BY), we need to wrap in a subquery\n const childTable = quoteIdentifier(include.child.table.name);\n let subquery: string;\n if (typeof include.child.limit === 'number') {\n // With LIMIT, we need to wrap in a subquery\n // Select individual columns in inner query, then aggregate\n // Create a map of column references to their aliases for ORDER BY\n // Only ColumnRef can be mapped (OperationExpr doesn't have table/column properties)\n const columnAliasMap = new Map<string, string>();\n for (const item of include.child.project) {\n if (item.expr.kind === 'col') {\n const columnKey = `${item.expr.table}.${item.expr.column}`;\n columnAliasMap.set(columnKey, item.alias);\n }\n }\n\n const innerColumns = include.child.project\n .map((item: { alias: string; expr: ColumnRef | OperationExpr }) => {\n const expr = renderExpr(item.expr, contract);\n return `${expr} AS ${quoteIdentifier(item.alias)}`;\n })\n .join(', ');\n\n // For ORDER BY, use column aliases if the column is in the SELECT list\n const childOrderByWithAliases = include.child.orderBy?.length\n ? ` ORDER BY ${include.child.orderBy\n .map((order: { expr: ColumnRef | OperationExpr; dir: string }) => {\n if (order.expr.kind === 'col') {\n const columnKey = `${order.expr.table}.${order.expr.column}`;\n const alias = columnAliasMap.get(columnKey);\n if (alias) {\n return `${quoteIdentifier(alias)} ${order.dir.toUpperCase()}`;\n }\n }\n return `${renderExpr(order.expr, contract)} ${order.dir.toUpperCase()}`;\n })\n .join(', ')}`\n : '';\n\n const innerSelect = `SELECT ${innerColumns} FROM ${childTable}${whereClause}${childOrderByWithAliases}${childLimit}`;\n subquery = `(SELECT json_agg(row_to_json(sub.*)) AS ${quoteIdentifier(alias)} FROM (${innerSelect}) sub)`;\n } else if (childOrderBy) {\n // With ORDER BY but no LIMIT, ORDER BY goes inside json_agg()\n subquery = `(SELECT json_agg(${jsonBuildObject}${childOrderBy}) AS ${quoteIdentifier(alias)} FROM ${childTable}${whereClause})`;\n } else {\n // No ORDER BY or LIMIT\n subquery = `(SELECT json_agg(${jsonBuildObject}) AS ${quoteIdentifier(alias)} FROM ${childTable}${whereClause})`;\n }\n\n // Return the LATERAL join with ON true (the condition is in the WHERE clause)\n // The subquery returns a single column (the JSON array) with the alias\n // We use a different alias for the table to avoid ambiguity when selecting the column\n const tableAlias = `${alias}_lateral`;\n return `LEFT JOIN LATERAL ${subquery} AS ${quoteIdentifier(tableAlias)} ON true`;\n}\n\nfunction quoteIdentifier(identifier: string): string {\n return `\"${identifier.replace(/\"/g, '\"\"')}\"`;\n}\n\nfunction renderInsert(ast: InsertAst, contract: PostgresContract): string {\n const table = quoteIdentifier(ast.table.name);\n const columns = Object.keys(ast.values).map((col) => quoteIdentifier(col));\n const tableMeta = contract.storage.tables[ast.table.name];\n const values = Object.entries(ast.values).map(([colName, val]) => {\n if (val.kind === 'param') {\n const columnMeta = tableMeta?.columns[colName];\n return renderTypedParam(val.index, columnMeta?.codecId);\n }\n if (val.kind === 'col') {\n return `${quoteIdentifier(val.table)}.${quoteIdentifier(val.column)}`;\n }\n throw new Error(`Unsupported value kind in INSERT: ${(val as { kind: string }).kind}`);\n });\n\n const insertClause =\n columns.length === 0\n ? `INSERT INTO ${table} DEFAULT VALUES`\n : `INSERT INTO ${table} (${columns.join(', ')}) VALUES (${values.join(', ')})`;\n const returningClause = ast.returning?.length\n ? ` RETURNING ${ast.returning.map((col) => `${quoteIdentifier(col.table)}.${quoteIdentifier(col.column)}`).join(', ')}`\n : '';\n\n return `${insertClause}${returningClause}`;\n}\n\nfunction renderUpdate(ast: UpdateAst, contract: PostgresContract): string {\n const table = quoteIdentifier(ast.table.name);\n const tableMeta = contract.storage.tables[ast.table.name];\n const setClauses = Object.entries(ast.set).map(([col, val]) => {\n const column = quoteIdentifier(col);\n let value: string;\n if (val.kind === 'param') {\n const columnMeta = tableMeta?.columns[col];\n value = renderTypedParam(val.index, columnMeta?.codecId);\n } else if (val.kind === 'col') {\n value = `${quoteIdentifier(val.table)}.${quoteIdentifier(val.column)}`;\n } else {\n throw new Error(`Unsupported value kind in UPDATE: ${(val as { kind: string }).kind}`);\n }\n return `${column} = ${value}`;\n });\n\n const whereClause = ` WHERE ${renderWhere(ast.where, contract)}`;\n const returningClause = ast.returning?.length\n ? ` RETURNING ${ast.returning.map((col) => `${quoteIdentifier(col.table)}.${quoteIdentifier(col.column)}`).join(', ')}`\n : '';\n\n return `UPDATE ${table} SET ${setClauses.join(', ')}${whereClause}${returningClause}`;\n}\n\nfunction renderDelete(ast: DeleteAst, contract?: PostgresContract): string {\n const table = quoteIdentifier(ast.table.name);\n const whereClause = ` WHERE ${renderWhere(ast.where, contract)}`;\n const returningClause = ast.returning?.length\n ? ` RETURNING ${ast.returning.map((col) => `${quoteIdentifier(col.table)}.${quoteIdentifier(col.column)}`).join(', ')}`\n : '';\n\n return `DELETE FROM ${table}${whereClause}${returningClause}`;\n}\n\nexport function createPostgresAdapter(options?: PostgresAdapterOptions) {\n return Object.freeze(new PostgresAdapterImpl(options));\n}\n"],"mappings":";;;;;;;AA2BA,MAAM,kBAAkB;AAExB,SAAS,kBAAkB,SAAiD;AAC1E,KAAI,YAAY,gBACd,QAAO;AAET,KAAI,YAAY,iBACd,QAAO;AAET,KAAI,YAAY,kBACd,QAAO;;AAKX,SAAS,iBAAiB,OAAe,SAAqC;CAC5E,MAAM,OAAO,kBAAkB,QAAQ;AACvC,QAAO,OAAO,IAAI,MAAM,IAAI,SAAS,IAAI;;AAG3C,MAAM,sBAAsB,OAAO,OAAO;CACxC,UAAU;EACR,SAAS;EACT,OAAO;EACP,SAAS;EACT,SAAS;EACT,WAAW;EACZ;CACD,KAAK,EACH,OAAO,MACR;CACF,CAAC;AAOF,MAAMA,sBAA4D,OAAO,OAAO,iBAAiB,CAC9F,KAAK,eAAe,WAAW,MAAM,CACrC,QAAQ,YAAuCC,QAAM,iBAAiB,OAAU,CAChF,KAAK,YACJ,OAAO,OAAO;CACZ,SAASA,QAAM;CACf,cAAcA,QAAM;CACpB,GAAG,UAAU,QAAQA,QAAM,KAAK;CACjC,CAAC,CACH;AAEH,IAAM,sBAAN,MAAmG;CAGjG,AAAS,WAAW;CACpB,AAAS,WAAW;CAEpB,AAAS;CACT,AAAiB,uBAAuB;EACtC,MAAM,WAAW,qBAAqB;AACtC,OAAK,MAAM,cAAc,OAAO,OAAO,iBAAiB,CACtD,UAAS,SAAS,WAAW,MAAM;AAErC,SAAO;KACL;CAEJ,YAAY,SAAkC;AAC5C,OAAK,UAAU,OAAO,OAAO;GAC3B,IAAI,SAAS,aAAa;GAC1B,QAAQ;GACR,cAAc;GACd,cAAc,KAAK;GACpB,CAAC;;CAGJ,sBAA4D;AAC1D,SAAO;;CAGT,MAAM,KAAe,SAA2C;EAC9D,IAAIC;EACJ,MAAM,SAAS,QAAQ,SAAS,CAAC,GAAG,QAAQ,OAAO,GAAG,EAAE;AAExD,MAAI,IAAI,SAAS,SACf,OAAM,aAAa,KAAK,QAAQ,SAAS;WAChC,IAAI,SAAS,SACtB,OAAM,aAAa,KAAK,QAAQ,SAAS;WAChC,IAAI,SAAS,SACtB,OAAM,aAAa,KAAK,QAAQ,SAAS;WAChC,IAAI,SAAS,SACtB,OAAM,aAAa,KAAK,QAAQ,SAAS;MAEzC,OAAM,IAAI,MAAM,yBAA0B,IAAyB,OAAO;AAG5E,SAAO,OAAO,OAAO;GACnB,WAAW,KAAK,QAAQ;GACxB,MAAM,OAAO,OAAO;IAAE;IAAK;IAAQ,CAAC;GACrC,CAAC;;;AAIN,SAAS,aAAa,KAAgB,UAAqC;CACzE,MAAM,eAAe,UAAU,iBAAiB,KAAK,SAAS;CAC9D,MAAM,aAAa,QAAQ,gBAAgB,IAAI,KAAK,KAAK;CAEzD,MAAM,cAAc,IAAI,OAAO,SAC3B,IAAI,MAAM,KAAK,SAAS,WAAW,MAAM,SAAS,CAAC,CAAC,KAAK,IAAI,GAC7D;CACJ,MAAM,iBAAiB,IAAI,UAAU,SACjC,IAAI,SAAS,KAAK,YAAY,cAAc,SAAS,SAAS,CAAC,CAAC,KAAK,IAAI,GACzE;CAEJ,MAAM,cAAc,IAAI,QAAQ,UAAU,YAAY,IAAI,OAAO,SAAS,KAAK;CAC/E,MAAM,cAAc,IAAI,SAAS,SAC7B,aAAa,IAAI,QACd,KAAK,UAAU;AAEd,SAAO,GADM,WAAW,MAAM,MAAmC,SAAS,CAC3D,GAAG,MAAM,IAAI,aAAa;GACzC,CACD,KAAK,KAAK,KACb;CACJ,MAAM,cAAc,OAAO,IAAI,UAAU,WAAW,UAAU,IAAI,UAAU;CAE5E,MAAM,UAAU,CAAC,aAAa,eAAe,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI;AACvE,QAAO,GAAG,aAAa,GAAG,aAAa,UAAU,IAAI,YAAY,KAAK,cAAc,cAAc,cAAc,MAAM;;AAGxH,SAAS,iBAAiB,KAAgB,UAAqC;AAC7E,QAAO,IAAI,QACR,KAAK,SAAS;EACb,MAAM,OAAO,KAAK;AAClB,MAAI,KAAK,SAAS,aAMhB,QAAO,GAAG,gBADS,GAAG,KAAK,MAAM,UACI,CAAC,GAAG,gBAAgB,KAAK,MAAM,CAAC,MAAM,gBAAgB,KAAK,MAAM;AAExG,MAAI,KAAK,SAAS,YAGhB,QAAO,GAFW,gBAAgB,MAAM,SAAS,CAE7B,MADN,gBAAgB,KAAK,MAAM;AAG3C,MAAI,KAAK,SAAS,UAGhB,QAAO,GAFS,cAAc,KAAK,CAEjB,MADJ,gBAAgB,KAAK,MAAM;AAK3C,SAAO,GAFQ,aAAa,KAAkB,CAE7B,MADH,gBAAgB,KAAK,MAAM;GAEzC,CACD,KAAK,KAAK;;AAGf,SAAS,YAAY,MAAiB,UAAqC;AACzE,KAAI,KAAK,SAAS,SAGhB,QAAO,GAFY,KAAK,MAAM,SAAS,GAElB,UADJ,aAAa,KAAK,UAAU,SAAS,CACd;AAE1C,KAAI,KAAK,SAAS,YAChB,QAAO,gBAAgB,MAAM,SAAS;AAExC,KAAI,KAAK,SAAS,OAAO;AACvB,MAAI,KAAK,MAAM,WAAW,EACxB,QAAO;AAET,SAAO,IAAI,KAAK,MAAM,KAAK,SAAS,YAAY,MAAM,SAAS,CAAC,CAAC,KAAK,QAAQ,CAAC;;AAEjF,KAAI,KAAK,SAAS,MAAM;AACtB,MAAI,KAAK,MAAM,WAAW,EACxB,QAAO;AAET,SAAO,IAAI,KAAK,MAAM,KAAK,SAAS,YAAY,MAAM,SAAS,CAAC,CAAC,KAAK,OAAO,CAAC;;AAEhF,QAAO,aAAa,MAAM,SAAS;;AAGrC,SAAS,gBAAgB,MAAqB,UAAqC;CACjF,MAAM,WAAW,WAAW,KAAK,MAAmC,SAAS;CAE7E,MAAM,eAAe,gBAAgB,KAAK,KAAK,GAAG,IAAI,SAAS,KAAK;AACpE,QAAO,KAAK,SAAS,GAAG,aAAa,YAAY,GAAG,aAAa;;AAGnE,SAAS,aAAa,MAAkB,UAAqC;CAC3E,MAAM,WAAW,KAAK;CACtB,MAAM,OAAO,WAAW,UAAU,SAAS;CAE3C,MAAM,eAAe,gBAAgB,SAAS,GAAG,IAAI,KAAK,KAAK;CAC/D,MAAM,QAAQ,kBAAkB,KAAK,OAAO,SAAS;AAcrD,QAAO,GAAG,aAAa,GAb+B;EACpD,IAAI;EACJ,KAAK;EACL,IAAI;EACJ,IAAI;EACJ,KAAK;EACL,KAAK;EACL,MAAM;EACN,OAAO;EACP,IAAI;EACJ,OAAO;EACR,CAEqC,KAAK,IAAI,GAAG;;AAGpD,SAAS,kBAAkB,OAA4B,UAAqC;AAC1F,KAAI,MAAM,SAAS,MACjB,QAAO,aAAa,MAAM;AAE5B,KAAI,MAAM,SAAS,QACjB,QAAO,YAAY,OAAO,SAAS;AAErC,KAAI,MAAM,SAAS,UACjB,QAAO,cAAc,MAAM;AAE7B,KAAI,MAAM,SAAS,YACjB,QAAO,WAAW,OAAO,SAAS;AAEpC,KAAI,MAAM,SAAS,eAAe;AAChC,MAAI,MAAM,OAAO,WAAW,EAC1B,QAAO;AAKT,SAAO,IAHQ,MAAM,OAAO,KAAK,UAC/B,MAAM,SAAS,UAAU,YAAY,OAAO,SAAS,GAAG,cAAc,MAAM,CAC7E,CACiB,KAAK,KAAK,CAAC;;AAG/B,OAAM,IAAI,MAAM,6CAA8C,MAA2B,OAAO;;AAGlG,SAAS,aAAa,KAAwB;AAC5C,QAAO,GAAG,gBAAgB,IAAI,MAAM,CAAC,GAAG,gBAAgB,IAAI,OAAO;;AAGrE,SAAS,WAAW,MAAiC,UAAqC;AACxF,KAAI,gBAAgB,KAAK,CACvB,QAAO,gBAAgB,MAAM,SAAS;AAExC,QAAO,aAAa,KAAK;;AAG3B,SAAS,YACP,KACA,UACA,WACA,YACQ;AACR,KAAI,YAAY,aAAa,YAAY;EAEvC,MAAM,aADY,SAAS,QAAQ,OAAO,YACZ,QAAQ;AACtC,SAAO,iBAAiB,IAAI,OAAO,YAAY,QAAQ;;AAEzD,QAAO,IAAI,IAAI;;AAGjB,SAAS,cAAc,MAA2B;AAChD,KAAI,OAAO,KAAK,UAAU,SACxB,QAAO,IAAI,cAAc,KAAK,MAAM,CAAC;AAEvC,KAAI,OAAO,KAAK,UAAU,YAAY,OAAO,KAAK,UAAU,UAC1D,QAAO,OAAO,KAAK,MAAM;AAE3B,KAAI,KAAK,UAAU,KACjB,QAAO;AAET,KAAI,MAAM,QAAQ,KAAK,MAAM,CAC3B,QAAO,SAAS,KAAK,MAAM,KAAK,MAAe,cAAc;EAAE,MAAM;EAAW,OAAO;EAAG,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC;AAE1G,QAAO,KAAK,UAAU,KAAK,MAAM;;AAGnC,SAAS,gBAAgB,MAAqB,UAAqC;CACjF,MAAM,OAAO,WAAW,KAAK,MAAM,SAAS;CAE5C,MAAM,oBAAoB,KAAK,cAAc;CAC7C,MAAM,OAAO,KAAK,KAAK,KAAK,QAA4D;AACtF,MAAI,IAAI,SAAS,MACf,QAAO,aAAa,IAAI;AAE1B,MAAI,IAAI,SAAS,QAEf,QAAO,oBAAoB,IAAI,IAAI,MAAM,YAAY,YAAY,KAAK,SAAS;AAEjF,MAAI,IAAI,SAAS,UACf,QAAO,cAAc,IAAI;AAE3B,MAAI,IAAI,SAAS,YACf,QAAO,gBAAgB,KAAK,SAAS;EAEvC,MAAMC,cAAqB;AAC3B,QAAM,IAAI,MAAM,8BAA+B,YAAiC,OAAO;GACvF;CAEF,IAAI,SAAS,KAAK,SAAS;AAC3B,UAAS,OAAO,QAAQ,eAAe,KAAK;AAC5C,MAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,IAC/B,UAAS,OAAO,QAAQ,IAAI,OAAO,YAAY,EAAE,MAAM,IAAI,EAAE,KAAK,MAAM,GAAG;AAG7E,KAAI,KAAK,SAAS,aAAa,WAC7B,QAAO;AAGT,QAAO;;AAGT,SAAS,WAAW,MAAe,WAAsC;AAIvE,QAAO,GAHU,KAAK,SAAS,aAAa,CAGzB,QAFL,gBAAgB,KAAK,MAAM,KAAK,CAEb,MADhB,aAAa,KAAK,GAAG;;AAIxC,SAAS,aAAa,IAA2B;AAC/C,KAAI,GAAG,SAAS,QAGd,QAAO,GAFM,aAAa,GAAG,KAAK,CAEnB,KADD,aAAa,GAAG,MAAM;AAGtC,OAAM,IAAI,MAAM,wCAAwC,GAAG,OAAO;;AAGpE,SAAS,cACP,SACA,UACQ;CACR,MAAM,QAAQ,QAAQ;CAUtB,MAAM,kBAAkB,qBAPA,QAAQ,MAAM,QACnC,KAAK,SAA6D;EACjE,MAAM,OAAO,WAAW,KAAK,MAAM,SAAS;AAC5C,SAAO,IAAI,KAAK,MAAM,KAAK;GAC3B,CACD,KAAK,KAAK,CAEgD;CAM7D,IAAI,cAAc,UAHE,aAAa,QAAQ,MAAM,GAAG;AAIlD,KAAI,QAAQ,MAAM,MAChB,gBAAe,QAAQ,YAAY,QAAQ,MAAM,OAAO,SAAS;CAInE,MAAM,eAAe,QAAQ,MAAM,SAAS,SACxC,aAAa,QAAQ,MAAM,QACxB,KACE,UACC,GAAG,WAAW,MAAM,MAAM,SAAS,CAAC,GAAG,MAAM,IAAI,aAAa,GACjE,CACA,KAAK,KAAK,KACb;CAGJ,MAAM,aAAa,OAAO,QAAQ,MAAM,UAAU,WAAW,UAAU,QAAQ,MAAM,UAAU;CAK/F,MAAM,aAAa,gBAAgB,QAAQ,MAAM,MAAM,KAAK;CAC5D,IAAIC;AACJ,KAAI,OAAO,QAAQ,MAAM,UAAU,UAAU;EAK3C,MAAM,iCAAiB,IAAI,KAAqB;AAChD,OAAK,MAAM,QAAQ,QAAQ,MAAM,QAC/B,KAAI,KAAK,KAAK,SAAS,OAAO;GAC5B,MAAM,YAAY,GAAG,KAAK,KAAK,MAAM,GAAG,KAAK,KAAK;AAClD,kBAAe,IAAI,WAAW,KAAK,MAAM;;EAI7C,MAAM,eAAe,QAAQ,MAAM,QAChC,KAAK,SAA6D;AAEjE,UAAO,GADM,WAAW,KAAK,MAAM,SAAS,CAC7B,MAAM,gBAAgB,KAAK,MAAM;IAChD,CACD,KAAK,KAAK;EAGb,MAAM,0BAA0B,QAAQ,MAAM,SAAS,SACnD,aAAa,QAAQ,MAAM,QACxB,KAAK,UAA4D;AAChE,OAAI,MAAM,KAAK,SAAS,OAAO;IAC7B,MAAM,YAAY,GAAG,MAAM,KAAK,MAAM,GAAG,MAAM,KAAK;IACpD,MAAMC,UAAQ,eAAe,IAAI,UAAU;AAC3C,QAAIA,QACF,QAAO,GAAG,gBAAgBA,QAAM,CAAC,GAAG,MAAM,IAAI,aAAa;;AAG/D,UAAO,GAAG,WAAW,MAAM,MAAM,SAAS,CAAC,GAAG,MAAM,IAAI,aAAa;IACrE,CACD,KAAK,KAAK,KACb;EAEJ,MAAM,cAAc,UAAU,aAAa,QAAQ,aAAa,cAAc,0BAA0B;AACxG,aAAW,2CAA2C,gBAAgB,MAAM,CAAC,SAAS,YAAY;YACzF,aAET,YAAW,oBAAoB,kBAAkB,aAAa,OAAO,gBAAgB,MAAM,CAAC,QAAQ,aAAa,YAAY;KAG7H,YAAW,oBAAoB,gBAAgB,OAAO,gBAAgB,MAAM,CAAC,QAAQ,aAAa,YAAY;CAMhH,MAAM,aAAa,GAAG,MAAM;AAC5B,QAAO,qBAAqB,SAAS,MAAM,gBAAgB,WAAW,CAAC;;AAGzE,SAAS,gBAAgB,YAA4B;AACnD,QAAO,IAAI,WAAW,QAAQ,MAAM,OAAK,CAAC;;AAG5C,SAAS,aAAa,KAAgB,UAAoC;CACxE,MAAM,QAAQ,gBAAgB,IAAI,MAAM,KAAK;CAC7C,MAAM,UAAU,OAAO,KAAK,IAAI,OAAO,CAAC,KAAK,QAAQ,gBAAgB,IAAI,CAAC;CAC1E,MAAM,YAAY,SAAS,QAAQ,OAAO,IAAI,MAAM;CACpD,MAAM,SAAS,OAAO,QAAQ,IAAI,OAAO,CAAC,KAAK,CAAC,SAAS,SAAS;AAChE,MAAI,IAAI,SAAS,SAAS;GACxB,MAAM,aAAa,WAAW,QAAQ;AACtC,UAAO,iBAAiB,IAAI,OAAO,YAAY,QAAQ;;AAEzD,MAAI,IAAI,SAAS,MACf,QAAO,GAAG,gBAAgB,IAAI,MAAM,CAAC,GAAG,gBAAgB,IAAI,OAAO;AAErE,QAAM,IAAI,MAAM,qCAAsC,IAAyB,OAAO;GACtF;AAUF,QAAO,GAPL,QAAQ,WAAW,IACf,eAAe,MAAM,mBACrB,eAAe,MAAM,IAAI,QAAQ,KAAK,KAAK,CAAC,YAAY,OAAO,KAAK,KAAK,CAAC,KACxD,IAAI,WAAW,SACnC,cAAc,IAAI,UAAU,KAAK,QAAQ,GAAG,gBAAgB,IAAI,MAAM,CAAC,GAAG,gBAAgB,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,KACnH;;AAKN,SAAS,aAAa,KAAgB,UAAoC;CACxE,MAAM,QAAQ,gBAAgB,IAAI,MAAM,KAAK;CAC7C,MAAM,YAAY,SAAS,QAAQ,OAAO,IAAI,MAAM;CACpD,MAAM,aAAa,OAAO,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,SAAS;EAC7D,MAAM,SAAS,gBAAgB,IAAI;EACnC,IAAIC;AACJ,MAAI,IAAI,SAAS,SAAS;GACxB,MAAM,aAAa,WAAW,QAAQ;AACtC,WAAQ,iBAAiB,IAAI,OAAO,YAAY,QAAQ;aAC/C,IAAI,SAAS,MACtB,SAAQ,GAAG,gBAAgB,IAAI,MAAM,CAAC,GAAG,gBAAgB,IAAI,OAAO;MAEpE,OAAM,IAAI,MAAM,qCAAsC,IAAyB,OAAO;AAExF,SAAO,GAAG,OAAO,KAAK;GACtB;CAEF,MAAM,cAAc,UAAU,YAAY,IAAI,OAAO,SAAS;CAC9D,MAAM,kBAAkB,IAAI,WAAW,SACnC,cAAc,IAAI,UAAU,KAAK,QAAQ,GAAG,gBAAgB,IAAI,MAAM,CAAC,GAAG,gBAAgB,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,KACnH;AAEJ,QAAO,UAAU,MAAM,OAAO,WAAW,KAAK,KAAK,GAAG,cAAc;;AAGtE,SAAS,aAAa,KAAgB,UAAqC;AAOzE,QAAO,eANO,gBAAgB,IAAI,MAAM,KAAK,GACzB,UAAU,YAAY,IAAI,OAAO,SAAS,KACtC,IAAI,WAAW,SACnC,cAAc,IAAI,UAAU,KAAK,QAAQ,GAAG,gBAAgB,IAAI,MAAM,CAAC,GAAG,gBAAgB,IAAI,OAAO,GAAG,CAAC,KAAK,KAAK,KACnH;;AAKN,SAAgB,sBAAsB,SAAkC;AACtE,QAAO,OAAO,OAAO,IAAI,oBAAoB,QAAQ,CAAC"}