@prisma-next/adapter-postgres 0.14.0-dev.4 → 0.14.0-dev.41
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-DX2HrqGc.mjs} +4 -3
- package/dist/adapter-DX2HrqGc.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-D5hAI05c.mjs} +172 -54
- package/dist/control-adapter-D5hAI05c.mjs.map +1 -0
- package/dist/control.d.mts +17 -11
- 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 +244 -70
- 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-D5hAI05c.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-DX2HrqGc.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter-DX2HrqGc.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-DX2HrqGc.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,7 +144,7 @@ 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) {
|
|
147
148
|
if (codecId === void 0) return `$${index}`;
|
|
148
149
|
const meta = codecLookup.metaFor(codecId);
|
|
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.`);
|
|
@@ -151,7 +152,11 @@ function renderTypedParam(index, codecId, codecLookup) {
|
|
|
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"
|
|
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);
|
|
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);
|
|
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
|
|
891
|
-
const
|
|
892
|
-
|
|
893
|
-
const
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
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
|
-
*
|
|
923
|
-
* the connection's `current_schema()
|
|
924
|
-
*
|
|
925
|
-
*
|
|
926
|
-
*
|
|
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
|
|
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
|
-
|
|
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
|
|
951
|
-
*
|
|
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
|
|
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,14 @@ 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));
|
|
1108
1117
|
columns[colRow.column_name] = {
|
|
1109
1118
|
name: colRow.column_name,
|
|
1110
1119
|
nativeType,
|
|
1111
1120
|
nullable: colRow.is_nullable === "YES",
|
|
1112
|
-
...ifDefined("default", colRow.column_default ?? void 0)
|
|
1121
|
+
...ifDefined("default", colRow.column_default ?? void 0),
|
|
1122
|
+
...ifDefined("many", many)
|
|
1113
1123
|
};
|
|
1114
1124
|
}
|
|
1115
1125
|
const pkRows = [...pksByTable.get(tableName) ?? []];
|
|
@@ -1191,7 +1201,7 @@ var PostgresControlAdapter = class {
|
|
|
1191
1201
|
permittedValues: parsed.permittedValues
|
|
1192
1202
|
});
|
|
1193
1203
|
}
|
|
1194
|
-
|
|
1204
|
+
tableInputs[tableName] = {
|
|
1195
1205
|
name: tableName,
|
|
1196
1206
|
columns,
|
|
1197
1207
|
...ifDefined("primaryKey", primaryKey),
|
|
@@ -1207,13 +1217,43 @@ var PostgresControlAdapter = class {
|
|
|
1207
1217
|
WHERE t.typtype = 'e'
|
|
1208
1218
|
AND n.nspname = $1
|
|
1209
1219
|
ORDER BY t.typname`, [schema])).rows.map((r) => r.typname);
|
|
1220
|
+
const policiesResult = await driver.query(`SELECT schemaname, tablename, policyname, cmd, roles, qual, with_check, permissive
|
|
1221
|
+
FROM pg_catalog.pg_policies
|
|
1222
|
+
WHERE schemaname = $1
|
|
1223
|
+
ORDER BY tablename, policyname`, [schema]);
|
|
1224
|
+
const policiesByTable = /* @__PURE__ */ new Map();
|
|
1225
|
+
for (const row of policiesResult.rows) {
|
|
1226
|
+
const operation = mapPgCmd(row.cmd);
|
|
1227
|
+
const policyRoles = [...new Set(parsePgNameArray(row.roles).map((r) => r.toLowerCase()))].sort();
|
|
1228
|
+
const permissive = row.permissive.toUpperCase() === "PERMISSIVE";
|
|
1229
|
+
const prefix = /^(.+)_([0-9a-f]{8})$/.exec(row.policyname)?.[1] ?? row.policyname;
|
|
1230
|
+
const policy = new PostgresPolicySchemaNode({
|
|
1231
|
+
name: row.policyname,
|
|
1232
|
+
prefix,
|
|
1233
|
+
tableName: row.tablename,
|
|
1234
|
+
namespaceId: row.schemaname,
|
|
1235
|
+
operation,
|
|
1236
|
+
roles: policyRoles,
|
|
1237
|
+
...row.qual !== null ? { using: row.qual } : {},
|
|
1238
|
+
...row.with_check !== null ? { withCheck: row.with_check } : {},
|
|
1239
|
+
permissive
|
|
1240
|
+
});
|
|
1241
|
+
const list = policiesByTable.get(row.tablename) ?? [];
|
|
1242
|
+
list.push(policy);
|
|
1243
|
+
policiesByTable.set(row.tablename, list);
|
|
1244
|
+
}
|
|
1245
|
+
const tables = {};
|
|
1246
|
+
for (const [tableName, input] of Object.entries(tableInputs)) tables[tableName] = new PostgresTableSchemaNode({
|
|
1247
|
+
...input,
|
|
1248
|
+
policies: policiesByTable.get(tableName) ?? []
|
|
1249
|
+
});
|
|
1210
1250
|
return {
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1251
|
+
namespace: new PostgresNamespaceSchemaNode({
|
|
1252
|
+
schemaName: schema,
|
|
1253
|
+
tables,
|
|
1254
|
+
nativeEnumTypeNames
|
|
1255
|
+
}),
|
|
1256
|
+
pgVersion: await this.getPostgresVersion(driver)
|
|
1217
1257
|
};
|
|
1218
1258
|
}
|
|
1219
1259
|
/**
|
|
@@ -1224,6 +1264,37 @@ var PostgresControlAdapter = class {
|
|
|
1224
1264
|
}
|
|
1225
1265
|
};
|
|
1226
1266
|
/**
|
|
1267
|
+
* Normalises a `name[]` column value from `pg_policies.roles`.
|
|
1268
|
+
*
|
|
1269
|
+
* The `pg` client's type-parser registry handles `text[]` (OID 1009) but not
|
|
1270
|
+
* `name[]` (OID 1003). When the parser is absent the raw Postgres text-array
|
|
1271
|
+
* literal (`{role1,role2}`) is returned as a string instead of a JS array.
|
|
1272
|
+
* This function accepts either form and returns a plain string array.
|
|
1273
|
+
*/
|
|
1274
|
+
function parsePgNameArray(value) {
|
|
1275
|
+
if (Array.isArray(value)) return value;
|
|
1276
|
+
if (typeof value !== "string") return [];
|
|
1277
|
+
const trimmed = value.trim();
|
|
1278
|
+
if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) return [];
|
|
1279
|
+
const inner = trimmed.slice(1, -1);
|
|
1280
|
+
if (inner === "") return [];
|
|
1281
|
+
return inner.split(",").map((s) => s.trim());
|
|
1282
|
+
}
|
|
1283
|
+
/**
|
|
1284
|
+
* Maps `pg_policies.cmd` text values to the `RlsPolicyOperation` union.
|
|
1285
|
+
* The `pg_policies` view renders the internal command code as an uppercase
|
|
1286
|
+
* English keyword; this function lowercases to match the IR type.
|
|
1287
|
+
*/
|
|
1288
|
+
function mapPgCmd(cmd) {
|
|
1289
|
+
switch (cmd.toUpperCase()) {
|
|
1290
|
+
case "SELECT": return "select";
|
|
1291
|
+
case "INSERT": return "insert";
|
|
1292
|
+
case "UPDATE": return "update";
|
|
1293
|
+
case "DELETE": return "delete";
|
|
1294
|
+
default: return "all";
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
/**
|
|
1227
1298
|
* Extracts the namespace coordinate ids declared on a contract's storage,
|
|
1228
1299
|
* or returns an empty array when no contract (or no storage / namespaces)
|
|
1229
1300
|
* is present. Used by `PostgresControlAdapter.introspect` to decide
|
|
@@ -1238,6 +1309,7 @@ function extractContractNamespaceIds(contract) {
|
|
|
1238
1309
|
return Object.keys(namespaces);
|
|
1239
1310
|
}
|
|
1240
1311
|
function normalizeFormattedType(formattedType, dataType, udtName) {
|
|
1312
|
+
if (formattedType.endsWith("[]")) return `${normalizeFormattedType(formattedType.slice(0, -2), dataType, udtName)}[]`;
|
|
1241
1313
|
if (formattedType === "integer") return "int4";
|
|
1242
1314
|
if (formattedType === "smallint") return "int2";
|
|
1243
1315
|
if (formattedType === "bigint") return "int8";
|
|
@@ -1383,6 +1455,16 @@ function extractQuotedLiterals(listBody) {
|
|
|
1383
1455
|
function pgIsTextLikeNativeType(nativeType) {
|
|
1384
1456
|
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
1457
|
}
|
|
1458
|
+
function pgRenderArrayElement(el) {
|
|
1459
|
+
if (el === null) return "NULL";
|
|
1460
|
+
if (typeof el === "number" || typeof el === "boolean") return String(el);
|
|
1461
|
+
if (typeof el === "string") return `'${escapeLiteral(el)}'`;
|
|
1462
|
+
return `'${escapeLiteral(JSON.stringify(el))}'`;
|
|
1463
|
+
}
|
|
1464
|
+
function pgRenderArrayLiteral(elements) {
|
|
1465
|
+
if (elements.length === 0) return "'{}'";
|
|
1466
|
+
return `ARRAY[${elements.map(pgRenderArrayElement).join(", ")}]`;
|
|
1467
|
+
}
|
|
1386
1468
|
function pgInlineLiteral(wire, nativeType) {
|
|
1387
1469
|
if (wire === null) return "NULL";
|
|
1388
1470
|
if (typeof wire === "boolean") return wire ? "true" : "false";
|
|
@@ -1401,6 +1483,7 @@ function pgInlineLiteral(wire, nativeType) {
|
|
|
1401
1483
|
return pgIsTextLikeNativeType(nativeType) ? quoted : `${quoted}::${nativeType}`;
|
|
1402
1484
|
}
|
|
1403
1485
|
if (wire instanceof Uint8Array) return `'\\x${Array.from(wire).map((b) => b.toString(16).padStart(2, "0")).join("")}'::${nativeType}`;
|
|
1486
|
+
if (Array.isArray(wire) && nativeType.endsWith("[]")) return pgRenderArrayLiteral(wire);
|
|
1404
1487
|
if (typeof wire === "object") return `${`'${escapeLiteral(JSON.stringify(wire))}'`}::${nativeType}`;
|
|
1405
1488
|
throw new Error(`pgRenderDdlExecuteRequest: unexpected wire type "${typeof wire}" for native type "${nativeType}"`);
|
|
1406
1489
|
}
|
|
@@ -1438,6 +1521,7 @@ function pgRenderDdlConstraint(constraint) {
|
|
|
1438
1521
|
if (constraint.name !== void 0) sql = `CONSTRAINT ${quoteIdentifier(constraint.name)} ${sql}`;
|
|
1439
1522
|
return sql;
|
|
1440
1523
|
}
|
|
1524
|
+
if (constraint.kind === "check-expression") return `CONSTRAINT ${quoteIdentifier(constraint.name)} CHECK (${constraint.expression})`;
|
|
1441
1525
|
const cols = constraint.columns.map(quoteIdentifier).join(", ");
|
|
1442
1526
|
if (constraint.name !== void 0) return `CONSTRAINT ${quoteIdentifier(constraint.name)} UNIQUE (${cols})`;
|
|
1443
1527
|
return `UNIQUE (${cols})`;
|
|
@@ -1460,22 +1544,56 @@ function pgRenderCreateSchema(node) {
|
|
|
1460
1544
|
}
|
|
1461
1545
|
async function pgRenderAlterTable(node, codecLookup) {
|
|
1462
1546
|
const tableRef = node.schema ? `${quoteIdentifier(node.schema)}.${quoteIdentifier(node.table)}` : quoteIdentifier(node.table);
|
|
1463
|
-
const actionVisitor = {
|
|
1464
|
-
|
|
1465
|
-
|
|
1547
|
+
const actionVisitor = {
|
|
1548
|
+
async addColumn(action) {
|
|
1549
|
+
return `ADD COLUMN ${await pgRenderDdlColumn(action.column, codecLookup)}`;
|
|
1550
|
+
},
|
|
1551
|
+
dropDefault(action) {
|
|
1552
|
+
return Promise.resolve(`ALTER COLUMN ${quoteIdentifier(action.columnName)} DROP DEFAULT`);
|
|
1553
|
+
}
|
|
1554
|
+
};
|
|
1466
1555
|
return {
|
|
1467
1556
|
sql: `ALTER TABLE ${tableRef} ${(await Promise.all(node.actions.map((a) => a.accept(actionVisitor)))).join(", ")}`,
|
|
1468
1557
|
params: []
|
|
1469
1558
|
};
|
|
1470
1559
|
}
|
|
1560
|
+
const POLICY_OPERATION_SQL = {
|
|
1561
|
+
select: "SELECT",
|
|
1562
|
+
insert: "INSERT",
|
|
1563
|
+
update: "UPDATE",
|
|
1564
|
+
delete: "DELETE",
|
|
1565
|
+
all: "ALL"
|
|
1566
|
+
};
|
|
1567
|
+
function pgRenderCreatePolicy(node) {
|
|
1568
|
+
const tableRef = `${quoteIdentifier(node.schema)}.${quoteIdentifier(node.table)}`;
|
|
1569
|
+
const permissiveness = node.permissive ? "PERMISSIVE" : "RESTRICTIVE";
|
|
1570
|
+
const command = POLICY_OPERATION_SQL[node.operation];
|
|
1571
|
+
const roles = node.roles.length === 0 ? "PUBLIC" : node.roles.join(", ");
|
|
1572
|
+
let sql = `CREATE POLICY ${quoteIdentifier(node.name)} ON ${tableRef} AS ${permissiveness} FOR ${command} TO ${roles}`;
|
|
1573
|
+
if (node.using !== void 0) sql += ` USING (${node.using})`;
|
|
1574
|
+
if (node.withCheck !== void 0) sql += ` WITH CHECK (${node.withCheck})`;
|
|
1575
|
+
return {
|
|
1576
|
+
sql,
|
|
1577
|
+
params: []
|
|
1578
|
+
};
|
|
1579
|
+
}
|
|
1580
|
+
function pgRenderDropPolicy(node) {
|
|
1581
|
+
const tableRef = `${quoteIdentifier(node.schema)}.${quoteIdentifier(node.table)}`;
|
|
1582
|
+
return {
|
|
1583
|
+
sql: `DROP POLICY ${quoteIdentifier(node.name)} ON ${tableRef}`,
|
|
1584
|
+
params: []
|
|
1585
|
+
};
|
|
1586
|
+
}
|
|
1471
1587
|
async function pgRenderDdlExecuteRequest(ast, codecLookup) {
|
|
1472
1588
|
return ast.accept({
|
|
1473
1589
|
createTable: (node) => pgRenderCreateTable(node, codecLookup),
|
|
1474
1590
|
createSchema: (node) => Promise.resolve(pgRenderCreateSchema(node)),
|
|
1475
|
-
alterTable: (node) => pgRenderAlterTable(node, codecLookup)
|
|
1591
|
+
alterTable: (node) => pgRenderAlterTable(node, codecLookup),
|
|
1592
|
+
createPolicy: (node) => Promise.resolve(pgRenderCreatePolicy(node)),
|
|
1593
|
+
dropPolicy: (node) => Promise.resolve(pgRenderDropPolicy(node))
|
|
1476
1594
|
});
|
|
1477
1595
|
}
|
|
1478
1596
|
//#endregion
|
|
1479
1597
|
export { renderLoweredSql as n, createPostgresBuiltinCodecLookup as r, PostgresControlAdapter as t };
|
|
1480
1598
|
|
|
1481
|
-
//# sourceMappingURL=control-adapter-
|
|
1599
|
+
//# sourceMappingURL=control-adapter-D5hAI05c.mjs.map
|