@prisma-next/adapter-postgres 0.5.0-dev.2 → 0.5.0-dev.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{adapter-hNElNHo4.mjs → adapter-cXPXgEG0.mjs} +9 -5
- package/dist/adapter-cXPXgEG0.mjs.map +1 -0
- package/dist/adapter.d.mts +2 -1
- package/dist/adapter.d.mts.map +1 -1
- package/dist/adapter.mjs +1 -1
- package/dist/control.d.mts +76 -3
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +44 -6
- package/dist/control.mjs.map +1 -1
- package/dist/{descriptor-meta-RTDzyrae.mjs → descriptor-meta-Dxnoq_rr.mjs} +22 -21
- package/dist/descriptor-meta-Dxnoq_rr.mjs.map +1 -0
- package/dist/operation-types.d.mts +11 -10
- package/dist/operation-types.d.mts.map +1 -1
- package/dist/runtime.d.mts +2 -2
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +10 -5
- package/dist/runtime.mjs.map +1 -1
- package/dist/{sql-renderer-pEaSP82_.mjs → sql-renderer-Dd_Y8oK_.mjs} +80 -27
- package/dist/sql-renderer-Dd_Y8oK_.mjs.map +1 -0
- package/dist/{types-CfRPdAk8.d.mts → types-tLtmYqCO.d.mts} +12 -1
- package/dist/types-tLtmYqCO.d.mts.map +1 -0
- package/dist/types.d.mts +1 -1
- package/package.json +21 -21
- package/src/core/adapter.ts +10 -2
- package/src/core/codec-lookup.ts +24 -0
- package/src/core/control-adapter.ts +68 -1
- package/src/core/descriptor-meta.ts +29 -11
- package/src/core/sql-renderer.ts +90 -40
- package/src/core/types.ts +11 -0
- package/src/exports/control.ts +3 -2
- package/src/exports/runtime.ts +16 -3
- package/src/types/operation-types.ts +19 -9
- package/dist/adapter-hNElNHo4.mjs.map +0 -1
- package/dist/descriptor-meta-RTDzyrae.mjs.map +0 -1
- package/dist/sql-renderer-pEaSP82_.mjs.map +0 -1
- package/dist/types-CfRPdAk8.d.mts.map +0 -1
package/src/core/adapter.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CodecLookup } from '@prisma-next/framework-components/codec';
|
|
1
2
|
import {
|
|
2
3
|
type Adapter,
|
|
3
4
|
type AdapterProfile,
|
|
@@ -6,8 +7,10 @@ import {
|
|
|
6
7
|
createCodecRegistry,
|
|
7
8
|
type LowererContext,
|
|
8
9
|
} from '@prisma-next/sql-relational-core/ast';
|
|
10
|
+
import { parseContractMarkerRow } from '@prisma-next/sql-runtime';
|
|
9
11
|
import { codecDefinitions } from '@prisma-next/target-postgres/codecs';
|
|
10
12
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
13
|
+
import { createPostgresBuiltinCodecLookup } from './codec-lookup';
|
|
11
14
|
import { renderLoweredSql } from './sql-renderer';
|
|
12
15
|
import type { PostgresAdapterOptions, PostgresContract, PostgresLoweredStatement } from './types';
|
|
13
16
|
|
|
@@ -58,17 +61,22 @@ class PostgresAdapterImpl
|
|
|
58
61
|
}
|
|
59
62
|
return registry;
|
|
60
63
|
})();
|
|
64
|
+
private readonly codecLookup: CodecLookup;
|
|
61
65
|
|
|
62
66
|
constructor(options?: PostgresAdapterOptions) {
|
|
67
|
+
this.codecLookup = options?.codecLookup ?? createPostgresBuiltinCodecLookup();
|
|
63
68
|
this.profile = Object.freeze({
|
|
64
69
|
id: options?.profileId ?? 'postgres/default@1',
|
|
65
70
|
target: 'postgres',
|
|
66
71
|
capabilities: defaultCapabilities,
|
|
67
72
|
codecs: () => this.codecRegistry,
|
|
68
73
|
readMarkerStatement: () => ({
|
|
69
|
-
sql: 'select core_hash, profile_hash, contract_json, canonical_version, updated_at, app_tag, meta from prisma_contract.marker where id = $1',
|
|
74
|
+
sql: 'select core_hash, profile_hash, contract_json, canonical_version, updated_at, app_tag, meta, invariants from prisma_contract.marker where id = $1',
|
|
70
75
|
params: [1],
|
|
71
76
|
}),
|
|
77
|
+
// Postgres' driver hydrates `text[]` columns as native JS arrays, so
|
|
78
|
+
// the row is already in the shape the shared parser expects.
|
|
79
|
+
parseMarkerRow: (row: unknown) => parseContractMarkerRow(row),
|
|
72
80
|
});
|
|
73
81
|
}
|
|
74
82
|
|
|
@@ -77,7 +85,7 @@ class PostgresAdapterImpl
|
|
|
77
85
|
}
|
|
78
86
|
|
|
79
87
|
lower(ast: AnyQueryAst, context: LowererContext<PostgresContract>): PostgresLoweredStatement {
|
|
80
|
-
return renderLoweredSql(ast, context.contract);
|
|
88
|
+
return renderLoweredSql(ast, context.contract, this.codecLookup);
|
|
81
89
|
}
|
|
82
90
|
}
|
|
83
91
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Codec, CodecLookup } from '@prisma-next/framework-components/codec';
|
|
2
|
+
import { codecDefinitions } from '@prisma-next/target-postgres/codecs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Build a {@link CodecLookup} populated with the Postgres-builtin codec
|
|
6
|
+
* definitions only.
|
|
7
|
+
*
|
|
8
|
+
* This is the default lookup used by `createPostgresAdapter()` and
|
|
9
|
+
* `new PostgresControlAdapter()` when called without a stack-derived lookup
|
|
10
|
+
* (e.g. from tests, or one-off scripts that don't compose a full stack).
|
|
11
|
+
*
|
|
12
|
+
* Extension codecs (e.g. `pg/vector@1` from `@prisma-next/extension-pgvector`)
|
|
13
|
+
* are intentionally NOT included here: a bare adapter cannot see extensions.
|
|
14
|
+
* Stack-composed paths (`SqlControlAdapterDescriptor.create(stack)` /
|
|
15
|
+
* `SqlRuntimeAdapterDescriptor.create(stack)`) supply the broader,
|
|
16
|
+
* extension-inclusive lookup at construction time.
|
|
17
|
+
*/
|
|
18
|
+
export function createPostgresBuiltinCodecLookup(): CodecLookup {
|
|
19
|
+
const byId = new Map<string, Codec>();
|
|
20
|
+
for (const definition of Object.values(codecDefinitions)) {
|
|
21
|
+
byId.set(definition.codec.id, definition.codec);
|
|
22
|
+
}
|
|
23
|
+
return { get: (id) => byId.get(id) };
|
|
24
|
+
}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import type { ContractMarkerRecord } from '@prisma-next/contract/types';
|
|
1
2
|
import type { SqlControlAdapter } from '@prisma-next/family-sql/control-adapter';
|
|
3
|
+
import { parseContractMarkerRow } from '@prisma-next/family-sql/verify';
|
|
4
|
+
import type { CodecLookup } from '@prisma-next/framework-components/codec';
|
|
2
5
|
import type { ControlDriverInstance } from '@prisma-next/framework-components/control';
|
|
3
6
|
import type {
|
|
4
7
|
AnyQueryAst,
|
|
@@ -19,6 +22,7 @@ import type {
|
|
|
19
22
|
import { parsePostgresDefault } from '@prisma-next/target-postgres/default-normalizer';
|
|
20
23
|
import { normalizeSchemaNativeType } from '@prisma-next/target-postgres/native-type-normalizer';
|
|
21
24
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
25
|
+
import { createPostgresBuiltinCodecLookup } from './codec-lookup';
|
|
22
26
|
import { pgEnumControlHooks } from './enum-control-hooks';
|
|
23
27
|
import { renderLoweredSql } from './sql-renderer';
|
|
24
28
|
import type { PostgresContract } from './types';
|
|
@@ -31,6 +35,19 @@ export class PostgresControlAdapter implements SqlControlAdapter<'postgres'> {
|
|
|
31
35
|
readonly familyId = 'sql' as const;
|
|
32
36
|
readonly targetId = 'postgres' as const;
|
|
33
37
|
|
|
38
|
+
private readonly codecLookup: CodecLookup;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @param codecLookup - Codec lookup used by the SQL renderer to resolve
|
|
42
|
+
* per-codec metadata at lower-time. Defaults to a Postgres-builtins-only
|
|
43
|
+
* lookup when omitted. Stack-aware callers
|
|
44
|
+
* (`SqlControlAdapterDescriptor.create(stack)`) supply
|
|
45
|
+
* `stack.codecLookup` so extension codecs are visible to the renderer.
|
|
46
|
+
*/
|
|
47
|
+
constructor(codecLookup?: CodecLookup) {
|
|
48
|
+
this.codecLookup = codecLookup ?? createPostgresBuiltinCodecLookup();
|
|
49
|
+
}
|
|
50
|
+
|
|
34
51
|
/**
|
|
35
52
|
* Target-specific normalizer for raw Postgres default expressions.
|
|
36
53
|
* Used by schema verification to normalize raw defaults before comparison.
|
|
@@ -53,7 +70,57 @@ export class PostgresControlAdapter implements SqlControlAdapter<'postgres'> {
|
|
|
53
70
|
* without instantiating the runtime adapter.
|
|
54
71
|
*/
|
|
55
72
|
lower(ast: AnyQueryAst, context: LowererContext<unknown>): LoweredStatement {
|
|
56
|
-
return renderLoweredSql(ast, context.contract as PostgresContract);
|
|
73
|
+
return renderLoweredSql(ast, context.contract as PostgresContract, this.codecLookup);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Reads the contract marker from `prisma_contract.marker`. Probes
|
|
78
|
+
* `information_schema.tables` first so a fresh database (where the
|
|
79
|
+
* `prisma_contract` schema doesn't yet exist) returns `null` instead of a
|
|
80
|
+
* "relation does not exist" error — some Postgres wire-protocol clients
|
|
81
|
+
* (e.g. PGlite's TCP proxy) don't fully recover from extended-protocol
|
|
82
|
+
* parse errors, so we probe before reading.
|
|
83
|
+
*/
|
|
84
|
+
async readMarker(
|
|
85
|
+
driver: ControlDriverInstance<'sql', 'postgres'>,
|
|
86
|
+
): Promise<ContractMarkerRecord | null> {
|
|
87
|
+
const exists = await driver.query(
|
|
88
|
+
`select 1
|
|
89
|
+
from information_schema.tables
|
|
90
|
+
where table_schema = $1 and table_name = $2`,
|
|
91
|
+
['prisma_contract', 'marker'],
|
|
92
|
+
);
|
|
93
|
+
if (exists.rows.length === 0) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const result = await driver.query<{
|
|
98
|
+
core_hash: string;
|
|
99
|
+
profile_hash: string;
|
|
100
|
+
contract_json: unknown | null;
|
|
101
|
+
canonical_version: number | null;
|
|
102
|
+
updated_at: Date | string;
|
|
103
|
+
app_tag: string | null;
|
|
104
|
+
meta: unknown | null;
|
|
105
|
+
invariants: readonly string[];
|
|
106
|
+
}>(
|
|
107
|
+
`select
|
|
108
|
+
core_hash,
|
|
109
|
+
profile_hash,
|
|
110
|
+
contract_json,
|
|
111
|
+
canonical_version,
|
|
112
|
+
updated_at,
|
|
113
|
+
app_tag,
|
|
114
|
+
meta,
|
|
115
|
+
invariants
|
|
116
|
+
from prisma_contract.marker
|
|
117
|
+
where id = $1`,
|
|
118
|
+
[1],
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
const row = result.rows[0];
|
|
122
|
+
if (!row) return null;
|
|
123
|
+
return parseContractMarkerRow(row);
|
|
57
124
|
}
|
|
58
125
|
|
|
59
126
|
/**
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import type { CodecControlHooks, ExpandNativeTypeInput } from '@prisma-next/family-sql/control';
|
|
2
2
|
import type { SqlOperationDescriptor } from '@prisma-next/sql-operations';
|
|
3
|
+
import {
|
|
4
|
+
buildOperation,
|
|
5
|
+
type CodecExpression,
|
|
6
|
+
type Expression,
|
|
7
|
+
type TraitExpression,
|
|
8
|
+
toExpr,
|
|
9
|
+
} from '@prisma-next/sql-relational-core/expression';
|
|
3
10
|
import {
|
|
4
11
|
PG_BIT_CODEC_ID,
|
|
5
12
|
PG_BOOL_CODEC_ID,
|
|
@@ -128,17 +135,28 @@ const identityHooks: CodecControlHooks = { expandNativeType: ({ nativeType }) =>
|
|
|
128
135
|
// Descriptor metadata
|
|
129
136
|
// ============================================================================
|
|
130
137
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
]
|
|
138
|
+
type CodecTypesBase = Record<string, { readonly input: unknown; readonly output: unknown }>;
|
|
139
|
+
|
|
140
|
+
export function postgresQueryOperations<
|
|
141
|
+
CT extends CodecTypesBase,
|
|
142
|
+
>(): readonly SqlOperationDescriptor[] {
|
|
143
|
+
return [
|
|
144
|
+
{
|
|
145
|
+
method: 'ilike',
|
|
146
|
+
self: { traits: ['textual'] },
|
|
147
|
+
impl: (
|
|
148
|
+
self: TraitExpression<readonly ['textual'], false, CT>,
|
|
149
|
+
pattern: CodecExpression<'pg/text@1', false, CT>,
|
|
150
|
+
): Expression<{ codecId: 'pg/bool@1'; nullable: false }> =>
|
|
151
|
+
buildOperation({
|
|
152
|
+
method: 'ilike',
|
|
153
|
+
args: [toExpr(self), toExpr(pattern, PG_TEXT_CODEC_ID)],
|
|
154
|
+
returns: { codecId: PG_BOOL_CODEC_ID, nullable: false },
|
|
155
|
+
lowering: { targetFamily: 'sql', strategy: 'infix', template: '{{self}} ILIKE {{arg0}}' },
|
|
156
|
+
}),
|
|
157
|
+
},
|
|
158
|
+
];
|
|
159
|
+
}
|
|
142
160
|
|
|
143
161
|
export const postgresAdapterDescriptorMeta = {
|
|
144
162
|
kind: 'adapter',
|
package/src/core/sql-renderer.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CodecLookup } from '@prisma-next/framework-components/codec';
|
|
1
2
|
import {
|
|
2
3
|
type AggregateExpr,
|
|
3
4
|
type AnyExpression,
|
|
@@ -20,50 +21,97 @@ import {
|
|
|
20
21
|
type ParamRef,
|
|
21
22
|
type ProjectionItem,
|
|
22
23
|
type SelectAst,
|
|
24
|
+
type Codec as SqlCodec,
|
|
23
25
|
type SubqueryExpr,
|
|
24
26
|
type UpdateAst,
|
|
25
27
|
} from '@prisma-next/sql-relational-core/ast';
|
|
26
|
-
import { PG_JSON_CODEC_ID, PG_JSONB_CODEC_ID } from '@prisma-next/target-postgres/codec-ids';
|
|
27
28
|
import { escapeLiteral, quoteIdentifier } from '@prisma-next/target-postgres/sql-utils';
|
|
28
29
|
import type { PostgresContract } from './types';
|
|
29
30
|
|
|
30
|
-
// Mirrors `VECTOR_CODEC_ID` in `@prisma-next/extension-pgvector/core/constants`.
|
|
31
|
-
// Duplicated here rather than imported because the canonical export is not
|
|
32
|
-
// part of the extension's public subpath surface, and `@prisma-next/adapter-postgres`
|
|
33
|
-
// does not (and should not) take a runtime dependency on the extension package
|
|
34
|
-
// just for one constant. The whole `getCodecParamCast` switch is slated for
|
|
35
|
-
// removal under TML-2310 ("Move SQL param-cast metadata onto codec descriptors"),
|
|
36
|
-
// at which point this and the JSON/JSONB IDs below also disappear.
|
|
37
|
-
const VECTOR_CODEC_ID = 'pg/vector@1' as const;
|
|
38
|
-
|
|
39
31
|
/**
|
|
40
|
-
*
|
|
41
|
-
*
|
|
32
|
+
* Postgres native types whose unknown-OID parameter inference is reliable in
|
|
33
|
+
* arbitrary expression positions. Parameters bound to a codec whose
|
|
34
|
+
* `meta.db.sql.postgres.nativeType` falls in this set are emitted as plain
|
|
35
|
+
* `$N`; everything else (including `json`, `jsonb`, extension types like
|
|
36
|
+
* `vector`, and unknown user types) is emitted as `$N::<nativeType>` so the
|
|
37
|
+
* planner picks an unambiguous overload.
|
|
38
|
+
*
|
|
39
|
+
* `json` / `jsonb` are intentionally excluded despite being Postgres builtins:
|
|
40
|
+
* their operator overloads make context inference unreliable in expression
|
|
41
|
+
* positions (e.g. `$1 -> 'key'` is ambiguous between the two).
|
|
42
42
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
43
|
+
* Spellings match the on-disk `meta.db.sql.postgres.nativeType` values in
|
|
44
|
+
* `@prisma-next/target-postgres`'s codec definitions, not the `udt_name`
|
|
45
|
+
* abbreviations that ADR 205 used as illustrative shorthand. The lookup-based
|
|
46
|
+
* cast policy compares against these strings directly.
|
|
46
47
|
*/
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
48
|
+
const POSTGRES_INFERRABLE_NATIVE_TYPES: ReadonlySet<string> = new Set([
|
|
49
|
+
// Numeric
|
|
50
|
+
'integer',
|
|
51
|
+
'smallint',
|
|
52
|
+
'bigint',
|
|
53
|
+
'real',
|
|
54
|
+
'double precision',
|
|
55
|
+
'numeric',
|
|
56
|
+
// Boolean
|
|
57
|
+
'boolean',
|
|
58
|
+
// Strings
|
|
59
|
+
'text',
|
|
60
|
+
'character',
|
|
61
|
+
'character varying',
|
|
62
|
+
// Temporal
|
|
63
|
+
'timestamp',
|
|
64
|
+
'timestamp without time zone',
|
|
65
|
+
'timestamp with time zone',
|
|
66
|
+
'time',
|
|
67
|
+
'timetz',
|
|
68
|
+
'interval',
|
|
69
|
+
// Bit strings
|
|
70
|
+
'bit',
|
|
71
|
+
'bit varying',
|
|
72
|
+
]);
|
|
73
|
+
|
|
74
|
+
function renderTypedParam(
|
|
75
|
+
index: number,
|
|
76
|
+
codecId: string | undefined,
|
|
77
|
+
codecLookup: CodecLookup,
|
|
78
|
+
): string {
|
|
79
|
+
if (codecId === undefined) {
|
|
80
|
+
return `$${index}`;
|
|
81
|
+
}
|
|
82
|
+
// SQL codecs extend the framework `Codec` base with an optional
|
|
83
|
+
// `meta: CodecMeta`; the framework `CodecLookup.get` returns the base type,
|
|
84
|
+
// so we narrow to `SqlCodec` to read `meta`. Every codec actually
|
|
85
|
+
// registered into a SQL codec lookup conforms to `SqlCodec`.
|
|
86
|
+
const codec = codecLookup.get(codecId) as SqlCodec | undefined;
|
|
87
|
+
if (codec === undefined) {
|
|
88
|
+
throw new Error(
|
|
89
|
+
`Postgres lowering: ParamRef carries codecId "${codecId}" but the ` +
|
|
90
|
+
'assembled codec lookup has no entry for it. This usually indicates ' +
|
|
91
|
+
'a missing extension pack in the runtime stack — register the pack ' +
|
|
92
|
+
'that contributes this codec (e.g. `extensionPacks: [pgvectorRuntime]`), ' +
|
|
93
|
+
'or use the codec directly from `@prisma-next/target-postgres/codecs` ' +
|
|
94
|
+
"if it's a builtin.",
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
const nativeType = codec.meta?.db?.sql?.postgres?.nativeType;
|
|
98
|
+
if (nativeType !== undefined && !POSTGRES_INFERRABLE_NATIVE_TYPES.has(nativeType)) {
|
|
99
|
+
return `$${index}::${nativeType}`;
|
|
100
|
+
}
|
|
101
|
+
return `$${index}`;
|
|
58
102
|
}
|
|
59
103
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
104
|
+
/**
|
|
105
|
+
* Per-render carrier threaded through every helper. Bundles the param-index
|
|
106
|
+
* map (for `$N` numbering) and the assembled-stack `codecLookup` (for
|
|
107
|
+
* cast policy at the `renderTypedParam` chokepoint). Carrying both on a
|
|
108
|
+
* single value keeps helper signatures stable.
|
|
109
|
+
*/
|
|
110
|
+
interface ParamIndexMap {
|
|
111
|
+
readonly indexMap: Map<ParamRef, number>;
|
|
112
|
+
readonly codecLookup: CodecLookup;
|
|
63
113
|
}
|
|
64
114
|
|
|
65
|
-
type ParamIndexMap = Map<ParamRef, number>;
|
|
66
|
-
|
|
67
115
|
/**
|
|
68
116
|
* Render a SQL query AST to a Postgres-flavored `{ sql, params }` payload.
|
|
69
117
|
*
|
|
@@ -74,32 +122,34 @@ type ParamIndexMap = Map<ParamRef, number>;
|
|
|
74
122
|
export function renderLoweredSql(
|
|
75
123
|
ast: AnyQueryAst,
|
|
76
124
|
contract: PostgresContract,
|
|
125
|
+
codecLookup: CodecLookup,
|
|
77
126
|
): { readonly sql: string; readonly params: readonly unknown[] } {
|
|
78
127
|
const collectedParamRefs = ast.collectParamRefs();
|
|
79
|
-
const
|
|
128
|
+
const indexMap = new Map<ParamRef, number>();
|
|
80
129
|
const params: unknown[] = [];
|
|
81
130
|
for (const ref of collectedParamRefs) {
|
|
82
|
-
if (
|
|
131
|
+
if (indexMap.has(ref)) {
|
|
83
132
|
continue;
|
|
84
133
|
}
|
|
85
|
-
|
|
134
|
+
indexMap.set(ref, params.length + 1);
|
|
86
135
|
params.push(ref.value);
|
|
87
136
|
}
|
|
137
|
+
const pim: ParamIndexMap = { indexMap, codecLookup };
|
|
88
138
|
|
|
89
139
|
const node = ast;
|
|
90
140
|
let sql: string;
|
|
91
141
|
switch (node.kind) {
|
|
92
142
|
case 'select':
|
|
93
|
-
sql = renderSelect(node, contract,
|
|
143
|
+
sql = renderSelect(node, contract, pim);
|
|
94
144
|
break;
|
|
95
145
|
case 'insert':
|
|
96
|
-
sql = renderInsert(node, contract,
|
|
146
|
+
sql = renderInsert(node, contract, pim);
|
|
97
147
|
break;
|
|
98
148
|
case 'update':
|
|
99
|
-
sql = renderUpdate(node, contract,
|
|
149
|
+
sql = renderUpdate(node, contract, pim);
|
|
100
150
|
break;
|
|
101
151
|
case 'delete':
|
|
102
|
-
sql = renderDelete(node, contract,
|
|
152
|
+
sql = renderDelete(node, contract, pim);
|
|
103
153
|
break;
|
|
104
154
|
// v8 ignore next 4
|
|
105
155
|
default:
|
|
@@ -457,11 +507,11 @@ function renderExpr(expr: AnyExpression, contract: PostgresContract, pim: ParamI
|
|
|
457
507
|
}
|
|
458
508
|
|
|
459
509
|
function renderParamRef(ref: ParamRef, pim: ParamIndexMap): string {
|
|
460
|
-
const index = pim.get(ref);
|
|
510
|
+
const index = pim.indexMap.get(ref);
|
|
461
511
|
if (index === undefined) {
|
|
462
512
|
throw new Error('ParamRef not found in index map');
|
|
463
513
|
}
|
|
464
|
-
return renderTypedParam(index, ref.codecId);
|
|
514
|
+
return renderTypedParam(index, ref.codecId, pim.codecLookup);
|
|
465
515
|
}
|
|
466
516
|
|
|
467
517
|
function renderLiteral(expr: LiteralExpr): string {
|
package/src/core/types.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Contract } from '@prisma-next/contract/types';
|
|
2
|
+
import type { CodecLookup } from '@prisma-next/framework-components/codec';
|
|
2
3
|
import type { SqlStorage, StorageColumn, StorageTable } from '@prisma-next/sql-contract/types';
|
|
3
4
|
import type {
|
|
4
5
|
AnyQueryAst,
|
|
@@ -19,6 +20,16 @@ import type {
|
|
|
19
20
|
|
|
20
21
|
export interface PostgresAdapterOptions {
|
|
21
22
|
readonly profileId?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Codec lookup used by the SQL renderer to resolve per-codec metadata at
|
|
25
|
+
* lower-time. Defaults to a Postgres-builtins-only lookup when omitted —
|
|
26
|
+
* see {@link createPostgresBuiltinCodecLookup} in `./codec-lookup`.
|
|
27
|
+
*
|
|
28
|
+
* Stack-aware callers (`SqlRuntimeAdapterDescriptor.create(stack)` /
|
|
29
|
+
* `SqlControlAdapterDescriptor.create(stack)`) supply the assembled stack
|
|
30
|
+
* lookup so extension codecs are visible to the renderer.
|
|
31
|
+
*/
|
|
32
|
+
readonly codecLookup?: CodecLookup;
|
|
22
33
|
}
|
|
23
34
|
|
|
24
35
|
export type PostgresContract = Contract<SqlStorage> & { readonly target: 'postgres' };
|
package/src/exports/control.ts
CHANGED
|
@@ -21,8 +21,8 @@ const postgresAdapterDescriptor: SqlControlAdapterDescriptor<'postgres'> = {
|
|
|
21
21
|
defaultFunctionRegistry: createPostgresDefaultFunctionRegistry(),
|
|
22
22
|
generatorDescriptors: createPostgresMutationDefaultGeneratorDescriptors(),
|
|
23
23
|
},
|
|
24
|
-
create(
|
|
25
|
-
return new PostgresControlAdapter();
|
|
24
|
+
create(stack): SqlControlAdapter<'postgres'> {
|
|
25
|
+
return new PostgresControlAdapter(stack.codecLookup);
|
|
26
26
|
},
|
|
27
27
|
};
|
|
28
28
|
|
|
@@ -31,3 +31,4 @@ export default postgresAdapterDescriptor;
|
|
|
31
31
|
export { parsePostgresDefault } from '@prisma-next/target-postgres/default-normalizer';
|
|
32
32
|
export { normalizeSchemaNativeType } from '@prisma-next/target-postgres/native-type-normalizer';
|
|
33
33
|
export { escapeLiteral, qualifyName, quoteIdentifier, SqlEscapeError };
|
|
34
|
+
export { PostgresControlAdapter } from '../core/control-adapter';
|
package/src/exports/runtime.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { GeneratedValueSpec } from '@prisma-next/contract/types';
|
|
2
|
+
import { extractCodecLookup } from '@prisma-next/framework-components/control';
|
|
2
3
|
import type { RuntimeAdapterInstance } from '@prisma-next/framework-components/execution';
|
|
3
4
|
import { builtinGeneratorIds } from '@prisma-next/ids';
|
|
4
5
|
import { generateId } from '@prisma-next/ids/runtime';
|
|
@@ -79,10 +80,22 @@ const postgresRuntimeAdapterDescriptor: SqlRuntimeAdapterDescriptor<'postgres',
|
|
|
79
80
|
...postgresAdapterDescriptorMeta,
|
|
80
81
|
codecs: createPostgresCodecRegistry,
|
|
81
82
|
parameterizedCodecs: () => parameterizedCodecDescriptors,
|
|
82
|
-
queryOperations: () => postgresQueryOperations,
|
|
83
|
+
queryOperations: () => postgresQueryOperations(),
|
|
83
84
|
mutationDefaultGenerators: createPostgresMutationDefaultGenerators,
|
|
84
|
-
create(
|
|
85
|
-
|
|
85
|
+
create(stack): SqlRuntimeAdapter {
|
|
86
|
+
// The runtime `ExecutionStack` does not (yet) carry a pre-assembled
|
|
87
|
+
// `codecLookup` field the way the control `ControlStack` does, so we
|
|
88
|
+
// derive an equivalent lookup here from the stack's component metadata
|
|
89
|
+
// (target + adapter + extension packs) using the same assembly helper
|
|
90
|
+
// that `createControlStack` uses. This keeps the renderer fed with the
|
|
91
|
+
// same codec set on both planes — including extension-contributed
|
|
92
|
+
// codecs like `pg/vector@1` from `@prisma-next/extension-pgvector`.
|
|
93
|
+
const codecLookup = extractCodecLookup([
|
|
94
|
+
stack.target,
|
|
95
|
+
stack.adapter,
|
|
96
|
+
...stack.extensionPacks,
|
|
97
|
+
]);
|
|
98
|
+
return createPostgresAdapter({ codecLookup });
|
|
86
99
|
},
|
|
87
100
|
};
|
|
88
101
|
|
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
import type { SqlQueryOperationTypes } from '@prisma-next/sql-contract/types';
|
|
2
|
+
import type {
|
|
3
|
+
CodecExpression,
|
|
4
|
+
Expression,
|
|
5
|
+
TraitExpression,
|
|
6
|
+
} from '@prisma-next/sql-relational-core/expression';
|
|
2
7
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
type CodecTypesBase = Record<string, { readonly input: unknown; readonly output: unknown }>;
|
|
9
|
+
|
|
10
|
+
export type QueryOperationTypes<CT extends CodecTypesBase> = SqlQueryOperationTypes<
|
|
11
|
+
CT,
|
|
12
|
+
{
|
|
13
|
+
readonly ilike: {
|
|
14
|
+
readonly self: { readonly traits: readonly ['textual'] };
|
|
15
|
+
readonly impl: (
|
|
16
|
+
self: TraitExpression<readonly ['textual'], false, CT>,
|
|
17
|
+
pattern: CodecExpression<'pg/text@1', false, CT>,
|
|
18
|
+
) => Expression<{ codecId: 'pg/bool@1'; nullable: false }>;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
>;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"adapter-hNElNHo4.mjs","names":["parameterizedCodecs: ReadonlyArray<CodecParamsDescriptor>"],"sources":["../src/core/adapter.ts"],"sourcesContent":["import {\n type Adapter,\n type AdapterProfile,\n type AnyQueryAst,\n type CodecParamsDescriptor,\n createCodecRegistry,\n type LowererContext,\n} from '@prisma-next/sql-relational-core/ast';\nimport { codecDefinitions } from '@prisma-next/target-postgres/codecs';\nimport { ifDefined } from '@prisma-next/utils/defined';\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 },\n sql: {\n enums: true,\n returning: true,\n defaultInInsert: true,\n },\n});\n\ntype AdapterCodec = (typeof codecDefinitions)[keyof typeof codecDefinitions]['codec'];\ntype ParameterizedCodec = AdapterCodec & {\n readonly paramsSchema: NonNullable<AdapterCodec['paramsSchema']>;\n};\n\nconst parameterizedCodecs: ReadonlyArray<CodecParamsDescriptor> = Object.values(codecDefinitions)\n .map((definition) => definition.codec)\n .filter((codec): codec is ParameterizedCodec => codec.paramsSchema !== undefined)\n .map((codec) =>\n Object.freeze({\n codecId: codec.id,\n paramsSchema: codec.paramsSchema,\n ...ifDefined('init', codec.init),\n }),\n );\n\nclass PostgresAdapterImpl\n implements Adapter<AnyQueryAst, PostgresContract, PostgresLoweredStatement>\n{\n // These fields make the adapter instance structurally compatible with\n // 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 codecRegistry = (() => {\n const registry = createCodecRegistry();\n for (const definition of Object.values(codecDefinitions)) {\n registry.register(definition.codec);\n }\n return registry;\n })();\n\n constructor(options?: PostgresAdapterOptions) {\n this.profile = Object.freeze({\n id: options?.profileId ?? 'postgres/default@1',\n target: 'postgres',\n capabilities: defaultCapabilities,\n codecs: () => this.codecRegistry,\n readMarkerStatement: () => ({\n sql: 'select core_hash, profile_hash, contract_json, canonical_version, updated_at, app_tag, meta from prisma_contract.marker where id = $1',\n params: [1],\n }),\n });\n }\n\n parameterizedCodecs(): ReadonlyArray<CodecParamsDescriptor> {\n return parameterizedCodecs;\n }\n\n lower(ast: AnyQueryAst, context: LowererContext<PostgresContract>): PostgresLoweredStatement {\n return renderLoweredSql(ast, context.contract);\n }\n}\n\nexport function createPostgresAdapter(options?: PostgresAdapterOptions) {\n return Object.freeze(new PostgresAdapterImpl(options));\n}\n"],"mappings":";;;;;;AAaA,MAAM,sBAAsB,OAAO,OAAO;CACxC,UAAU;EACR,SAAS;EACT,OAAO;EACP,SAAS;EACT,SAAS;EACT,WAAW;EACZ;CACD,KAAK;EACH,OAAO;EACP,WAAW;EACX,iBAAiB;EAClB;CACF,CAAC;AAOF,MAAMA,sBAA4D,OAAO,OAAO,iBAAiB,CAC9F,KAAK,eAAe,WAAW,MAAM,CACrC,QAAQ,UAAuC,MAAM,iBAAiB,OAAU,CAChF,KAAK,UACJ,OAAO,OAAO;CACZ,SAAS,MAAM;CACf,cAAc,MAAM;CACpB,GAAG,UAAU,QAAQ,MAAM,KAAK;CACjC,CAAC,CACH;AAEH,IAAM,sBAAN,MAEA;CAGE,AAAS,WAAW;CACpB,AAAS,WAAW;CAEpB,AAAS;CACT,AAAiB,uBAAuB;EACtC,MAAM,WAAW,qBAAqB;AACtC,OAAK,MAAM,cAAc,OAAO,OAAO,iBAAiB,CACtD,UAAS,SAAS,WAAW,MAAM;AAErC,SAAO;KACL;CAEJ,YAAY,SAAkC;AAC5C,OAAK,UAAU,OAAO,OAAO;GAC3B,IAAI,SAAS,aAAa;GAC1B,QAAQ;GACR,cAAc;GACd,cAAc,KAAK;GACnB,4BAA4B;IAC1B,KAAK;IACL,QAAQ,CAAC,EAAE;IACZ;GACF,CAAC;;CAGJ,sBAA4D;AAC1D,SAAO;;CAGT,MAAM,KAAkB,SAAqE;AAC3F,SAAO,iBAAiB,KAAK,QAAQ,SAAS;;;AAIlD,SAAgB,sBAAsB,SAAkC;AACtE,QAAO,OAAO,OAAO,IAAI,oBAAoB,QAAQ,CAAC"}
|