@prisma-next/adapter-postgres 0.14.0-dev.39 → 0.14.0-dev.40
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-i3d2XWIq.mjs → adapter-DX2HrqGc.mjs} +2 -2
- package/dist/{adapter-i3d2XWIq.mjs.map → adapter-DX2HrqGc.mjs.map} +1 -1
- package/dist/adapter.mjs +1 -1
- package/dist/{control-adapter-BdWK3EV1.mjs → control-adapter-D5hAI05c.mjs} +50 -63
- package/dist/control-adapter-D5hAI05c.mjs.map +1 -0
- package/dist/control.d.mts +18 -15
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +1 -1
- package/dist/runtime.mjs +1 -1
- package/package.json +23 -23
- package/src/core/control-adapter.ts +68 -113
- package/dist/control-adapter-BdWK3EV1.mjs.map +0 -1
package/dist/control.d.mts
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
import { SchemaDiffIssue } from "@prisma-next/framework-components/control";
|
|
2
1
|
import { AnyQueryAst, DdlNode, LoweredStatement, LowererContext, MarkerReadResult, SqlExecuteRequest } from "@prisma-next/sql-relational-core/ast";
|
|
3
2
|
import { parsePostgresDefault, parsePostgresDefault as parsePostgresDefault$1 } from "@prisma-next/target-postgres/default-normalizer";
|
|
4
3
|
import { normalizeSchemaNativeType, normalizeSchemaNativeType as normalizeSchemaNativeType$1 } from "@prisma-next/target-postgres/native-type-normalizer";
|
|
5
4
|
import { SqlEscapeError, escapeLiteral, qualifyName, quoteIdentifier } from "@prisma-next/target-postgres/sql-utils";
|
|
6
|
-
import {
|
|
5
|
+
import { PostgresDatabaseSchemaNode } from "@prisma-next/target-postgres/types";
|
|
7
6
|
import { SqlControlAdapterDescriptor } from "@prisma-next/family-sql/control";
|
|
8
7
|
import { PostgresDdlNode } from "@prisma-next/target-postgres/ddl";
|
|
9
8
|
import { CodecRegistry } from "@prisma-next/framework-components/codec";
|
|
10
|
-
import { SqlControlDriverInstance
|
|
11
|
-
import {
|
|
9
|
+
import { SqlControlDriverInstance } from "@prisma-next/sql-contract/types";
|
|
10
|
+
import { ContractMarkerRecord, LedgerEntryRecord } from "@prisma-next/contract/types";
|
|
12
11
|
import { SqlControlAdapter } from "@prisma-next/family-sql/control-adapter";
|
|
13
|
-
import { SqlSchemaIR } from "@prisma-next/sql-schema-ir/types";
|
|
14
12
|
|
|
15
13
|
//#region src/core/codec-lookup.d.ts
|
|
16
14
|
/**
|
|
@@ -43,7 +41,6 @@ declare class PostgresControlAdapter implements SqlControlAdapter<'postgres'> {
|
|
|
43
41
|
* before comparison with contract native types.
|
|
44
42
|
*/
|
|
45
43
|
readonly normalizeNativeType: typeof normalizeSchemaNativeType$1;
|
|
46
|
-
collectSchemaDiffIssues(contract: Contract<SqlStorage>, schema: SqlSchemaIR): readonly SchemaDiffIssue[];
|
|
47
44
|
bootstrapControlTableQueries(): readonly DdlNode[];
|
|
48
45
|
bootstrapSignMarkerQueries(): readonly DdlNode[];
|
|
49
46
|
/**
|
|
@@ -151,7 +148,12 @@ declare class PostgresControlAdapter implements SqlControlAdapter<'postgres'> {
|
|
|
151
148
|
* @param schema - Schema name to introspect when no contract is provided (defaults to 'public')
|
|
152
149
|
* @returns Promise resolving to SqlSchemaIR representing the live database schema
|
|
153
150
|
*/
|
|
154
|
-
introspect(driver: SqlControlDriverInstance<'postgres'>, contract?: unknown, schema?: string): Promise<
|
|
151
|
+
introspect(driver: SqlControlDriverInstance<'postgres'>, contract?: unknown, schema?: string): Promise<PostgresDatabaseSchemaNode>;
|
|
152
|
+
/**
|
|
153
|
+
* Reads cluster-scoped database roles. Roles are not schema-qualified, so
|
|
154
|
+
* this is queried once for the whole database rather than per namespace.
|
|
155
|
+
*/
|
|
156
|
+
private introspectRoles;
|
|
155
157
|
/**
|
|
156
158
|
* Lists every non-system schema present in the connected database.
|
|
157
159
|
* The introspection consumer (`verifyPostgresNamespacePresence`)
|
|
@@ -162,16 +164,17 @@ declare class PostgresControlAdapter implements SqlControlAdapter<'postgres'> {
|
|
|
162
164
|
*/
|
|
163
165
|
private listExistingSchemas;
|
|
164
166
|
/**
|
|
165
|
-
*
|
|
166
|
-
* the connection's `current_schema()
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
*
|
|
167
|
+
* Resolves the declared namespace ids to their live DDL schema names,
|
|
168
|
+
* mapping `UNBOUND_NAMESPACE_ID` to the connection's `current_schema()`
|
|
169
|
+
* and de-duplicating. The caller introspects one namespace node per
|
|
170
|
+
* resolved schema — there is no flat cross-schema merge, so two schemas
|
|
171
|
+
* holding a same-named table no longer collide.
|
|
170
172
|
*/
|
|
171
|
-
private
|
|
173
|
+
private resolveNamespaceSchemas;
|
|
172
174
|
/**
|
|
173
|
-
* Introspects a single Postgres schema and returns
|
|
174
|
-
*
|
|
175
|
+
* Introspects a single Postgres schema and returns the namespace node for
|
|
176
|
+
* that schema (its tables, their policies, and its native enum type names),
|
|
177
|
+
* alongside the cluster-scoped Postgres version. Used by `introspect` as
|
|
175
178
|
* the per-namespace walk.
|
|
176
179
|
*/
|
|
177
180
|
private introspectSchema;
|
package/dist/control.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control.d.mts","names":[],"sources":["../src/core/codec-lookup.ts","../src/core/control-adapter.ts","../src/exports/control.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"control.d.mts","names":[],"sources":["../src/core/codec-lookup.ts","../src/core/control-adapter.ts","../src/exports/control.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;iBAWgB,gCAAA,IAAoC,aAAa;;;;;;;cCqFpD,sBAAA,YAAkC,iBAAA;EAAA,SACpC,QAAA;EAAA,SACA,QAAA;EAAA,iBAEQ,aAAA;cAEL,aAAA,EAAe,aAAA;;;;AAN7B;WAcW,gBAAA,SAAgB,sBAAA;;;;;;WAOhB,mBAAA,SAAmB,2BAAA;EAE5B,4BAAA,aAAyC,OAAA;EAIzC,0BAAA,aAAuC,OAAA;EAYY;;;;;;;;EAAnD,KAAA,CAAM,GAAA,EAAK,WAAA,GAAc,eAAA,EAAiB,OAAA,EAAS,cAAA,YAA0B,gBAAA;EAuD1E;;;;;;;EAjCG,qBAAA,CACJ,GAAA,EAAK,WAAA,GAAc,eAAA,EACnB,OAAA,GAAU,cAAA,YACT,OAAA,CAAQ,iBAAA;EAkHD;;;;;;;;EAvFJ,UAAA,CACJ,MAAA,EAAQ,wBAAA,cACR,KAAA,WACC,OAAA,CAAQ,oBAAA;EAKL,uBAAA,CACJ,MAAA,EAAQ,wBAAA,cACR,KAAA,WACC,OAAA,CAAQ,gBAAA;EAgQR;;;;;;EArPG,cAAA,CACJ,MAAA,EAAQ,wBAAA,eACP,OAAA,CAAQ,WAAA,SAAoB,oBAAA;EAAA,QAKjB,oBAAA;EAvHL;;;;;;EAgLH,UAAA,CACJ,MAAA,EAAQ,wBAAA,cACR,KAAA,YACC,OAAA,UAAiB,iBAAA;EAAA,QAKN,gBAAA;EApKL;;;;;EAwNH,YAAA,CACJ,MAAA,EAAQ,wBAAA,cACR,KAAA,UACA,WAAA;IAAA,SACW,WAAA;IAAA,SACA,WAAA;IAAA,SACA,UAAA;EAAA,IAEV,OAAA;EAoBG,UAAA,CACJ,MAAA,EAAQ,wBAAA,cACR,KAAA,UACA,WAAA;IAAA,SACW,WAAA;IAAA,SACA,WAAA;IAAA,SACA,UAAA;EAAA,IAEV,OAAA;EAnNkB;;;;EAsPf,YAAA,CACJ,MAAA,EAAQ,wBAAA,cACR,KAAA,UACA,YAAA,UACA,WAAA;IAAA,SACW,WAAA;IAAA,SACA,WAAA;IAAA,SACA,UAAA;EAAA,IAEV,OAAA;EAhOD;;;;EA8PI,gBAAA,CACJ,MAAA,EAAQ,wBAAA,cACR,KAAA,UACA,KAAA;IAAA,SACW,MAAA;IAAA,SACA,IAAA;IAAA,SACA,EAAA;IAAA,SACA,aAAA;IAAA,SACA,aAAA;IAAA,SACA,UAAA;EAAA,IAEV,OAAA;EAAA,QAiBW,+BAAA;EAAA,QA0BA,gBAAA;EA9RiB;;;;;;;;;;;;;;;;;;;;;;;;EAwVzB,UAAA,CACJ,MAAA,EAAQ,wBAAA,cACR,QAAA,YACA,MAAA,YACC,OAAA,CAAQ,0BAAA;EAnMT;;;;EAAA,QAmOY,eAAA;EAzLZ;;;;;;;;EAAA,QAgNY,mBAAA;EA1KZ;;;;;;;EAAA,QA+LY,uBAAA;EA7LZ;;;;;;EAAA,QAqNY,gBAAA;EAtGZ;;;EAAA,QAgnBY,kBAAA;AAAA;;;cC7oCV,yBAAA,EAA2B,2BAA2B"}
|
package/dist/control.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as createPostgresBuiltinCodecLookup, t as PostgresControlAdapter } from "./control-adapter-
|
|
1
|
+
import { r as createPostgresBuiltinCodecLookup, t as PostgresControlAdapter } from "./control-adapter-D5hAI05c.mjs";
|
|
2
2
|
import { t as postgresAdapterDescriptorMeta } from "./descriptor-meta-DnWlLrI6.mjs";
|
|
3
3
|
import { parsePostgresDefault } from "@prisma-next/target-postgres/default-normalizer";
|
|
4
4
|
import { normalizeSchemaNativeType } from "@prisma-next/target-postgres/native-type-normalizer";
|
package/dist/runtime.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as postgresRawCodecInferer, t as createPostgresAdapter } from "./adapter-
|
|
1
|
+
import { n as postgresRawCodecInferer, t as createPostgresAdapter } from "./adapter-DX2HrqGc.mjs";
|
|
2
2
|
import { n as postgresQueryOperations, t as postgresAdapterDescriptorMeta } from "./descriptor-meta-DnWlLrI6.mjs";
|
|
3
3
|
import { extractCodecLookup } from "@prisma-next/framework-components/control";
|
|
4
4
|
import { postgresCodecRegistry } from "@prisma-next/target-postgres/codecs";
|
package/package.json
CHANGED
|
@@ -1,35 +1,35 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/adapter-postgres",
|
|
3
|
-
"version": "0.14.0-dev.
|
|
3
|
+
"version": "0.14.0-dev.40",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@prisma-next/contract": "0.14.0-dev.
|
|
9
|
-
"@prisma-next/contract-authoring": "0.14.0-dev.
|
|
10
|
-
"@prisma-next/errors": "0.14.0-dev.
|
|
11
|
-
"@prisma-next/family-sql": "0.14.0-dev.
|
|
12
|
-
"@prisma-next/framework-components": "0.14.0-dev.
|
|
13
|
-
"@prisma-next/ids": "0.14.0-dev.
|
|
14
|
-
"@prisma-next/sql-contract": "0.14.0-dev.
|
|
15
|
-
"@prisma-next/sql-contract-psl": "0.14.0-dev.
|
|
16
|
-
"@prisma-next/sql-contract-ts": "0.14.0-dev.
|
|
17
|
-
"@prisma-next/sql-operations": "0.14.0-dev.
|
|
18
|
-
"@prisma-next/sql-relational-core": "0.14.0-dev.
|
|
19
|
-
"@prisma-next/sql-runtime": "0.14.0-dev.
|
|
20
|
-
"@prisma-next/sql-schema-ir": "0.14.0-dev.
|
|
21
|
-
"@prisma-next/target-postgres": "0.14.0-dev.
|
|
22
|
-
"@prisma-next/utils": "0.14.0-dev.
|
|
8
|
+
"@prisma-next/contract": "0.14.0-dev.40",
|
|
9
|
+
"@prisma-next/contract-authoring": "0.14.0-dev.40",
|
|
10
|
+
"@prisma-next/errors": "0.14.0-dev.40",
|
|
11
|
+
"@prisma-next/family-sql": "0.14.0-dev.40",
|
|
12
|
+
"@prisma-next/framework-components": "0.14.0-dev.40",
|
|
13
|
+
"@prisma-next/ids": "0.14.0-dev.40",
|
|
14
|
+
"@prisma-next/sql-contract": "0.14.0-dev.40",
|
|
15
|
+
"@prisma-next/sql-contract-psl": "0.14.0-dev.40",
|
|
16
|
+
"@prisma-next/sql-contract-ts": "0.14.0-dev.40",
|
|
17
|
+
"@prisma-next/sql-operations": "0.14.0-dev.40",
|
|
18
|
+
"@prisma-next/sql-relational-core": "0.14.0-dev.40",
|
|
19
|
+
"@prisma-next/sql-runtime": "0.14.0-dev.40",
|
|
20
|
+
"@prisma-next/sql-schema-ir": "0.14.0-dev.40",
|
|
21
|
+
"@prisma-next/target-postgres": "0.14.0-dev.40",
|
|
22
|
+
"@prisma-next/utils": "0.14.0-dev.40",
|
|
23
23
|
"arktype": "^2.2.0"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@prisma-next/cli": "0.14.0-dev.
|
|
27
|
-
"@prisma-next/driver-postgres": "0.14.0-dev.
|
|
28
|
-
"@prisma-next/migration-tools": "0.14.0-dev.
|
|
29
|
-
"@prisma-next/psl-parser": "0.14.0-dev.
|
|
30
|
-
"@prisma-next/test-utils": "0.14.0-dev.
|
|
31
|
-
"@prisma-next/tsconfig": "0.14.0-dev.
|
|
32
|
-
"@prisma-next/tsdown": "0.14.0-dev.
|
|
26
|
+
"@prisma-next/cli": "0.14.0-dev.40",
|
|
27
|
+
"@prisma-next/driver-postgres": "0.14.0-dev.40",
|
|
28
|
+
"@prisma-next/migration-tools": "0.14.0-dev.40",
|
|
29
|
+
"@prisma-next/psl-parser": "0.14.0-dev.40",
|
|
30
|
+
"@prisma-next/test-utils": "0.14.0-dev.40",
|
|
31
|
+
"@prisma-next/tsconfig": "0.14.0-dev.40",
|
|
32
|
+
"@prisma-next/tsdown": "0.14.0-dev.40",
|
|
33
33
|
"pathe": "^2.0.3",
|
|
34
34
|
"tsdown": "0.22.1",
|
|
35
35
|
"typescript": "5.9.3",
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
Contract,
|
|
3
|
-
ContractMarkerRecord,
|
|
4
|
-
LedgerEntryRecord,
|
|
5
|
-
} from '@prisma-next/contract/types';
|
|
1
|
+
import type { ContractMarkerRecord, LedgerEntryRecord } from '@prisma-next/contract/types';
|
|
6
2
|
import {
|
|
7
3
|
parseMarkerRowSafely,
|
|
8
4
|
rethrowMarkerReadError,
|
|
@@ -11,11 +7,11 @@ import {
|
|
|
11
7
|
import type { SqlControlAdapter } from '@prisma-next/family-sql/control-adapter';
|
|
12
8
|
import { parseContractMarkerRow } from '@prisma-next/family-sql/verify';
|
|
13
9
|
import type { CodecLookup, CodecRegistry } from '@prisma-next/framework-components/codec';
|
|
14
|
-
import { APP_SPACE_ID
|
|
10
|
+
import { APP_SPACE_ID } from '@prisma-next/framework-components/control';
|
|
15
11
|
import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
|
|
16
12
|
import { ledgerOriginFromStored } from '@prisma-next/migration-tools/ledger-origin';
|
|
17
13
|
import { REFERENTIAL_ACTION_SQL } from '@prisma-next/sql-contract/referential-action-sql';
|
|
18
|
-
import type { SqlControlDriverInstance
|
|
14
|
+
import type { SqlControlDriverInstance } from '@prisma-next/sql-contract/types';
|
|
19
15
|
import type {
|
|
20
16
|
AnyQueryAst,
|
|
21
17
|
CodecRef,
|
|
@@ -38,7 +34,6 @@ import type {
|
|
|
38
34
|
SqlForeignKeyIR,
|
|
39
35
|
SqlIndexIR,
|
|
40
36
|
SqlReferentialAction,
|
|
41
|
-
SqlSchemaIR,
|
|
42
37
|
SqlUniqueIR,
|
|
43
38
|
} from '@prisma-next/sql-schema-ir/types';
|
|
44
39
|
import {
|
|
@@ -59,19 +54,13 @@ import type {
|
|
|
59
54
|
} from '@prisma-next/target-postgres/ddl';
|
|
60
55
|
import { parsePostgresDefault } from '@prisma-next/target-postgres/default-normalizer';
|
|
61
56
|
import { normalizeSchemaNativeType } from '@prisma-next/target-postgres/native-type-normalizer';
|
|
62
|
-
import {
|
|
63
|
-
contractToPostgresSchemaIR,
|
|
64
|
-
diffPostgresSchema,
|
|
65
|
-
filterIssuesByOwnership,
|
|
66
|
-
} from '@prisma-next/target-postgres/planner';
|
|
67
57
|
import { escapeLiteral, quoteIdentifier } from '@prisma-next/target-postgres/sql-utils';
|
|
68
58
|
import {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
PostgresTableIR,
|
|
59
|
+
PostgresDatabaseSchemaNode,
|
|
60
|
+
PostgresNamespaceSchemaNode,
|
|
61
|
+
PostgresPolicySchemaNode,
|
|
62
|
+
PostgresRoleSchemaNode,
|
|
63
|
+
PostgresTableSchemaNode,
|
|
75
64
|
} from '@prisma-next/target-postgres/types';
|
|
76
65
|
import { blindCast } from '@prisma-next/utils/casts';
|
|
77
66
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
@@ -128,31 +117,6 @@ export class PostgresControlAdapter implements SqlControlAdapter<'postgres'> {
|
|
|
128
117
|
*/
|
|
129
118
|
readonly normalizeNativeType = normalizeSchemaNativeType;
|
|
130
119
|
|
|
131
|
-
collectSchemaDiffIssues(
|
|
132
|
-
contract: Contract<SqlStorage>,
|
|
133
|
-
schema: SqlSchemaIR,
|
|
134
|
-
): readonly SchemaDiffIssue[] {
|
|
135
|
-
if (!isPostgresSchemaIR(schema)) {
|
|
136
|
-
throw new Error(
|
|
137
|
-
`Postgres schema diff requires a PostgresSchemaIR; got ${(schema as { constructor?: { name?: string } }).constructor?.name ?? typeof schema}`,
|
|
138
|
-
);
|
|
139
|
-
}
|
|
140
|
-
const expected = contractToPostgresSchemaIR(
|
|
141
|
-
blindCast<
|
|
142
|
-
PostgresContract,
|
|
143
|
-
'collectSchemaDiffIssues is only called with a postgres contract'
|
|
144
|
-
>(contract),
|
|
145
|
-
{ annotationNamespace: 'pg' },
|
|
146
|
-
);
|
|
147
|
-
const actual = ensurePostgresSchemaIR(schema);
|
|
148
|
-
const issues = diffPostgresSchema(expected, actual);
|
|
149
|
-
const ownedSchemaNames = new Set([
|
|
150
|
-
...expected.rlsPolicies.map((p) => p.namespaceId),
|
|
151
|
-
...expected.existingSchemas,
|
|
152
|
-
]);
|
|
153
|
-
return filterIssuesByOwnership(issues, ownedSchemaNames);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
120
|
bootstrapControlTableQueries(): readonly DdlNode[] {
|
|
157
121
|
return buildControlTableBootstrapQueries();
|
|
158
122
|
}
|
|
@@ -593,23 +557,53 @@ export class PostgresControlAdapter implements SqlControlAdapter<'postgres'> {
|
|
|
593
557
|
driver: SqlControlDriverInstance<'postgres'>,
|
|
594
558
|
contract?: unknown,
|
|
595
559
|
schema = 'public',
|
|
596
|
-
): Promise<
|
|
560
|
+
): Promise<PostgresDatabaseSchemaNode> {
|
|
597
561
|
const declaredNamespaces = extractContractNamespaceIds(contract);
|
|
598
|
-
const
|
|
562
|
+
const resolvedSchemas =
|
|
599
563
|
declaredNamespaces.length > 0
|
|
600
|
-
? await this.
|
|
601
|
-
:
|
|
564
|
+
? await this.resolveNamespaceSchemas(driver, declaredNamespaces)
|
|
565
|
+
: [schema];
|
|
566
|
+
|
|
567
|
+
// Walk schemas sequentially: every introspectSchema call shares the one
|
|
568
|
+
// control connection, so a parallel walk only serialises behind the wire
|
|
569
|
+
// protocol and trips pg's "already executing a query" deprecation.
|
|
570
|
+
const namespaces: Record<string, PostgresNamespaceSchemaNode> = {};
|
|
571
|
+
let pgVersion = 'unknown';
|
|
572
|
+
for (const resolved of resolvedSchemas) {
|
|
573
|
+
const { namespace, pgVersion: version } = await this.introspectSchema(driver, resolved);
|
|
574
|
+
namespaces[resolved] = namespace;
|
|
575
|
+
pgVersion = version;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
const roles = await this.introspectRoles(driver);
|
|
602
579
|
const existingSchemas = await this.listExistingSchemas(driver);
|
|
603
|
-
return new
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
pgVersion: ir.pgVersion,
|
|
607
|
-
roles: ir.roles,
|
|
580
|
+
return new PostgresDatabaseSchemaNode({
|
|
581
|
+
namespaces,
|
|
582
|
+
roles,
|
|
608
583
|
existingSchemas,
|
|
609
|
-
|
|
584
|
+
pgVersion,
|
|
610
585
|
});
|
|
611
586
|
}
|
|
612
587
|
|
|
588
|
+
/**
|
|
589
|
+
* Reads cluster-scoped database roles. Roles are not schema-qualified, so
|
|
590
|
+
* this is queried once for the whole database rather than per namespace.
|
|
591
|
+
*/
|
|
592
|
+
private async introspectRoles(
|
|
593
|
+
driver: SqlControlDriverInstance<'postgres'>,
|
|
594
|
+
): Promise<readonly PostgresRoleSchemaNode[]> {
|
|
595
|
+
const rolesResult = await driver.query<{ rolname: string }>(
|
|
596
|
+
`SELECT rolname
|
|
597
|
+
FROM pg_catalog.pg_roles
|
|
598
|
+
WHERE rolname NOT LIKE 'pg_%'
|
|
599
|
+
AND rolname != 'postgres'
|
|
600
|
+
ORDER BY rolname`,
|
|
601
|
+
);
|
|
602
|
+
return rolesResult.rows.map(
|
|
603
|
+
(row) => new PostgresRoleSchemaNode({ name: row.rolname, namespaceId: UNBOUND_NAMESPACE_ID }),
|
|
604
|
+
);
|
|
605
|
+
}
|
|
606
|
+
|
|
613
607
|
/**
|
|
614
608
|
* Lists every non-system schema present in the connected database.
|
|
615
609
|
* The introspection consumer (`verifyPostgresNamespacePresence`)
|
|
@@ -633,16 +627,16 @@ export class PostgresControlAdapter implements SqlControlAdapter<'postgres'> {
|
|
|
633
627
|
}
|
|
634
628
|
|
|
635
629
|
/**
|
|
636
|
-
*
|
|
637
|
-
* the connection's `current_schema()
|
|
638
|
-
*
|
|
639
|
-
*
|
|
640
|
-
*
|
|
630
|
+
* Resolves the declared namespace ids to their live DDL schema names,
|
|
631
|
+
* mapping `UNBOUND_NAMESPACE_ID` to the connection's `current_schema()`
|
|
632
|
+
* and de-duplicating. The caller introspects one namespace node per
|
|
633
|
+
* resolved schema — there is no flat cross-schema merge, so two schemas
|
|
634
|
+
* holding a same-named table no longer collide.
|
|
641
635
|
*/
|
|
642
|
-
private async
|
|
636
|
+
private async resolveNamespaceSchemas(
|
|
643
637
|
driver: SqlControlDriverInstance<'postgres'>,
|
|
644
638
|
namespaceIds: readonly string[],
|
|
645
|
-
): Promise<
|
|
639
|
+
): Promise<readonly string[]> {
|
|
646
640
|
const resolvedSchemas: string[] = [];
|
|
647
641
|
for (const id of namespaceIds) {
|
|
648
642
|
if (id === UNBOUND_NAMESPACE_ID) {
|
|
@@ -654,45 +648,19 @@ export class PostgresControlAdapter implements SqlControlAdapter<'postgres'> {
|
|
|
654
648
|
resolvedSchemas.push(id);
|
|
655
649
|
}
|
|
656
650
|
}
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
// Walk schemas sequentially: every introspectSchema call shares the one
|
|
660
|
-
// control connection, so a parallel walk only serialises behind the wire
|
|
661
|
-
// protocol and trips pg's "already executing a query" deprecation.
|
|
662
|
-
const perSchema: PostgresSchemaIR[] = [];
|
|
663
|
-
for (const schema of uniqueSchemas) {
|
|
664
|
-
perSchema.push(await this.introspectSchema(driver, schema));
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
const mergedTables: Record<string, PostgresTableIR> = {};
|
|
668
|
-
const mergedRoles: PostgresRole[] = [];
|
|
669
|
-
for (const ir of perSchema) {
|
|
670
|
-
for (const [tableName, table] of Object.entries(ir.tables)) {
|
|
671
|
-
mergedTables[tableName] = table;
|
|
672
|
-
}
|
|
673
|
-
mergedRoles.push(...ir.roles);
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
const first = perSchema[0];
|
|
677
|
-
return new PostgresSchemaIR({
|
|
678
|
-
tables: mergedTables,
|
|
679
|
-
pgSchemaName: first?.pgSchemaName ?? 'public',
|
|
680
|
-
pgVersion: first?.pgVersion ?? 'unknown',
|
|
681
|
-
roles: mergedRoles,
|
|
682
|
-
existingSchemas: first?.existingSchemas ?? ['public'],
|
|
683
|
-
nativeEnumTypeNames: first?.nativeEnumTypeNames ?? [],
|
|
684
|
-
});
|
|
651
|
+
return Array.from(new Set(resolvedSchemas));
|
|
685
652
|
}
|
|
686
653
|
|
|
687
654
|
/**
|
|
688
|
-
* Introspects a single Postgres schema and returns
|
|
689
|
-
*
|
|
655
|
+
* Introspects a single Postgres schema and returns the namespace node for
|
|
656
|
+
* that schema (its tables, their policies, and its native enum type names),
|
|
657
|
+
* alongside the cluster-scoped Postgres version. Used by `introspect` as
|
|
690
658
|
* the per-namespace walk.
|
|
691
659
|
*/
|
|
692
660
|
private async introspectSchema(
|
|
693
661
|
driver: SqlControlDriverInstance<'postgres'>,
|
|
694
662
|
schema: string,
|
|
695
|
-
): Promise<
|
|
663
|
+
): Promise<{ readonly namespace: PostgresNamespaceSchemaNode; readonly pgVersion: string }> {
|
|
696
664
|
// Issue the schema-wide queries one at a time. A single control connection
|
|
697
665
|
// serialises queries anyway, so Promise.all buys no parallelism here and
|
|
698
666
|
// makes pg emit a "client is already executing a query" deprecation. One
|
|
@@ -1167,14 +1135,7 @@ export class PostgresControlAdapter implements SqlControlAdapter<'postgres'> {
|
|
|
1167
1135
|
ORDER BY tablename, policyname`,
|
|
1168
1136
|
[schema],
|
|
1169
1137
|
);
|
|
1170
|
-
const
|
|
1171
|
-
`SELECT rolname
|
|
1172
|
-
FROM pg_catalog.pg_roles
|
|
1173
|
-
WHERE rolname NOT LIKE 'pg_%'
|
|
1174
|
-
AND rolname != 'postgres'
|
|
1175
|
-
ORDER BY rolname`,
|
|
1176
|
-
);
|
|
1177
|
-
const policiesByTable = new Map<string, PostgresRlsPolicy[]>();
|
|
1138
|
+
const policiesByTable = new Map<string, PostgresPolicySchemaNode[]>();
|
|
1178
1139
|
for (const row of policiesResult.rows) {
|
|
1179
1140
|
const operation = mapPgCmd(row.cmd);
|
|
1180
1141
|
const policyRoles = [
|
|
@@ -1183,7 +1144,7 @@ export class PostgresControlAdapter implements SqlControlAdapter<'postgres'> {
|
|
|
1183
1144
|
const permissive = row.permissive.toUpperCase() === 'PERMISSIVE';
|
|
1184
1145
|
const hashSuffixMatch = /^(.+)_([0-9a-f]{8})$/.exec(row.policyname);
|
|
1185
1146
|
const prefix = hashSuffixMatch?.[1] ?? row.policyname;
|
|
1186
|
-
const policy = new
|
|
1147
|
+
const policy = new PostgresPolicySchemaNode({
|
|
1187
1148
|
name: row.policyname,
|
|
1188
1149
|
prefix,
|
|
1189
1150
|
tableName: row.tablename,
|
|
@@ -1199,26 +1160,20 @@ export class PostgresControlAdapter implements SqlControlAdapter<'postgres'> {
|
|
|
1199
1160
|
policiesByTable.set(row.tablename, list);
|
|
1200
1161
|
}
|
|
1201
1162
|
|
|
1202
|
-
const tables: Record<string,
|
|
1163
|
+
const tables: Record<string, PostgresTableSchemaNode> = {};
|
|
1203
1164
|
for (const [tableName, input] of Object.entries(tableInputs)) {
|
|
1204
|
-
tables[tableName] = new
|
|
1165
|
+
tables[tableName] = new PostgresTableSchemaNode({
|
|
1205
1166
|
...input,
|
|
1206
|
-
|
|
1167
|
+
policies: policiesByTable.get(tableName) ?? [],
|
|
1207
1168
|
});
|
|
1208
1169
|
}
|
|
1209
1170
|
|
|
1210
|
-
const
|
|
1211
|
-
|
|
1212
|
-
);
|
|
1213
|
-
|
|
1214
|
-
return new PostgresSchemaIR({
|
|
1171
|
+
const namespace = new PostgresNamespaceSchemaNode({
|
|
1172
|
+
schemaName: schema,
|
|
1215
1173
|
tables,
|
|
1216
|
-
pgSchemaName: schema,
|
|
1217
|
-
pgVersion: await this.getPostgresVersion(driver),
|
|
1218
|
-
roles,
|
|
1219
|
-
existingSchemas: [],
|
|
1220
1174
|
nativeEnumTypeNames,
|
|
1221
1175
|
});
|
|
1176
|
+
return { namespace, pgVersion: await this.getPostgresVersion(driver) };
|
|
1222
1177
|
}
|
|
1223
1178
|
|
|
1224
1179
|
/**
|