@prisma-next/adapter-postgres 0.14.0-dev.5 → 0.14.0-dev.50

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.
@@ -1,4 +1,4 @@
1
- import { n as renderLoweredSql, r as createPostgresBuiltinCodecLookup, t as PostgresControlAdapter } from "./control-adapter-Dspz5uKp.mjs";
1
+ import { n as renderLoweredSql, r as createPostgresBuiltinCodecLookup, t as PostgresControlAdapter } from "./control-adapter-CkLNE6V5.mjs";
2
2
  import { APP_SPACE_ID } from "@prisma-next/framework-components/control";
3
3
  import { isDdlNode } from "@prisma-next/sql-relational-core/ast";
4
4
  //#region src/core/adapter.ts
@@ -15,7 +15,8 @@ const defaultCapabilities = Object.freeze({
15
15
  enums: true,
16
16
  returning: true,
17
17
  defaultInInsert: true,
18
- lateral: true
18
+ lateral: true,
19
+ scalarList: true
19
20
  }
20
21
  });
21
22
  var PostgresAdapterImpl = class {
@@ -62,4 +63,4 @@ function createPostgresAdapter(options) {
62
63
  //#endregion
63
64
  export { postgresRawCodecInferer as n, createPostgresAdapter as t };
64
65
 
65
- //# sourceMappingURL=adapter-CwkcdpM_.mjs.map
66
+ //# sourceMappingURL=adapter-bOgoyFDq.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter-bOgoyFDq.mjs","names":[],"sources":["../src/core/adapter.ts"],"sourcesContent":["import type { CodecRegistry } from '@prisma-next/framework-components/codec';\nimport { APP_SPACE_ID } from '@prisma-next/framework-components/control';\nimport type {\n Adapter,\n AdapterProfile,\n AnyQueryAst,\n LowererContext,\n RawSqlLiteral,\n SqlQueryable,\n} from '@prisma-next/sql-relational-core/ast';\nimport { isDdlNode } from '@prisma-next/sql-relational-core/ast';\nimport type { RawCodecInferer } from '@prisma-next/sql-relational-core/expression';\nimport type { PostgresDdlNode } from '@prisma-next/target-postgres/ddl';\nimport { createPostgresBuiltinCodecLookup } from './codec-lookup';\nimport { PostgresControlAdapter } from './control-adapter';\nimport { renderLoweredSql } from './sql-renderer';\nimport type { PostgresAdapterOptions, PostgresContract, PostgresLoweredStatement } from './types';\n\nconst defaultCapabilities = Object.freeze({\n postgres: {\n orderBy: true,\n limit: true,\n lateral: true,\n jsonAgg: true,\n returning: true,\n distinctOn: true,\n },\n sql: {\n enums: true,\n returning: true,\n defaultInInsert: true,\n lateral: true,\n scalarList: true,\n },\n});\n\nclass PostgresAdapterImpl\n implements Adapter<AnyQueryAst, PostgresContract, PostgresLoweredStatement>\n{\n // These fields make the adapter instance structurally compatible with 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 codecLookup: CodecRegistry;\n\n constructor(options?: PostgresAdapterOptions) {\n this.codecLookup = options?.codecLookup ?? createPostgresBuiltinCodecLookup();\n const controlAdapter = new PostgresControlAdapter(this.codecLookup);\n this.profile = Object.freeze({\n id: options?.profileId ?? 'postgres/default@1',\n target: 'postgres',\n capabilities: defaultCapabilities,\n readMarker: (queryable: SqlQueryable) =>\n controlAdapter.readMarkerDiscriminated(\n {\n familyId: 'sql',\n targetId: 'postgres',\n query: async <Row = Record<string, unknown>>(\n sql: string,\n params?: readonly unknown[],\n ) => {\n const result = await queryable.query<Row>(sql, params);\n return { rows: [...result.rows] };\n },\n close: async () => {},\n },\n APP_SPACE_ID,\n ),\n });\n }\n\n lower(\n ast: AnyQueryAst | PostgresDdlNode,\n context: LowererContext<PostgresContract>,\n ): PostgresLoweredStatement {\n if (isDdlNode(ast)) {\n throw new Error(\n 'lower() does not lower DDL on the runtime adapter — DDL lowering is a control-plane concern handled by the control adapter.',\n );\n }\n return renderLoweredSql(ast, context.contract, this.codecLookup);\n }\n}\n\n/** Codec-id lookup for bare-literal interpolations used by `fns.raw` on a postgres client. Contributed as the descriptor's static `rawCodecInferer` slot. */\nexport const postgresRawCodecInferer: RawCodecInferer = {\n inferCodec(value: RawSqlLiteral): string {\n switch (typeof value) {\n case 'number':\n return Number.isSafeInteger(value) && value % 1 === 0 ? 'pg/int4' : 'pg/float8';\n case 'bigint':\n return 'pg/int8';\n case 'string':\n return 'pg/text';\n case 'boolean':\n return 'pg/bool';\n case 'object':\n if (value instanceof Uint8Array) return 'pg/bytea';\n }\n throw new Error(\n 'unsupported JS value type for raw-SQL interpolation: wrap this value in `param(...)` with an explicit codec',\n );\n },\n};\n\nexport function createPostgresAdapter(options?: PostgresAdapterOptions) {\n return Object.freeze(new PostgresAdapterImpl(options));\n}\n"],"mappings":";;;;AAkBA,MAAM,sBAAsB,OAAO,OAAO;CACxC,UAAU;EACR,SAAS;EACT,OAAO;EACP,SAAS;EACT,SAAS;EACT,WAAW;EACX,YAAY;CACd;CACA,KAAK;EACH,OAAO;EACP,WAAW;EACX,iBAAiB;EACjB,SAAS;EACT,YAAY;CACd;AACF,CAAC;AAED,IAAM,sBAAN,MAEA;CAEE,WAAoB;CACpB,WAAoB;CAEpB;CACA;CAEA,YAAY,SAAkC;EAC5C,KAAK,cAAc,SAAS,eAAe,iCAAiC;EAC5E,MAAM,iBAAiB,IAAI,uBAAuB,KAAK,WAAW;EAClE,KAAK,UAAU,OAAO,OAAO;GAC3B,IAAI,SAAS,aAAa;GAC1B,QAAQ;GACR,cAAc;GACd,aAAa,cACX,eAAe,wBACb;IACE,UAAU;IACV,UAAU;IACV,OAAO,OACL,KACA,WACG;KAEH,OAAO,EAAE,MAAM,CAAC,IAAG,MADE,UAAU,MAAW,KAAK,MAAM,EAAA,CAC3B,IAAI,EAAE;IAClC;IACA,OAAO,YAAY,CAAC;GACtB,GACA,YACF;EACJ,CAAC;CACH;CAEA,MACE,KACA,SAC0B;EAC1B,IAAI,UAAU,GAAG,GACf,MAAM,IAAI,MACR,6HACF;EAEF,OAAO,iBAAiB,KAAK,QAAQ,UAAU,KAAK,WAAW;CACjE;AACF;;AAGA,MAAa,0BAA2C,EACtD,WAAW,OAA8B;CACvC,QAAQ,OAAO,OAAf;EACE,KAAK,UACH,OAAO,OAAO,cAAc,KAAK,KAAK,QAAQ,MAAM,IAAI,YAAY;EACtE,KAAK,UACH,OAAO;EACT,KAAK,UACH,OAAO;EACT,KAAK,WACH,OAAO;EACT,KAAK,UACH,IAAI,iBAAiB,YAAY,OAAO;CAC5C;CACA,MAAM,IAAI,MACR,6GACF;AACF,EACF;AAEA,SAAgB,sBAAsB,SAAkC;CACtE,OAAO,OAAO,OAAO,IAAI,oBAAoB,OAAO,CAAC;AACvD"}
@@ -1,4 +1,4 @@
1
- import { c as PostgresContract, l as PostgresLoweredStatement, s as PostgresAdapterOptions } from "./types-KXRwRZU8.mjs";
1
+ import { c as PostgresContract, l as PostgresLoweredStatement, s as PostgresAdapterOptions } from "./types-DkGeLfUp.mjs";
2
2
  import { Adapter, AdapterProfile, AnyQueryAst, LowererContext } from "@prisma-next/sql-relational-core/ast";
3
3
  import { RawCodecInferer } from "@prisma-next/sql-relational-core/expression";
4
4
  import { PostgresDdlNode } from "@prisma-next/target-postgres/ddl";
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.d.mts","names":[],"sources":["../src/core/adapter.ts"],"mappings":";;;;;;cAmCM,mBAAA,YACO,OAAA,CAAQ,WAAA,EAAa,gBAAA,EAAkB,wBAAA;EAAA,SAGzC,QAAA;EAAA,SACA,QAAA;EAAA,SAEA,OAAA,EAAS,cAAA;EAAA,iBACD,WAAA;cAEL,OAAA,GAAU,sBAAA;EA0BtB,KAAA,CACE,GAAA,EAAK,WAAA,GAAc,eAAA,EACnB,OAAA,EAAS,cAAA,CAAe,gBAAA,IACvB,wBAAA;AAAA;;cAWQ,uBAAA,EAAyB,eAkBrC;AAAA,iBAEe,qBAAA,CAAsB,OAAA,GAAU,sBAAA,GAAsB,QAAA,CAAA,mBAAA"}
1
+ {"version":3,"file":"adapter.d.mts","names":[],"sources":["../src/core/adapter.ts"],"mappings":";;;;;;cAoCM,mBAAA,YACO,OAAA,CAAQ,WAAA,EAAa,gBAAA,EAAkB,wBAAA;EAAA,SAGzC,QAAA;EAAA,SACA,QAAA;EAAA,SAEA,OAAA,EAAS,cAAA;EAAA,iBACD,WAAA;cAEL,OAAA,GAAU,sBAAA;EA0BtB,KAAA,CACE,GAAA,EAAK,WAAA,GAAc,eAAA,EACnB,OAAA,EAAS,cAAA,CAAe,gBAAA,IACvB,wBAAA;AAAA;;cAWQ,uBAAA,EAAyB,eAkBrC;AAAA,iBAEe,qBAAA,CAAsB,OAAA,GAAU,sBAAA,GAAsB,QAAA,CAAA,mBAAA"}
package/dist/adapter.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { n as postgresRawCodecInferer, t as createPostgresAdapter } from "./adapter-CwkcdpM_.mjs";
1
+ import { n as postgresRawCodecInferer, t as createPostgresAdapter } from "./adapter-bOgoyFDq.mjs";
2
2
  export { createPostgresAdapter, postgresRawCodecInferer };
@@ -9,6 +9,7 @@ import { buildControlTableBootstrapQueries, buildSignMarkerBootstrapQueries, int
9
9
  import { parsePostgresDefault } from "@prisma-next/target-postgres/default-normalizer";
10
10
  import { normalizeSchemaNativeType } from "@prisma-next/target-postgres/native-type-normalizer";
11
11
  import { escapeLiteral, quoteIdentifier } from "@prisma-next/target-postgres/sql-utils";
12
+ import { PostgresDatabaseSchemaNode, PostgresNamespaceSchemaNode, PostgresPolicySchemaNode, PostgresRoleSchemaNode, PostgresTableSchemaNode } from "@prisma-next/target-postgres/types";
12
13
  import { blindCast } from "@prisma-next/utils/casts";
13
14
  import { ifDefined } from "@prisma-next/utils/defined";
14
15
  import { createAstCodecRegistry, deriveParamMetadata, encodeParamsWithMetadata } from "@prisma-next/sql-runtime";
@@ -143,15 +144,19 @@ const POSTGRES_INFERRABLE_NATIVE_TYPES = new Set([
143
144
  "bit",
144
145
  "bit varying"
145
146
  ]);
146
- function renderTypedParam(index, codecId, codecLookup) {
147
+ function renderTypedParam(index, codecId, codecLookup, many, typeParams) {
147
148
  if (codecId === void 0) return `$${index}`;
148
- const meta = codecLookup.metaFor(codecId);
149
+ const meta = codecLookup.metaFor(codecId, typeParams);
149
150
  if (!(codecLookup.get(codecId) !== void 0 || meta !== void 0 || codecLookup.targetTypesFor(codecId) !== void 0)) throw new Error(`Postgres lowering: ParamRef carries codecId "${codecId}" but the assembled codec lookup has no entry for it. This usually indicates a missing extension pack in the runtime stack — register the pack that contributes this codec (e.g. \`extensionPacks: [pgvectorRuntime]\`), or use the codec directly from \`@prisma-next/target-postgres/codecs\` if it's a builtin.`);
150
151
  const dbRecord = meta?.db;
151
152
  const sqlBlock = isRecord(dbRecord) ? dbRecord["sql"] : void 0;
152
153
  const dialectBlock = isRecord(sqlBlock) ? sqlBlock["postgres"] : void 0;
153
154
  const nativeType = isRecord(dialectBlock) ? dialectBlock["nativeType"] : void 0;
154
- if (typeof nativeType === "string" && !POSTGRES_INFERRABLE_NATIVE_TYPES.has(nativeType)) return `$${index}::${nativeType}`;
155
+ if (typeof nativeType === "string") {
156
+ const arraySuffix = many ? "[]" : "";
157
+ if (!POSTGRES_INFERRABLE_NATIVE_TYPES.has(nativeType)) return `$${index}::${nativeType}${arraySuffix}`;
158
+ if (many) return `$${index}::${nativeType}${arraySuffix}`;
159
+ }
155
160
  return `$${index}`;
156
161
  }
157
162
  function isRecord(value) {
@@ -497,12 +502,12 @@ function renderExpr(expr, contract, pim) {
497
502
  function renderParamRef(ref, pim) {
498
503
  const index = pim.indexMap.get(ref);
499
504
  if (index === void 0) throw new Error("ParamRef not found in index map");
500
- if (ref.kind === "prepared-param-ref") return renderTypedParam(index, ref.codec.codecId, pim.codecLookup);
505
+ if (ref.kind === "prepared-param-ref") return renderTypedParam(index, ref.codec.codecId, pim.codecLookup, ref.codec.many, ref.codec.typeParams);
501
506
  if (ref.codec === void 0) throw runtimeError("RUNTIME.PARAM_REF_MISSING_CODEC", "Postgres renderer: ParamRef reached lowering without a bound CodecRef. Every column-bound ParamRef must carry a codec under the AST-bound codec contract. This usually indicates a builder path that constructed a ParamRef without threading the column codec.", {
502
507
  paramIndex: index,
503
508
  ...ifDefined("name", ref.name)
504
509
  });
505
- return renderTypedParam(index, ref.codec.codecId, pim.codecLookup);
510
+ return renderTypedParam(index, ref.codec.codecId, pim.codecLookup, ref.codec.many, ref.codec.typeParams);
506
511
  }
507
512
  function renderLiteral(expr) {
508
513
  if (typeof expr.value === "string") return `'${escapeLiteral(expr.value)}'`;
@@ -887,20 +892,34 @@ var PostgresControlAdapter = class {
887
892
  */
888
893
  async introspect(driver, contract, schema = "public") {
889
894
  const declaredNamespaces = extractContractNamespaceIds(contract);
890
- const ir = declaredNamespaces.length > 0 ? await this.introspectNamespaces(driver, declaredNamespaces) : await this.introspectSchema(driver, schema);
891
- const existingSchemas = await this.listExistingSchemas(driver);
892
- const annotations = ir.annotations ?? {};
893
- const pg = annotations.pg ?? {};
894
- return {
895
- ...ir,
896
- annotations: {
897
- ...annotations,
898
- pg: {
899
- ...pg,
900
- existingSchemas
901
- }
902
- }
903
- };
895
+ const resolvedSchemas = declaredNamespaces.length > 0 ? await this.resolveNamespaceSchemas(driver, declaredNamespaces) : [schema];
896
+ const namespaces = {};
897
+ let pgVersion = "unknown";
898
+ for (const resolved of resolvedSchemas) {
899
+ const { namespace, pgVersion: version } = await this.introspectSchema(driver, resolved);
900
+ namespaces[resolved] = namespace;
901
+ pgVersion = version;
902
+ }
903
+ return new PostgresDatabaseSchemaNode({
904
+ namespaces,
905
+ roles: await this.introspectRoles(driver),
906
+ existingSchemas: await this.listExistingSchemas(driver),
907
+ pgVersion
908
+ });
909
+ }
910
+ /**
911
+ * Reads cluster-scoped database roles. Roles are not schema-qualified, so
912
+ * this is queried once for the whole database rather than per namespace.
913
+ */
914
+ async introspectRoles(driver) {
915
+ return (await driver.query(`SELECT rolname
916
+ FROM pg_catalog.pg_roles
917
+ WHERE rolname NOT LIKE 'pg_%'
918
+ AND rolname != 'postgres'
919
+ ORDER BY rolname`)).rows.map((row) => new PostgresRoleSchemaNode({
920
+ name: row.rolname,
921
+ namespaceId: UNBOUND_NAMESPACE_ID
922
+ }));
904
923
  }
905
924
  /**
906
925
  * Lists every non-system schema present in the connected database.
@@ -919,36 +938,24 @@ var PostgresControlAdapter = class {
919
938
  ORDER BY nspname`)).rows.map((row) => row.nspname);
920
939
  }
921
940
  /**
922
- * Walks every declared namespace, resolving `UNBOUND_NAMESPACE_ID` to
923
- * the connection's `current_schema()`, and merges the per-schema results
924
- * into a single `SqlSchemaIR`. The merged `tables` map is flat (keyed by
925
- * table name) so callers that look up by `tableName` see every contract
926
- * table regardless of which namespace it lives in.
941
+ * Resolves the declared namespace ids to their live DDL schema names,
942
+ * mapping `UNBOUND_NAMESPACE_ID` to the connection's `current_schema()`
943
+ * and de-duplicating. The caller introspects one namespace node per
944
+ * resolved schema there is no flat cross-schema merge, so two schemas
945
+ * holding a same-named table no longer collide.
927
946
  */
928
- async introspectNamespaces(driver, namespaceIds) {
947
+ async resolveNamespaceSchemas(driver, namespaceIds) {
929
948
  const resolvedSchemas = [];
930
949
  for (const id of namespaceIds) if (id === UNBOUND_NAMESPACE_ID) {
931
950
  const { rows } = await driver.query("SELECT current_schema() AS current_schema");
932
951
  resolvedSchemas.push(rows[0]?.current_schema ?? "public");
933
952
  } else resolvedSchemas.push(id);
934
- const uniqueSchemas = Array.from(new Set(resolvedSchemas));
935
- const perSchema = [];
936
- for (const schema of uniqueSchemas) perSchema.push(await this.introspectSchema(driver, schema));
937
- const mergedTables = {};
938
- for (const ir of perSchema) for (const [tableName, table] of Object.entries(ir.tables)) mergedTables[tableName] = table;
939
- const firstAnnotations = perSchema[0]?.annotations;
940
- const firstPg = blindCast(firstAnnotations?.["pg"]) ?? {};
941
- return {
942
- tables: mergedTables,
943
- ...ifDefined("annotations", {
944
- ...firstAnnotations,
945
- pg: { ...firstPg }
946
- })
947
- };
953
+ return Array.from(new Set(resolvedSchemas));
948
954
  }
949
955
  /**
950
- * Introspects a single Postgres schema and returns a raw SqlSchemaIR
951
- * containing only the tables in that schema. Used by `introspect` as
956
+ * Introspects a single Postgres schema and returns the namespace node for
957
+ * that schema (its tables, their policies, and its native enum type names),
958
+ * alongside the cluster-scoped Postgres version. Used by `introspect` as
952
959
  * the per-namespace walk.
953
960
  */
954
961
  async introspectSchema(driver, schema) {
@@ -1091,7 +1098,7 @@ var PostgresControlAdapter = class {
1091
1098
  }
1092
1099
  constraints.add(row.constraint_name);
1093
1100
  }
1094
- const tables = {};
1101
+ const tableInputs = {};
1095
1102
  for (const tableRow of tablesResult.rows) {
1096
1103
  const tableName = tableRow.table_name;
1097
1104
  const columns = {};
@@ -1105,11 +1112,18 @@ var PostgresControlAdapter = class {
1105
1112
  else if (colRow.numeric_precision) nativeType = `${colRow.data_type}(${colRow.numeric_precision})`;
1106
1113
  else nativeType = colRow.data_type;
1107
1114
  else nativeType = colRow.udt_name || colRow.data_type;
1115
+ const many = nativeType.endsWith("[]") ? true : void 0;
1116
+ if (many) nativeType = normalizeSchemaNativeType(nativeType.slice(0, -2));
1117
+ const resolvedNativeType = `${normalizeSchemaNativeType(nativeType)}${many ? "[]" : ""}`;
1118
+ const rawDefault = colRow.column_default ?? void 0;
1108
1119
  columns[colRow.column_name] = {
1109
1120
  name: colRow.column_name,
1110
1121
  nativeType,
1111
1122
  nullable: colRow.is_nullable === "YES",
1112
- ...ifDefined("default", colRow.column_default ?? void 0)
1123
+ ...ifDefined("default", rawDefault),
1124
+ ...ifDefined("many", many),
1125
+ resolvedNativeType,
1126
+ ...ifDefined("resolvedDefault", rawDefault !== void 0 ? parsePostgresDefault(rawDefault, resolvedNativeType) : void 0)
1113
1127
  };
1114
1128
  }
1115
1129
  const pkRows = [...pksByTable.get(tableName) ?? []];
@@ -1191,7 +1205,7 @@ var PostgresControlAdapter = class {
1191
1205
  permittedValues: parsed.permittedValues
1192
1206
  });
1193
1207
  }
1194
- tables[tableName] = {
1208
+ tableInputs[tableName] = {
1195
1209
  name: tableName,
1196
1210
  columns,
1197
1211
  ...ifDefined("primaryKey", primaryKey),
@@ -1207,13 +1221,43 @@ var PostgresControlAdapter = class {
1207
1221
  WHERE t.typtype = 'e'
1208
1222
  AND n.nspname = $1
1209
1223
  ORDER BY t.typname`, [schema])).rows.map((r) => r.typname);
1224
+ const policiesResult = await driver.query(`SELECT schemaname, tablename, policyname, cmd, roles, qual, with_check, permissive
1225
+ FROM pg_catalog.pg_policies
1226
+ WHERE schemaname = $1
1227
+ ORDER BY tablename, policyname`, [schema]);
1228
+ const policiesByTable = /* @__PURE__ */ new Map();
1229
+ for (const row of policiesResult.rows) {
1230
+ const operation = mapPgCmd(row.cmd);
1231
+ const policyRoles = [...new Set(parsePgNameArray(row.roles).map((r) => r.toLowerCase()))].sort();
1232
+ const permissive = row.permissive.toUpperCase() === "PERMISSIVE";
1233
+ const prefix = /^(.+)_([0-9a-f]{8})$/.exec(row.policyname)?.[1] ?? row.policyname;
1234
+ const policy = new PostgresPolicySchemaNode({
1235
+ name: row.policyname,
1236
+ prefix,
1237
+ tableName: row.tablename,
1238
+ namespaceId: row.schemaname,
1239
+ operation,
1240
+ roles: policyRoles,
1241
+ ...row.qual !== null ? { using: row.qual } : {},
1242
+ ...row.with_check !== null ? { withCheck: row.with_check } : {},
1243
+ permissive
1244
+ });
1245
+ const list = policiesByTable.get(row.tablename) ?? [];
1246
+ list.push(policy);
1247
+ policiesByTable.set(row.tablename, list);
1248
+ }
1249
+ const tables = {};
1250
+ for (const [tableName, input] of Object.entries(tableInputs)) tables[tableName] = new PostgresTableSchemaNode({
1251
+ ...input,
1252
+ policies: policiesByTable.get(tableName) ?? []
1253
+ });
1210
1254
  return {
1211
- tables,
1212
- annotations: { pg: {
1213
- schema,
1214
- version: await this.getPostgresVersion(driver),
1215
- ...nativeEnumTypeNames.length > 0 && { nativeEnumTypeNames }
1216
- } }
1255
+ namespace: new PostgresNamespaceSchemaNode({
1256
+ schemaName: schema,
1257
+ tables,
1258
+ nativeEnumTypeNames
1259
+ }),
1260
+ pgVersion: await this.getPostgresVersion(driver)
1217
1261
  };
1218
1262
  }
1219
1263
  /**
@@ -1224,6 +1268,37 @@ var PostgresControlAdapter = class {
1224
1268
  }
1225
1269
  };
1226
1270
  /**
1271
+ * Normalises a `name[]` column value from `pg_policies.roles`.
1272
+ *
1273
+ * The `pg` client's type-parser registry handles `text[]` (OID 1009) but not
1274
+ * `name[]` (OID 1003). When the parser is absent the raw Postgres text-array
1275
+ * literal (`{role1,role2}`) is returned as a string instead of a JS array.
1276
+ * This function accepts either form and returns a plain string array.
1277
+ */
1278
+ function parsePgNameArray(value) {
1279
+ if (Array.isArray(value)) return value;
1280
+ if (typeof value !== "string") return [];
1281
+ const trimmed = value.trim();
1282
+ if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) return [];
1283
+ const inner = trimmed.slice(1, -1);
1284
+ if (inner === "") return [];
1285
+ return inner.split(",").map((s) => s.trim());
1286
+ }
1287
+ /**
1288
+ * Maps `pg_policies.cmd` text values to the `RlsPolicyOperation` union.
1289
+ * The `pg_policies` view renders the internal command code as an uppercase
1290
+ * English keyword; this function lowercases to match the IR type.
1291
+ */
1292
+ function mapPgCmd(cmd) {
1293
+ switch (cmd.toUpperCase()) {
1294
+ case "SELECT": return "select";
1295
+ case "INSERT": return "insert";
1296
+ case "UPDATE": return "update";
1297
+ case "DELETE": return "delete";
1298
+ default: return "all";
1299
+ }
1300
+ }
1301
+ /**
1227
1302
  * Extracts the namespace coordinate ids declared on a contract's storage,
1228
1303
  * or returns an empty array when no contract (or no storage / namespaces)
1229
1304
  * is present. Used by `PostgresControlAdapter.introspect` to decide
@@ -1238,6 +1313,7 @@ function extractContractNamespaceIds(contract) {
1238
1313
  return Object.keys(namespaces);
1239
1314
  }
1240
1315
  function normalizeFormattedType(formattedType, dataType, udtName) {
1316
+ if (formattedType.endsWith("[]")) return `${normalizeFormattedType(formattedType.slice(0, -2), dataType, udtName)}[]`;
1241
1317
  if (formattedType === "integer") return "int4";
1242
1318
  if (formattedType === "smallint") return "int2";
1243
1319
  if (formattedType === "bigint") return "int8";
@@ -1383,6 +1459,16 @@ function extractQuotedLiterals(listBody) {
1383
1459
  function pgIsTextLikeNativeType(nativeType) {
1384
1460
  return nativeType === "text" || nativeType === "varchar" || nativeType.startsWith("varchar(") || nativeType === "character varying" || nativeType.startsWith("character varying(") || nativeType === "char" || nativeType.startsWith("char(") || nativeType === "character" || nativeType.startsWith("character(");
1385
1461
  }
1462
+ function pgRenderArrayElement(el) {
1463
+ if (el === null) return "NULL";
1464
+ if (typeof el === "number" || typeof el === "boolean") return String(el);
1465
+ if (typeof el === "string") return `'${escapeLiteral(el)}'`;
1466
+ return `'${escapeLiteral(JSON.stringify(el))}'`;
1467
+ }
1468
+ function pgRenderArrayLiteral(elements) {
1469
+ if (elements.length === 0) return "'{}'";
1470
+ return `ARRAY[${elements.map(pgRenderArrayElement).join(", ")}]`;
1471
+ }
1386
1472
  function pgInlineLiteral(wire, nativeType) {
1387
1473
  if (wire === null) return "NULL";
1388
1474
  if (typeof wire === "boolean") return wire ? "true" : "false";
@@ -1401,6 +1487,7 @@ function pgInlineLiteral(wire, nativeType) {
1401
1487
  return pgIsTextLikeNativeType(nativeType) ? quoted : `${quoted}::${nativeType}`;
1402
1488
  }
1403
1489
  if (wire instanceof Uint8Array) return `'\\x${Array.from(wire).map((b) => b.toString(16).padStart(2, "0")).join("")}'::${nativeType}`;
1490
+ if (Array.isArray(wire) && nativeType.endsWith("[]")) return pgRenderArrayLiteral(wire);
1404
1491
  if (typeof wire === "object") return `${`'${escapeLiteral(JSON.stringify(wire))}'`}::${nativeType}`;
1405
1492
  throw new Error(`pgRenderDdlExecuteRequest: unexpected wire type "${typeof wire}" for native type "${nativeType}"`);
1406
1493
  }
@@ -1438,6 +1525,7 @@ function pgRenderDdlConstraint(constraint) {
1438
1525
  if (constraint.name !== void 0) sql = `CONSTRAINT ${quoteIdentifier(constraint.name)} ${sql}`;
1439
1526
  return sql;
1440
1527
  }
1528
+ if (constraint.kind === "check-expression") return `CONSTRAINT ${quoteIdentifier(constraint.name)} CHECK (${constraint.expression})`;
1441
1529
  const cols = constraint.columns.map(quoteIdentifier).join(", ");
1442
1530
  if (constraint.name !== void 0) return `CONSTRAINT ${quoteIdentifier(constraint.name)} UNIQUE (${cols})`;
1443
1531
  return `UNIQUE (${cols})`;
@@ -1460,22 +1548,56 @@ function pgRenderCreateSchema(node) {
1460
1548
  }
1461
1549
  async function pgRenderAlterTable(node, codecLookup) {
1462
1550
  const tableRef = node.schema ? `${quoteIdentifier(node.schema)}.${quoteIdentifier(node.table)}` : quoteIdentifier(node.table);
1463
- const actionVisitor = { async addColumn(action) {
1464
- return `ADD COLUMN ${await pgRenderDdlColumn(action.column, codecLookup)}`;
1465
- } };
1551
+ const actionVisitor = {
1552
+ async addColumn(action) {
1553
+ return `ADD COLUMN ${await pgRenderDdlColumn(action.column, codecLookup)}`;
1554
+ },
1555
+ dropDefault(action) {
1556
+ return Promise.resolve(`ALTER COLUMN ${quoteIdentifier(action.columnName)} DROP DEFAULT`);
1557
+ }
1558
+ };
1466
1559
  return {
1467
1560
  sql: `ALTER TABLE ${tableRef} ${(await Promise.all(node.actions.map((a) => a.accept(actionVisitor)))).join(", ")}`,
1468
1561
  params: []
1469
1562
  };
1470
1563
  }
1564
+ const POLICY_OPERATION_SQL = {
1565
+ select: "SELECT",
1566
+ insert: "INSERT",
1567
+ update: "UPDATE",
1568
+ delete: "DELETE",
1569
+ all: "ALL"
1570
+ };
1571
+ function pgRenderCreatePolicy(node) {
1572
+ const tableRef = `${quoteIdentifier(node.schema)}.${quoteIdentifier(node.table)}`;
1573
+ const permissiveness = node.permissive ? "PERMISSIVE" : "RESTRICTIVE";
1574
+ const command = POLICY_OPERATION_SQL[node.operation];
1575
+ const roles = node.roles.length === 0 ? "PUBLIC" : node.roles.join(", ");
1576
+ let sql = `CREATE POLICY ${quoteIdentifier(node.name)} ON ${tableRef} AS ${permissiveness} FOR ${command} TO ${roles}`;
1577
+ if (node.using !== void 0) sql += ` USING (${node.using})`;
1578
+ if (node.withCheck !== void 0) sql += ` WITH CHECK (${node.withCheck})`;
1579
+ return {
1580
+ sql,
1581
+ params: []
1582
+ };
1583
+ }
1584
+ function pgRenderDropPolicy(node) {
1585
+ const tableRef = `${quoteIdentifier(node.schema)}.${quoteIdentifier(node.table)}`;
1586
+ return {
1587
+ sql: `DROP POLICY ${quoteIdentifier(node.name)} ON ${tableRef}`,
1588
+ params: []
1589
+ };
1590
+ }
1471
1591
  async function pgRenderDdlExecuteRequest(ast, codecLookup) {
1472
1592
  return ast.accept({
1473
1593
  createTable: (node) => pgRenderCreateTable(node, codecLookup),
1474
1594
  createSchema: (node) => Promise.resolve(pgRenderCreateSchema(node)),
1475
- alterTable: (node) => pgRenderAlterTable(node, codecLookup)
1595
+ alterTable: (node) => pgRenderAlterTable(node, codecLookup),
1596
+ createPolicy: (node) => Promise.resolve(pgRenderCreatePolicy(node)),
1597
+ dropPolicy: (node) => Promise.resolve(pgRenderDropPolicy(node))
1476
1598
  });
1477
1599
  }
1478
1600
  //#endregion
1479
1601
  export { renderLoweredSql as n, createPostgresBuiltinCodecLookup as r, PostgresControlAdapter as t };
1480
1602
 
1481
- //# sourceMappingURL=control-adapter-Dspz5uKp.mjs.map
1603
+ //# sourceMappingURL=control-adapter-CkLNE6V5.mjs.map