@prisma-next/adapter-postgres 0.14.0-dev.2 → 0.14.0-dev.20
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.
- package/dist/{adapter-CwkcdpM_.mjs → adapter-BvM9axNH.mjs} +4 -3
- package/dist/adapter-BvM9axNH.mjs.map +1 -0
- package/dist/adapter.d.mts.map +1 -1
- package/dist/adapter.mjs +1 -1
- package/dist/{control-adapter-Dspz5uKp.mjs → control-adapter-AffpjrYN.mjs} +165 -37
- package/dist/control-adapter-AffpjrYN.mjs.map +1 -0
- package/dist/control.d.mts +6 -3
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +2 -2
- package/dist/{descriptor-meta-DOgMfoqm.mjs → descriptor-meta-DnWlLrI6.mjs} +3 -2
- package/dist/descriptor-meta-DnWlLrI6.mjs.map +1 -0
- package/dist/runtime.mjs +2 -2
- package/package.json +23 -22
- package/src/core/adapter.ts +1 -0
- package/src/core/control-adapter.ts +222 -41
- package/src/core/descriptor-meta.ts +1 -0
- package/src/core/sql-renderer.ts +11 -4
- package/dist/adapter-CwkcdpM_.mjs.map +0 -1
- package/dist/control-adapter-Dspz5uKp.mjs.map +0 -1
- package/dist/descriptor-meta-DOgMfoqm.mjs.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as renderLoweredSql, r as createPostgresBuiltinCodecLookup, t as PostgresControlAdapter } from "./control-adapter-
|
|
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-
|
|
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"}
|
package/dist/adapter.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.mts","names":[],"sources":["../src/core/adapter.ts"],"mappings":";;;;;;
|
|
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-
|
|
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"
|
|
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
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
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
|
|
940
|
-
const
|
|
941
|
-
|
|
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
|
-
|
|
944
|
-
|
|
945
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
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 = {
|
|
1464
|
-
|
|
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-
|
|
1609
|
+
//# sourceMappingURL=control-adapter-AffpjrYN.mjs.map
|