@prisma-next/adapter-postgres 0.14.0-dev.3 → 0.14.0-dev.30
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-C9_442Ul.mjs} +4 -3
- package/dist/adapter-C9_442Ul.mjs.map +1 -0
- package/dist/adapter.d.mts +1 -1
- package/dist/adapter.d.mts.map +1 -1
- package/dist/adapter.mjs +1 -1
- package/dist/{control-adapter-Dspz5uKp.mjs → control-adapter-QeICiKLE.mjs} +170 -40
- package/dist/control-adapter-QeICiKLE.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.d.mts +1 -1
- package/dist/runtime.mjs +2 -2
- package/dist/{types-KXRwRZU8.d.mts → types-DkGeLfUp.d.mts} +3 -6
- package/dist/types-DkGeLfUp.d.mts.map +1 -0
- package/dist/types.d.mts +1 -1
- package/package.json +23 -22
- package/src/core/adapter.ts +1 -0
- package/src/core/control-adapter.ts +261 -45
- package/src/core/descriptor-meta.ts +1 -0
- package/src/core/sql-renderer.ts +11 -4
- package/src/core/types.ts +2 -3
- 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
- package/dist/types-KXRwRZU8.d.mts.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-QeICiKLE.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-C9_442Ul.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter-C9_442Ul.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
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as PostgresContract, l as PostgresLoweredStatement, s as PostgresAdapterOptions } from "./types-
|
|
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";
|
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-C9_442Ul.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 { contractToPostgresSchemaIR, diffPostgresSchema, filterIssuesByOwnership } from "@prisma-next/target-postgres/planner";
|
|
11
12
|
import { escapeLiteral, quoteIdentifier } from "@prisma-next/target-postgres/sql-utils";
|
|
13
|
+
import { PostgresRlsPolicy, PostgresRole, PostgresSchemaIR, PostgresTableIR, ensurePostgresSchemaIR, 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,11 @@ 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(`Postgres schema diff requires a PostgresSchemaIR; got ${schema.constructor?.name ?? typeof schema}`);
|
|
675
|
+
const expected = contractToPostgresSchemaIR(blindCast(contract), { annotationNamespace: "pg" });
|
|
676
|
+
return filterIssuesByOwnership(diffPostgresSchema(expected, ensurePostgresSchemaIR(schema)), new Set([...expected.rlsPolicies.map((p) => p.namespaceId), ...expected.existingSchemas]));
|
|
677
|
+
}
|
|
667
678
|
bootstrapControlTableQueries() {
|
|
668
679
|
return buildControlTableBootstrapQueries();
|
|
669
680
|
}
|
|
@@ -889,18 +900,14 @@ var PostgresControlAdapter = class {
|
|
|
889
900
|
const declaredNamespaces = extractContractNamespaceIds(contract);
|
|
890
901
|
const ir = declaredNamespaces.length > 0 ? await this.introspectNamespaces(driver, declaredNamespaces) : await this.introspectSchema(driver, schema);
|
|
891
902
|
const existingSchemas = await this.listExistingSchemas(driver);
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
existingSchemas
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
};
|
|
903
|
+
return new PostgresSchemaIR({
|
|
904
|
+
tables: ir.tables,
|
|
905
|
+
pgSchemaName: ir.pgSchemaName,
|
|
906
|
+
pgVersion: ir.pgVersion,
|
|
907
|
+
roles: ir.roles,
|
|
908
|
+
existingSchemas,
|
|
909
|
+
nativeEnumTypeNames: ir.nativeEnumTypeNames
|
|
910
|
+
});
|
|
904
911
|
}
|
|
905
912
|
/**
|
|
906
913
|
* Lists every non-system schema present in the connected database.
|
|
@@ -935,16 +942,20 @@ var PostgresControlAdapter = class {
|
|
|
935
942
|
const perSchema = [];
|
|
936
943
|
for (const schema of uniqueSchemas) perSchema.push(await this.introspectSchema(driver, schema));
|
|
937
944
|
const mergedTables = {};
|
|
938
|
-
|
|
939
|
-
const
|
|
940
|
-
|
|
941
|
-
|
|
945
|
+
const mergedRoles = [];
|
|
946
|
+
for (const ir of perSchema) {
|
|
947
|
+
for (const [tableName, table] of Object.entries(ir.tables)) mergedTables[tableName] = table;
|
|
948
|
+
mergedRoles.push(...ir.roles);
|
|
949
|
+
}
|
|
950
|
+
const first = perSchema[0];
|
|
951
|
+
return new PostgresSchemaIR({
|
|
942
952
|
tables: mergedTables,
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
953
|
+
pgSchemaName: first?.pgSchemaName ?? "public",
|
|
954
|
+
pgVersion: first?.pgVersion ?? "unknown",
|
|
955
|
+
roles: mergedRoles,
|
|
956
|
+
existingSchemas: first?.existingSchemas ?? ["public"],
|
|
957
|
+
nativeEnumTypeNames: first?.nativeEnumTypeNames ?? []
|
|
958
|
+
});
|
|
948
959
|
}
|
|
949
960
|
/**
|
|
950
961
|
* Introspects a single Postgres schema and returns a raw SqlSchemaIR
|
|
@@ -1091,7 +1102,7 @@ var PostgresControlAdapter = class {
|
|
|
1091
1102
|
}
|
|
1092
1103
|
constraints.add(row.constraint_name);
|
|
1093
1104
|
}
|
|
1094
|
-
const
|
|
1105
|
+
const tableInputs = {};
|
|
1095
1106
|
for (const tableRow of tablesResult.rows) {
|
|
1096
1107
|
const tableName = tableRow.table_name;
|
|
1097
1108
|
const columns = {};
|
|
@@ -1105,11 +1116,14 @@ var PostgresControlAdapter = class {
|
|
|
1105
1116
|
else if (colRow.numeric_precision) nativeType = `${colRow.data_type}(${colRow.numeric_precision})`;
|
|
1106
1117
|
else nativeType = colRow.data_type;
|
|
1107
1118
|
else nativeType = colRow.udt_name || colRow.data_type;
|
|
1119
|
+
const many = nativeType.endsWith("[]") ? true : void 0;
|
|
1120
|
+
if (many) nativeType = normalizeSchemaNativeType(nativeType.slice(0, -2));
|
|
1108
1121
|
columns[colRow.column_name] = {
|
|
1109
1122
|
name: colRow.column_name,
|
|
1110
1123
|
nativeType,
|
|
1111
1124
|
nullable: colRow.is_nullable === "YES",
|
|
1112
|
-
...ifDefined("default", colRow.column_default ?? void 0)
|
|
1125
|
+
...ifDefined("default", colRow.column_default ?? void 0),
|
|
1126
|
+
...ifDefined("many", many)
|
|
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
|
-
|
|
1208
|
+
tableInputs[tableName] = {
|
|
1195
1209
|
name: tableName,
|
|
1196
1210
|
columns,
|
|
1197
1211
|
...ifDefined("primaryKey", primaryKey),
|
|
@@ -1207,14 +1221,53 @@ 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);
|
|
1210
|
-
|
|
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 rolesResult = await driver.query(`SELECT rolname
|
|
1229
|
+
FROM pg_catalog.pg_roles
|
|
1230
|
+
WHERE rolname NOT LIKE 'pg_%'
|
|
1231
|
+
AND rolname != 'postgres'
|
|
1232
|
+
ORDER BY rolname`);
|
|
1233
|
+
const policiesByTable = /* @__PURE__ */ new Map();
|
|
1234
|
+
for (const row of policiesResult.rows) {
|
|
1235
|
+
const operation = mapPgCmd(row.cmd);
|
|
1236
|
+
const policyRoles = [...new Set(parsePgNameArray(row.roles).map((r) => r.toLowerCase()))].sort();
|
|
1237
|
+
const permissive = row.permissive.toUpperCase() === "PERMISSIVE";
|
|
1238
|
+
const prefix = /^(.+)_([0-9a-f]{8})$/.exec(row.policyname)?.[1] ?? row.policyname;
|
|
1239
|
+
const policy = new PostgresRlsPolicy({
|
|
1240
|
+
name: row.policyname,
|
|
1241
|
+
prefix,
|
|
1242
|
+
tableName: row.tablename,
|
|
1243
|
+
namespaceId: row.schemaname,
|
|
1244
|
+
operation,
|
|
1245
|
+
roles: policyRoles,
|
|
1246
|
+
...row.qual !== null ? { using: row.qual } : {},
|
|
1247
|
+
...row.with_check !== null ? { withCheck: row.with_check } : {},
|
|
1248
|
+
permissive
|
|
1249
|
+
});
|
|
1250
|
+
const list = policiesByTable.get(row.tablename) ?? [];
|
|
1251
|
+
list.push(policy);
|
|
1252
|
+
policiesByTable.set(row.tablename, list);
|
|
1253
|
+
}
|
|
1254
|
+
const tables = {};
|
|
1255
|
+
for (const [tableName, input] of Object.entries(tableInputs)) tables[tableName] = new PostgresTableIR({
|
|
1256
|
+
...input,
|
|
1257
|
+
rlsPolicies: policiesByTable.get(tableName) ?? []
|
|
1258
|
+
});
|
|
1259
|
+
const roles = rolesResult.rows.map((row) => new PostgresRole({
|
|
1260
|
+
name: row.rolname,
|
|
1261
|
+
namespaceId: UNBOUND_NAMESPACE_ID
|
|
1262
|
+
}));
|
|
1263
|
+
return new PostgresSchemaIR({
|
|
1211
1264
|
tables,
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
};
|
|
1265
|
+
pgSchemaName: schema,
|
|
1266
|
+
pgVersion: await this.getPostgresVersion(driver),
|
|
1267
|
+
roles,
|
|
1268
|
+
existingSchemas: [],
|
|
1269
|
+
nativeEnumTypeNames
|
|
1270
|
+
});
|
|
1218
1271
|
}
|
|
1219
1272
|
/**
|
|
1220
1273
|
* Gets the Postgres version from the database.
|
|
@@ -1224,6 +1277,37 @@ var PostgresControlAdapter = class {
|
|
|
1224
1277
|
}
|
|
1225
1278
|
};
|
|
1226
1279
|
/**
|
|
1280
|
+
* Normalises a `name[]` column value from `pg_policies.roles`.
|
|
1281
|
+
*
|
|
1282
|
+
* The `pg` client's type-parser registry handles `text[]` (OID 1009) but not
|
|
1283
|
+
* `name[]` (OID 1003). When the parser is absent the raw Postgres text-array
|
|
1284
|
+
* literal (`{role1,role2}`) is returned as a string instead of a JS array.
|
|
1285
|
+
* This function accepts either form and returns a plain string array.
|
|
1286
|
+
*/
|
|
1287
|
+
function parsePgNameArray(value) {
|
|
1288
|
+
if (Array.isArray(value)) return value;
|
|
1289
|
+
if (typeof value !== "string") return [];
|
|
1290
|
+
const trimmed = value.trim();
|
|
1291
|
+
if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) return [];
|
|
1292
|
+
const inner = trimmed.slice(1, -1);
|
|
1293
|
+
if (inner === "") return [];
|
|
1294
|
+
return inner.split(",").map((s) => s.trim());
|
|
1295
|
+
}
|
|
1296
|
+
/**
|
|
1297
|
+
* Maps `pg_policies.cmd` text values to the `RlsPolicyOperation` union.
|
|
1298
|
+
* The `pg_policies` view renders the internal command code as an uppercase
|
|
1299
|
+
* English keyword; this function lowercases to match the IR type.
|
|
1300
|
+
*/
|
|
1301
|
+
function mapPgCmd(cmd) {
|
|
1302
|
+
switch (cmd.toUpperCase()) {
|
|
1303
|
+
case "SELECT": return "select";
|
|
1304
|
+
case "INSERT": return "insert";
|
|
1305
|
+
case "UPDATE": return "update";
|
|
1306
|
+
case "DELETE": return "delete";
|
|
1307
|
+
default: return "all";
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
/**
|
|
1227
1311
|
* Extracts the namespace coordinate ids declared on a contract's storage,
|
|
1228
1312
|
* or returns an empty array when no contract (or no storage / namespaces)
|
|
1229
1313
|
* is present. Used by `PostgresControlAdapter.introspect` to decide
|
|
@@ -1238,6 +1322,7 @@ function extractContractNamespaceIds(contract) {
|
|
|
1238
1322
|
return Object.keys(namespaces);
|
|
1239
1323
|
}
|
|
1240
1324
|
function normalizeFormattedType(formattedType, dataType, udtName) {
|
|
1325
|
+
if (formattedType.endsWith("[]")) return `${normalizeFormattedType(formattedType.slice(0, -2), dataType, udtName)}[]`;
|
|
1241
1326
|
if (formattedType === "integer") return "int4";
|
|
1242
1327
|
if (formattedType === "smallint") return "int2";
|
|
1243
1328
|
if (formattedType === "bigint") return "int8";
|
|
@@ -1383,6 +1468,16 @@ function extractQuotedLiterals(listBody) {
|
|
|
1383
1468
|
function pgIsTextLikeNativeType(nativeType) {
|
|
1384
1469
|
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
1470
|
}
|
|
1471
|
+
function pgRenderArrayElement(el) {
|
|
1472
|
+
if (el === null) return "NULL";
|
|
1473
|
+
if (typeof el === "number" || typeof el === "boolean") return String(el);
|
|
1474
|
+
if (typeof el === "string") return `'${escapeLiteral(el)}'`;
|
|
1475
|
+
return `'${escapeLiteral(JSON.stringify(el))}'`;
|
|
1476
|
+
}
|
|
1477
|
+
function pgRenderArrayLiteral(elements) {
|
|
1478
|
+
if (elements.length === 0) return "'{}'";
|
|
1479
|
+
return `ARRAY[${elements.map(pgRenderArrayElement).join(", ")}]`;
|
|
1480
|
+
}
|
|
1386
1481
|
function pgInlineLiteral(wire, nativeType) {
|
|
1387
1482
|
if (wire === null) return "NULL";
|
|
1388
1483
|
if (typeof wire === "boolean") return wire ? "true" : "false";
|
|
@@ -1401,6 +1496,7 @@ function pgInlineLiteral(wire, nativeType) {
|
|
|
1401
1496
|
return pgIsTextLikeNativeType(nativeType) ? quoted : `${quoted}::${nativeType}`;
|
|
1402
1497
|
}
|
|
1403
1498
|
if (wire instanceof Uint8Array) return `'\\x${Array.from(wire).map((b) => b.toString(16).padStart(2, "0")).join("")}'::${nativeType}`;
|
|
1499
|
+
if (Array.isArray(wire) && nativeType.endsWith("[]")) return pgRenderArrayLiteral(wire);
|
|
1404
1500
|
if (typeof wire === "object") return `${`'${escapeLiteral(JSON.stringify(wire))}'`}::${nativeType}`;
|
|
1405
1501
|
throw new Error(`pgRenderDdlExecuteRequest: unexpected wire type "${typeof wire}" for native type "${nativeType}"`);
|
|
1406
1502
|
}
|
|
@@ -1460,22 +1556,56 @@ function pgRenderCreateSchema(node) {
|
|
|
1460
1556
|
}
|
|
1461
1557
|
async function pgRenderAlterTable(node, codecLookup) {
|
|
1462
1558
|
const tableRef = node.schema ? `${quoteIdentifier(node.schema)}.${quoteIdentifier(node.table)}` : quoteIdentifier(node.table);
|
|
1463
|
-
const actionVisitor = {
|
|
1464
|
-
|
|
1465
|
-
|
|
1559
|
+
const actionVisitor = {
|
|
1560
|
+
async addColumn(action) {
|
|
1561
|
+
return `ADD COLUMN ${await pgRenderDdlColumn(action.column, codecLookup)}`;
|
|
1562
|
+
},
|
|
1563
|
+
dropDefault(action) {
|
|
1564
|
+
return Promise.resolve(`ALTER COLUMN ${quoteIdentifier(action.columnName)} DROP DEFAULT`);
|
|
1565
|
+
}
|
|
1566
|
+
};
|
|
1466
1567
|
return {
|
|
1467
1568
|
sql: `ALTER TABLE ${tableRef} ${(await Promise.all(node.actions.map((a) => a.accept(actionVisitor)))).join(", ")}`,
|
|
1468
1569
|
params: []
|
|
1469
1570
|
};
|
|
1470
1571
|
}
|
|
1572
|
+
const POLICY_OPERATION_SQL = {
|
|
1573
|
+
select: "SELECT",
|
|
1574
|
+
insert: "INSERT",
|
|
1575
|
+
update: "UPDATE",
|
|
1576
|
+
delete: "DELETE",
|
|
1577
|
+
all: "ALL"
|
|
1578
|
+
};
|
|
1579
|
+
function pgRenderCreatePolicy(node) {
|
|
1580
|
+
const tableRef = `${quoteIdentifier(node.schema)}.${quoteIdentifier(node.table)}`;
|
|
1581
|
+
const permissiveness = node.permissive ? "PERMISSIVE" : "RESTRICTIVE";
|
|
1582
|
+
const command = POLICY_OPERATION_SQL[node.operation];
|
|
1583
|
+
const roles = node.roles.length === 0 ? "PUBLIC" : node.roles.join(", ");
|
|
1584
|
+
let sql = `CREATE POLICY ${quoteIdentifier(node.name)} ON ${tableRef} AS ${permissiveness} FOR ${command} TO ${roles}`;
|
|
1585
|
+
if (node.using !== void 0) sql += ` USING (${node.using})`;
|
|
1586
|
+
if (node.withCheck !== void 0) sql += ` WITH CHECK (${node.withCheck})`;
|
|
1587
|
+
return {
|
|
1588
|
+
sql,
|
|
1589
|
+
params: []
|
|
1590
|
+
};
|
|
1591
|
+
}
|
|
1592
|
+
function pgRenderDropPolicy(node) {
|
|
1593
|
+
const tableRef = `${quoteIdentifier(node.schema)}.${quoteIdentifier(node.table)}`;
|
|
1594
|
+
return {
|
|
1595
|
+
sql: `DROP POLICY ${quoteIdentifier(node.name)} ON ${tableRef}`,
|
|
1596
|
+
params: []
|
|
1597
|
+
};
|
|
1598
|
+
}
|
|
1471
1599
|
async function pgRenderDdlExecuteRequest(ast, codecLookup) {
|
|
1472
1600
|
return ast.accept({
|
|
1473
1601
|
createTable: (node) => pgRenderCreateTable(node, codecLookup),
|
|
1474
1602
|
createSchema: (node) => Promise.resolve(pgRenderCreateSchema(node)),
|
|
1475
|
-
alterTable: (node) => pgRenderAlterTable(node, codecLookup)
|
|
1603
|
+
alterTable: (node) => pgRenderAlterTable(node, codecLookup),
|
|
1604
|
+
createPolicy: (node) => Promise.resolve(pgRenderCreatePolicy(node)),
|
|
1605
|
+
dropPolicy: (node) => Promise.resolve(pgRenderDropPolicy(node))
|
|
1476
1606
|
});
|
|
1477
1607
|
}
|
|
1478
1608
|
//#endregion
|
|
1479
1609
|
export { renderLoweredSql as n, createPostgresBuiltinCodecLookup as r, PostgresControlAdapter as t };
|
|
1480
1610
|
|
|
1481
|
-
//# sourceMappingURL=control-adapter-
|
|
1611
|
+
//# sourceMappingURL=control-adapter-QeICiKLE.mjs.map
|