@prisma-next/adapter-postgres 0.14.0-dev.2 → 0.14.0-dev.21

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-AffpjrYN.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-BvM9axNH.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter-BvM9axNH.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 +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-BvM9axNH.mjs";
2
2
  export { createPostgresAdapter, postgresRawCodecInferer };
@@ -8,7 +8,9 @@ import { REFERENTIAL_ACTION_SQL } from "@prisma-next/sql-contract/referential-ac
8
8
  import { buildControlTableBootstrapQueries, buildSignMarkerBootstrapQueries, int4, int8, jsonb, pgTable, text, textArray, timestamptz } from "@prisma-next/target-postgres/contract-free";
9
9
  import { parsePostgresDefault } from "@prisma-next/target-postgres/default-normalizer";
10
10
  import { normalizeSchemaNativeType } from "@prisma-next/target-postgres/native-type-normalizer";
11
+ import { diffPostgresRlsPolicies } from "@prisma-next/target-postgres/planner";
11
12
  import { escapeLiteral, quoteIdentifier } from "@prisma-next/target-postgres/sql-utils";
13
+ import { PostgresRlsPolicy, PostgresRole, PostgresSchemaIR, isPostgresSchemaIR } from "@prisma-next/target-postgres/types";
12
14
  import { blindCast } from "@prisma-next/utils/casts";
13
15
  import { ifDefined } from "@prisma-next/utils/defined";
14
16
  import { createAstCodecRegistry, deriveParamMetadata, encodeParamsWithMetadata } from "@prisma-next/sql-runtime";
@@ -143,7 +145,7 @@ const POSTGRES_INFERRABLE_NATIVE_TYPES = new Set([
143
145
  "bit",
144
146
  "bit varying"
145
147
  ]);
146
- function renderTypedParam(index, codecId, codecLookup) {
148
+ function renderTypedParam(index, codecId, codecLookup, many) {
147
149
  if (codecId === void 0) return `$${index}`;
148
150
  const meta = codecLookup.metaFor(codecId);
149
151
  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.`);
@@ -151,7 +153,11 @@ function renderTypedParam(index, codecId, codecLookup) {
151
153
  const sqlBlock = isRecord(dbRecord) ? dbRecord["sql"] : void 0;
152
154
  const dialectBlock = isRecord(sqlBlock) ? sqlBlock["postgres"] : void 0;
153
155
  const nativeType = isRecord(dialectBlock) ? dialectBlock["nativeType"] : void 0;
154
- if (typeof nativeType === "string" && !POSTGRES_INFERRABLE_NATIVE_TYPES.has(nativeType)) return `$${index}::${nativeType}`;
156
+ if (typeof nativeType === "string") {
157
+ const arraySuffix = many ? "[]" : "";
158
+ if (!POSTGRES_INFERRABLE_NATIVE_TYPES.has(nativeType)) return `$${index}::${nativeType}${arraySuffix}`;
159
+ if (many) return `$${index}::${nativeType}${arraySuffix}`;
160
+ }
155
161
  return `$${index}`;
156
162
  }
157
163
  function isRecord(value) {
@@ -497,12 +503,12 @@ function renderExpr(expr, contract, pim) {
497
503
  function renderParamRef(ref, pim) {
498
504
  const index = pim.indexMap.get(ref);
499
505
  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);
506
+ if (ref.kind === "prepared-param-ref") return renderTypedParam(index, ref.codec.codecId, pim.codecLookup, ref.codec.many);
501
507
  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
508
  paramIndex: index,
503
509
  ...ifDefined("name", ref.name)
504
510
  });
505
- return renderTypedParam(index, ref.codec.codecId, pim.codecLookup);
511
+ return renderTypedParam(index, ref.codec.codecId, pim.codecLookup, ref.codec.many);
506
512
  }
507
513
  function renderLiteral(expr) {
508
514
  if (typeof expr.value === "string") return `'${escapeLiteral(expr.value)}'`;
@@ -664,6 +670,13 @@ var PostgresControlAdapter = class {
664
670
  * before comparison with contract native types.
665
671
  */
666
672
  normalizeNativeType = normalizeSchemaNativeType;
673
+ collectSchemaDiffIssues(contract, schema) {
674
+ if (!isPostgresSchemaIR(schema)) throw new Error(`RLS verification requires a PostgresSchemaIR; got ${schema.constructor?.name ?? typeof schema}`);
675
+ return diffPostgresRlsPolicies({
676
+ contract,
677
+ schema
678
+ });
679
+ }
667
680
  bootstrapControlTableQueries() {
668
681
  return buildControlTableBootstrapQueries();
669
682
  }
@@ -889,18 +902,15 @@ var PostgresControlAdapter = class {
889
902
  const declaredNamespaces = extractContractNamespaceIds(contract);
890
903
  const ir = declaredNamespaces.length > 0 ? await this.introspectNamespaces(driver, declaredNamespaces) : await this.introspectSchema(driver, schema);
891
904
  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
- };
905
+ return new PostgresSchemaIR({
906
+ tables: ir.tables,
907
+ pgSchemaName: ir.pgSchemaName,
908
+ pgVersion: ir.pgVersion,
909
+ rlsPolicies: ir.rlsPolicies,
910
+ roles: ir.roles,
911
+ existingSchemas,
912
+ nativeEnumTypeNames: ir.nativeEnumTypeNames
913
+ });
904
914
  }
905
915
  /**
906
916
  * Lists every non-system schema present in the connected database.
@@ -936,15 +946,22 @@ var PostgresControlAdapter = class {
936
946
  for (const schema of uniqueSchemas) perSchema.push(await this.introspectSchema(driver, schema));
937
947
  const mergedTables = {};
938
948
  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 {
949
+ const mergedRlsPolicies = [];
950
+ const mergedRoles = [];
951
+ for (const ir of perSchema) {
952
+ mergedRlsPolicies.push(...ir.rlsPolicies);
953
+ mergedRoles.push(...ir.roles);
954
+ }
955
+ const first = perSchema[0];
956
+ return new PostgresSchemaIR({
942
957
  tables: mergedTables,
943
- ...ifDefined("annotations", {
944
- ...firstAnnotations,
945
- pg: { ...firstPg }
946
- })
947
- };
958
+ pgSchemaName: first?.pgSchemaName ?? "public",
959
+ pgVersion: first?.pgVersion ?? "unknown",
960
+ rlsPolicies: mergedRlsPolicies,
961
+ roles: mergedRoles,
962
+ existingSchemas: first?.existingSchemas ?? ["public"],
963
+ nativeEnumTypeNames: first?.nativeEnumTypeNames ?? []
964
+ });
948
965
  }
949
966
  /**
950
967
  * Introspects a single Postgres schema and returns a raw SqlSchemaIR
@@ -1105,11 +1122,14 @@ var PostgresControlAdapter = class {
1105
1122
  else if (colRow.numeric_precision) nativeType = `${colRow.data_type}(${colRow.numeric_precision})`;
1106
1123
  else nativeType = colRow.data_type;
1107
1124
  else nativeType = colRow.udt_name || colRow.data_type;
1125
+ const many = nativeType.endsWith("[]") ? true : void 0;
1126
+ if (many) nativeType = normalizeSchemaNativeType(nativeType.slice(0, -2));
1108
1127
  columns[colRow.column_name] = {
1109
1128
  name: colRow.column_name,
1110
1129
  nativeType,
1111
1130
  nullable: colRow.is_nullable === "YES",
1112
- ...ifDefined("default", colRow.column_default ?? void 0)
1131
+ ...ifDefined("default", colRow.column_default ?? void 0),
1132
+ ...ifDefined("many", many)
1113
1133
  };
1114
1134
  }
1115
1135
  const pkRows = [...pksByTable.get(tableName) ?? []];
@@ -1207,14 +1227,45 @@ var PostgresControlAdapter = class {
1207
1227
  WHERE t.typtype = 'e'
1208
1228
  AND n.nspname = $1
1209
1229
  ORDER BY t.typname`, [schema])).rows.map((r) => r.typname);
1210
- return {
1230
+ const policiesResult = await driver.query(`SELECT schemaname, tablename, policyname, cmd, roles, qual, with_check, permissive
1231
+ FROM pg_catalog.pg_policies
1232
+ WHERE schemaname = $1
1233
+ ORDER BY tablename, policyname`, [schema]);
1234
+ const rolesResult = await driver.query(`SELECT rolname
1235
+ FROM pg_catalog.pg_roles
1236
+ WHERE rolname NOT LIKE 'pg_%'
1237
+ AND rolname != 'postgres'
1238
+ ORDER BY rolname`);
1239
+ const rlsPolicies = policiesResult.rows.map((row) => {
1240
+ const operation = mapPgCmd(row.cmd);
1241
+ const roles = [...new Set(parsePgNameArray(row.roles).map((r) => r.toLowerCase()))].sort();
1242
+ const permissive = row.permissive.toUpperCase() === "PERMISSIVE";
1243
+ const prefix = /^(.+)_([0-9a-f]{8})$/.exec(row.policyname)?.[1] ?? row.policyname;
1244
+ return new PostgresRlsPolicy({
1245
+ name: row.policyname,
1246
+ prefix,
1247
+ tableName: row.tablename,
1248
+ namespaceId: row.schemaname,
1249
+ operation,
1250
+ roles,
1251
+ ...row.qual !== null ? { using: row.qual } : {},
1252
+ ...row.with_check !== null ? { withCheck: row.with_check } : {},
1253
+ permissive
1254
+ });
1255
+ });
1256
+ const roles = rolesResult.rows.map((row) => new PostgresRole({
1257
+ name: row.rolname,
1258
+ namespaceId: UNBOUND_NAMESPACE_ID
1259
+ }));
1260
+ return new PostgresSchemaIR({
1211
1261
  tables,
1212
- annotations: { pg: {
1213
- schema,
1214
- version: await this.getPostgresVersion(driver),
1215
- ...nativeEnumTypeNames.length > 0 && { nativeEnumTypeNames }
1216
- } }
1217
- };
1262
+ pgSchemaName: schema,
1263
+ pgVersion: await this.getPostgresVersion(driver),
1264
+ rlsPolicies,
1265
+ roles,
1266
+ existingSchemas: [],
1267
+ nativeEnumTypeNames
1268
+ });
1218
1269
  }
1219
1270
  /**
1220
1271
  * Gets the Postgres version from the database.
@@ -1224,6 +1275,37 @@ var PostgresControlAdapter = class {
1224
1275
  }
1225
1276
  };
1226
1277
  /**
1278
+ * Normalises a `name[]` column value from `pg_policies.roles`.
1279
+ *
1280
+ * The `pg` client's type-parser registry handles `text[]` (OID 1009) but not
1281
+ * `name[]` (OID 1003). When the parser is absent the raw Postgres text-array
1282
+ * literal (`{role1,role2}`) is returned as a string instead of a JS array.
1283
+ * This function accepts either form and returns a plain string array.
1284
+ */
1285
+ function parsePgNameArray(value) {
1286
+ if (Array.isArray(value)) return value;
1287
+ if (typeof value !== "string") return [];
1288
+ const trimmed = value.trim();
1289
+ if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) return [];
1290
+ const inner = trimmed.slice(1, -1);
1291
+ if (inner === "") return [];
1292
+ return inner.split(",").map((s) => s.trim());
1293
+ }
1294
+ /**
1295
+ * Maps `pg_policies.cmd` text values to the `RlsPolicyOperation` union.
1296
+ * The `pg_policies` view renders the internal command code as an uppercase
1297
+ * English keyword; this function lowercases to match the IR type.
1298
+ */
1299
+ function mapPgCmd(cmd) {
1300
+ switch (cmd.toUpperCase()) {
1301
+ case "SELECT": return "select";
1302
+ case "INSERT": return "insert";
1303
+ case "UPDATE": return "update";
1304
+ case "DELETE": return "delete";
1305
+ default: return "all";
1306
+ }
1307
+ }
1308
+ /**
1227
1309
  * Extracts the namespace coordinate ids declared on a contract's storage,
1228
1310
  * or returns an empty array when no contract (or no storage / namespaces)
1229
1311
  * is present. Used by `PostgresControlAdapter.introspect` to decide
@@ -1238,6 +1320,7 @@ function extractContractNamespaceIds(contract) {
1238
1320
  return Object.keys(namespaces);
1239
1321
  }
1240
1322
  function normalizeFormattedType(formattedType, dataType, udtName) {
1323
+ if (formattedType.endsWith("[]")) return `${normalizeFormattedType(formattedType.slice(0, -2), dataType, udtName)}[]`;
1241
1324
  if (formattedType === "integer") return "int4";
1242
1325
  if (formattedType === "smallint") return "int2";
1243
1326
  if (formattedType === "bigint") return "int8";
@@ -1383,6 +1466,16 @@ function extractQuotedLiterals(listBody) {
1383
1466
  function pgIsTextLikeNativeType(nativeType) {
1384
1467
  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
1468
  }
1469
+ function pgRenderArrayElement(el) {
1470
+ if (el === null) return "NULL";
1471
+ if (typeof el === "number" || typeof el === "boolean") return String(el);
1472
+ if (typeof el === "string") return `'${escapeLiteral(el)}'`;
1473
+ return `'${escapeLiteral(JSON.stringify(el))}'`;
1474
+ }
1475
+ function pgRenderArrayLiteral(elements) {
1476
+ if (elements.length === 0) return "'{}'";
1477
+ return `ARRAY[${elements.map(pgRenderArrayElement).join(", ")}]`;
1478
+ }
1386
1479
  function pgInlineLiteral(wire, nativeType) {
1387
1480
  if (wire === null) return "NULL";
1388
1481
  if (typeof wire === "boolean") return wire ? "true" : "false";
@@ -1401,6 +1494,7 @@ function pgInlineLiteral(wire, nativeType) {
1401
1494
  return pgIsTextLikeNativeType(nativeType) ? quoted : `${quoted}::${nativeType}`;
1402
1495
  }
1403
1496
  if (wire instanceof Uint8Array) return `'\\x${Array.from(wire).map((b) => b.toString(16).padStart(2, "0")).join("")}'::${nativeType}`;
1497
+ if (Array.isArray(wire) && nativeType.endsWith("[]")) return pgRenderArrayLiteral(wire);
1404
1498
  if (typeof wire === "object") return `${`'${escapeLiteral(JSON.stringify(wire))}'`}::${nativeType}`;
1405
1499
  throw new Error(`pgRenderDdlExecuteRequest: unexpected wire type "${typeof wire}" for native type "${nativeType}"`);
1406
1500
  }
@@ -1460,22 +1554,56 @@ function pgRenderCreateSchema(node) {
1460
1554
  }
1461
1555
  async function pgRenderAlterTable(node, codecLookup) {
1462
1556
  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
- } };
1557
+ const actionVisitor = {
1558
+ async addColumn(action) {
1559
+ return `ADD COLUMN ${await pgRenderDdlColumn(action.column, codecLookup)}`;
1560
+ },
1561
+ dropDefault(action) {
1562
+ return Promise.resolve(`ALTER COLUMN ${quoteIdentifier(action.columnName)} DROP DEFAULT`);
1563
+ }
1564
+ };
1466
1565
  return {
1467
1566
  sql: `ALTER TABLE ${tableRef} ${(await Promise.all(node.actions.map((a) => a.accept(actionVisitor)))).join(", ")}`,
1468
1567
  params: []
1469
1568
  };
1470
1569
  }
1570
+ const POLICY_OPERATION_SQL = {
1571
+ select: "SELECT",
1572
+ insert: "INSERT",
1573
+ update: "UPDATE",
1574
+ delete: "DELETE",
1575
+ all: "ALL"
1576
+ };
1577
+ function pgRenderCreatePolicy(node) {
1578
+ const tableRef = `${quoteIdentifier(node.schema)}.${quoteIdentifier(node.table)}`;
1579
+ const permissiveness = node.permissive ? "PERMISSIVE" : "RESTRICTIVE";
1580
+ const command = POLICY_OPERATION_SQL[node.operation];
1581
+ const roles = node.roles.length === 0 ? "PUBLIC" : node.roles.join(", ");
1582
+ let sql = `CREATE POLICY ${quoteIdentifier(node.name)} ON ${tableRef} AS ${permissiveness} FOR ${command} TO ${roles}`;
1583
+ if (node.using !== void 0) sql += ` USING (${node.using})`;
1584
+ if (node.withCheck !== void 0) sql += ` WITH CHECK (${node.withCheck})`;
1585
+ return {
1586
+ sql,
1587
+ params: []
1588
+ };
1589
+ }
1590
+ function pgRenderDropPolicy(node) {
1591
+ const tableRef = `${quoteIdentifier(node.schema)}.${quoteIdentifier(node.table)}`;
1592
+ return {
1593
+ sql: `DROP POLICY ${quoteIdentifier(node.name)} ON ${tableRef}`,
1594
+ params: []
1595
+ };
1596
+ }
1471
1597
  async function pgRenderDdlExecuteRequest(ast, codecLookup) {
1472
1598
  return ast.accept({
1473
1599
  createTable: (node) => pgRenderCreateTable(node, codecLookup),
1474
1600
  createSchema: (node) => Promise.resolve(pgRenderCreateSchema(node)),
1475
- alterTable: (node) => pgRenderAlterTable(node, codecLookup)
1601
+ alterTable: (node) => pgRenderAlterTable(node, codecLookup),
1602
+ createPolicy: (node) => Promise.resolve(pgRenderCreatePolicy(node)),
1603
+ dropPolicy: (node) => Promise.resolve(pgRenderDropPolicy(node))
1476
1604
  });
1477
1605
  }
1478
1606
  //#endregion
1479
1607
  export { renderLoweredSql as n, createPostgresBuiltinCodecLookup as r, PostgresControlAdapter as t };
1480
1608
 
1481
- //# sourceMappingURL=control-adapter-Dspz5uKp.mjs.map
1609
+ //# sourceMappingURL=control-adapter-AffpjrYN.mjs.map