@prisma-next/adapter-postgres 0.5.0-dev.5 → 0.5.0-dev.50
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/README.md +21 -15
- package/dist/{adapter-hNElNHo4.mjs → adapter-_L4wXA4O.mjs} +9 -5
- package/dist/adapter-_L4wXA4O.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/column-types.d.mts +27 -23
- package/dist/column-types.d.mts.map +1 -1
- package/dist/column-types.mjs +27 -58
- package/dist/column-types.mjs.map +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-CpEka_0t.mjs} +30 -22
- package/dist/descriptor-meta-CpEka_0t.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 +3 -11
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +22 -65
- package/dist/runtime.mjs.map +1 -1
- package/dist/{sql-renderer-pEaSP82_.mjs → sql-renderer-DLwYpnxz.mjs} +97 -36
- package/dist/sql-renderer-DLwYpnxz.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 -22
- 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 +32 -11
- package/src/core/sql-renderer.ts +118 -50
- package/src/core/types.ts +11 -0
- package/src/exports/column-types.ts +27 -58
- package/src/exports/control.ts +3 -2
- package/src/exports/runtime.ts +28 -41
- 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/json-schema-validator.ts +0 -54
- package/src/core/standard-schema.ts +0 -71
|
@@ -1,8 +1,16 @@
|
|
|
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,
|
|
13
|
+
PG_BYTEA_CODEC_ID,
|
|
6
14
|
PG_CHAR_CODEC_ID,
|
|
7
15
|
PG_ENUM_CODEC_ID,
|
|
8
16
|
PG_FLOAT_CODEC_ID,
|
|
@@ -128,17 +136,28 @@ const identityHooks: CodecControlHooks = { expandNativeType: ({ nativeType }) =>
|
|
|
128
136
|
// Descriptor metadata
|
|
129
137
|
// ============================================================================
|
|
130
138
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
]
|
|
139
|
+
type CodecTypesBase = Record<string, { readonly input: unknown; readonly output: unknown }>;
|
|
140
|
+
|
|
141
|
+
export function postgresQueryOperations<
|
|
142
|
+
CT extends CodecTypesBase,
|
|
143
|
+
>(): readonly SqlOperationDescriptor[] {
|
|
144
|
+
return [
|
|
145
|
+
{
|
|
146
|
+
method: 'ilike',
|
|
147
|
+
self: { traits: ['textual'] },
|
|
148
|
+
impl: (
|
|
149
|
+
self: TraitExpression<readonly ['textual'], false, CT>,
|
|
150
|
+
pattern: CodecExpression<'pg/text@1', false, CT>,
|
|
151
|
+
): Expression<{ codecId: 'pg/bool@1'; nullable: false }> =>
|
|
152
|
+
buildOperation({
|
|
153
|
+
method: 'ilike',
|
|
154
|
+
args: [toExpr(self), toExpr(pattern, PG_TEXT_CODEC_ID)],
|
|
155
|
+
returns: { codecId: PG_BOOL_CODEC_ID, nullable: false },
|
|
156
|
+
lowering: { targetFamily: 'sql', strategy: 'infix', template: '{{self}} ILIKE {{arg0}}' },
|
|
157
|
+
}),
|
|
158
|
+
},
|
|
159
|
+
];
|
|
160
|
+
}
|
|
142
161
|
|
|
143
162
|
export const postgresAdapterDescriptorMeta = {
|
|
144
163
|
kind: 'adapter',
|
|
@@ -202,6 +221,7 @@ export const postgresAdapterDescriptorMeta = {
|
|
|
202
221
|
[PG_ENUM_CODEC_ID]: pgEnumControlHooks,
|
|
203
222
|
[PG_JSON_CODEC_ID]: identityHooks,
|
|
204
223
|
[PG_JSONB_CODEC_ID]: identityHooks,
|
|
224
|
+
[PG_BYTEA_CODEC_ID]: identityHooks,
|
|
205
225
|
},
|
|
206
226
|
},
|
|
207
227
|
storage: [
|
|
@@ -267,6 +287,7 @@ export const postgresAdapterDescriptorMeta = {
|
|
|
267
287
|
},
|
|
268
288
|
{ typeId: PG_JSON_CODEC_ID, familyId: 'sql', targetId: 'postgres', nativeType: 'json' },
|
|
269
289
|
{ typeId: PG_JSONB_CODEC_ID, familyId: 'sql', targetId: 'postgres', nativeType: 'jsonb' },
|
|
290
|
+
{ typeId: PG_BYTEA_CODEC_ID, familyId: 'sql', targetId: 'postgres', nativeType: 'bytea' },
|
|
270
291
|
],
|
|
271
292
|
queryOperationTypes: {
|
|
272
293
|
import: {
|
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,
|
|
@@ -5,6 +6,7 @@ import {
|
|
|
5
6
|
type AnyQueryAst,
|
|
6
7
|
type BinaryExpr,
|
|
7
8
|
type ColumnRef,
|
|
9
|
+
collectOrderedParamRefs,
|
|
8
10
|
type DeleteAst,
|
|
9
11
|
type InsertAst,
|
|
10
12
|
type InsertValue,
|
|
@@ -20,50 +22,97 @@ import {
|
|
|
20
22
|
type ParamRef,
|
|
21
23
|
type ProjectionItem,
|
|
22
24
|
type SelectAst,
|
|
25
|
+
type Codec as SqlCodec,
|
|
23
26
|
type SubqueryExpr,
|
|
24
27
|
type UpdateAst,
|
|
25
28
|
} 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
29
|
import { escapeLiteral, quoteIdentifier } from '@prisma-next/target-postgres/sql-utils';
|
|
28
30
|
import type { PostgresContract } from './types';
|
|
29
31
|
|
|
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
32
|
/**
|
|
40
|
-
*
|
|
41
|
-
*
|
|
33
|
+
* Postgres native types whose unknown-OID parameter inference is reliable in
|
|
34
|
+
* arbitrary expression positions. Parameters bound to a codec whose
|
|
35
|
+
* `meta.db.sql.postgres.nativeType` falls in this set are emitted as plain
|
|
36
|
+
* `$N`; everything else (including `json`, `jsonb`, extension types like
|
|
37
|
+
* `vector`, and unknown user types) is emitted as `$N::<nativeType>` so the
|
|
38
|
+
* planner picks an unambiguous overload.
|
|
39
|
+
*
|
|
40
|
+
* `json` / `jsonb` are intentionally excluded despite being Postgres builtins:
|
|
41
|
+
* their operator overloads make context inference unreliable in expression
|
|
42
|
+
* positions (e.g. `$1 -> 'key'` is ambiguous between the two).
|
|
42
43
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
44
|
+
* Spellings match the on-disk `meta.db.sql.postgres.nativeType` values in
|
|
45
|
+
* `@prisma-next/target-postgres`'s codec definitions, not the `udt_name`
|
|
46
|
+
* abbreviations that ADR 205 used as illustrative shorthand. The lookup-based
|
|
47
|
+
* cast policy compares against these strings directly.
|
|
46
48
|
*/
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
49
|
+
const POSTGRES_INFERRABLE_NATIVE_TYPES: ReadonlySet<string> = new Set([
|
|
50
|
+
// Numeric
|
|
51
|
+
'integer',
|
|
52
|
+
'smallint',
|
|
53
|
+
'bigint',
|
|
54
|
+
'real',
|
|
55
|
+
'double precision',
|
|
56
|
+
'numeric',
|
|
57
|
+
// Boolean
|
|
58
|
+
'boolean',
|
|
59
|
+
// Strings
|
|
60
|
+
'text',
|
|
61
|
+
'character',
|
|
62
|
+
'character varying',
|
|
63
|
+
// Temporal
|
|
64
|
+
'timestamp',
|
|
65
|
+
'timestamp without time zone',
|
|
66
|
+
'timestamp with time zone',
|
|
67
|
+
'time',
|
|
68
|
+
'timetz',
|
|
69
|
+
'interval',
|
|
70
|
+
// Bit strings
|
|
71
|
+
'bit',
|
|
72
|
+
'bit varying',
|
|
73
|
+
]);
|
|
74
|
+
|
|
75
|
+
function renderTypedParam(
|
|
76
|
+
index: number,
|
|
77
|
+
codecId: string | undefined,
|
|
78
|
+
codecLookup: CodecLookup,
|
|
79
|
+
): string {
|
|
80
|
+
if (codecId === undefined) {
|
|
81
|
+
return `$${index}`;
|
|
82
|
+
}
|
|
83
|
+
// SQL codecs extend the framework `Codec` base with an optional
|
|
84
|
+
// `meta: CodecMeta`; the framework `CodecLookup.get` returns the base type,
|
|
85
|
+
// so we narrow to `SqlCodec` to read `meta`. Every codec actually
|
|
86
|
+
// registered into a SQL codec lookup conforms to `SqlCodec`.
|
|
87
|
+
const codec = codecLookup.get(codecId) as SqlCodec | undefined;
|
|
88
|
+
if (codec === undefined) {
|
|
89
|
+
throw new Error(
|
|
90
|
+
`Postgres lowering: ParamRef carries codecId "${codecId}" but the ` +
|
|
91
|
+
'assembled codec lookup has no entry for it. This usually indicates ' +
|
|
92
|
+
'a missing extension pack in the runtime stack — register the pack ' +
|
|
93
|
+
'that contributes this codec (e.g. `extensionPacks: [pgvectorRuntime]`), ' +
|
|
94
|
+
'or use the codec directly from `@prisma-next/target-postgres/codecs` ' +
|
|
95
|
+
"if it's a builtin.",
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
const nativeType = codec.meta?.db?.sql?.postgres?.nativeType;
|
|
99
|
+
if (nativeType !== undefined && !POSTGRES_INFERRABLE_NATIVE_TYPES.has(nativeType)) {
|
|
100
|
+
return `$${index}::${nativeType}`;
|
|
101
|
+
}
|
|
102
|
+
return `$${index}`;
|
|
58
103
|
}
|
|
59
104
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
105
|
+
/**
|
|
106
|
+
* Per-render carrier threaded through every helper. Bundles the param-index
|
|
107
|
+
* map (for `$N` numbering) and the assembled-stack `codecLookup` (for
|
|
108
|
+
* cast policy at the `renderTypedParam` chokepoint). Carrying both on a
|
|
109
|
+
* single value keeps helper signatures stable.
|
|
110
|
+
*/
|
|
111
|
+
interface ParamIndexMap {
|
|
112
|
+
readonly indexMap: Map<ParamRef, number>;
|
|
113
|
+
readonly codecLookup: CodecLookup;
|
|
63
114
|
}
|
|
64
115
|
|
|
65
|
-
type ParamIndexMap = Map<ParamRef, number>;
|
|
66
|
-
|
|
67
116
|
/**
|
|
68
117
|
* Render a SQL query AST to a Postgres-flavored `{ sql, params }` payload.
|
|
69
118
|
*
|
|
@@ -74,32 +123,30 @@ type ParamIndexMap = Map<ParamRef, number>;
|
|
|
74
123
|
export function renderLoweredSql(
|
|
75
124
|
ast: AnyQueryAst,
|
|
76
125
|
contract: PostgresContract,
|
|
126
|
+
codecLookup: CodecLookup,
|
|
77
127
|
): { readonly sql: string; readonly params: readonly unknown[] } {
|
|
78
|
-
const
|
|
79
|
-
const
|
|
80
|
-
const params: unknown[] =
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
paramIndexMap.set(ref, params.length + 1);
|
|
86
|
-
params.push(ref.value);
|
|
87
|
-
}
|
|
128
|
+
const orderedRefs = collectOrderedParamRefs(ast);
|
|
129
|
+
const indexMap = new Map<ParamRef, number>();
|
|
130
|
+
const params: unknown[] = orderedRefs.map((ref, i) => {
|
|
131
|
+
indexMap.set(ref, i + 1);
|
|
132
|
+
return ref.value;
|
|
133
|
+
});
|
|
134
|
+
const pim: ParamIndexMap = { indexMap, codecLookup };
|
|
88
135
|
|
|
89
136
|
const node = ast;
|
|
90
137
|
let sql: string;
|
|
91
138
|
switch (node.kind) {
|
|
92
139
|
case 'select':
|
|
93
|
-
sql = renderSelect(node, contract,
|
|
140
|
+
sql = renderSelect(node, contract, pim);
|
|
94
141
|
break;
|
|
95
142
|
case 'insert':
|
|
96
|
-
sql = renderInsert(node, contract,
|
|
143
|
+
sql = renderInsert(node, contract, pim);
|
|
97
144
|
break;
|
|
98
145
|
case 'update':
|
|
99
|
-
sql = renderUpdate(node, contract,
|
|
146
|
+
sql = renderUpdate(node, contract, pim);
|
|
100
147
|
break;
|
|
101
148
|
case 'delete':
|
|
102
|
-
sql = renderDelete(node, contract,
|
|
149
|
+
sql = renderDelete(node, contract, pim);
|
|
103
150
|
break;
|
|
104
151
|
// v8 ignore next 4
|
|
105
152
|
default:
|
|
@@ -171,6 +218,27 @@ function renderProjection(
|
|
|
171
218
|
.join(', ');
|
|
172
219
|
}
|
|
173
220
|
|
|
221
|
+
function renderReturning(
|
|
222
|
+
items: ReadonlyArray<ProjectionItem>,
|
|
223
|
+
contract: PostgresContract,
|
|
224
|
+
pim: ParamIndexMap,
|
|
225
|
+
): string {
|
|
226
|
+
return items
|
|
227
|
+
.map((item) => {
|
|
228
|
+
if (item.expr.kind === 'column-ref') {
|
|
229
|
+
const rendered = renderColumn(item.expr);
|
|
230
|
+
return item.expr.column === item.alias
|
|
231
|
+
? rendered
|
|
232
|
+
: `${rendered} AS ${quoteIdentifier(item.alias)}`;
|
|
233
|
+
}
|
|
234
|
+
if (item.expr.kind === 'literal') {
|
|
235
|
+
return `${renderLiteral(item.expr)} AS ${quoteIdentifier(item.alias)}`;
|
|
236
|
+
}
|
|
237
|
+
return `${renderExpr(item.expr, contract, pim)} AS ${quoteIdentifier(item.alias)}`;
|
|
238
|
+
})
|
|
239
|
+
.join(', ');
|
|
240
|
+
}
|
|
241
|
+
|
|
174
242
|
function renderDistinctPrefix(
|
|
175
243
|
distinct: true | undefined,
|
|
176
244
|
distinctOn: ReadonlyArray<AnyExpression> | undefined,
|
|
@@ -457,11 +525,11 @@ function renderExpr(expr: AnyExpression, contract: PostgresContract, pim: ParamI
|
|
|
457
525
|
}
|
|
458
526
|
|
|
459
527
|
function renderParamRef(ref: ParamRef, pim: ParamIndexMap): string {
|
|
460
|
-
const index = pim.get(ref);
|
|
528
|
+
const index = pim.indexMap.get(ref);
|
|
461
529
|
if (index === undefined) {
|
|
462
530
|
throw new Error('ParamRef not found in index map');
|
|
463
531
|
}
|
|
464
|
-
return renderTypedParam(index, ref.codecId);
|
|
532
|
+
return renderTypedParam(index, ref.codecId, pim.codecLookup);
|
|
465
533
|
}
|
|
466
534
|
|
|
467
535
|
function renderLiteral(expr: LiteralExpr): string {
|
|
@@ -660,7 +728,7 @@ function renderInsert(ast: InsertAst, contract: PostgresContract, pim: ParamInde
|
|
|
660
728
|
})()
|
|
661
729
|
: '';
|
|
662
730
|
const returningClause = ast.returning?.length
|
|
663
|
-
? ` RETURNING ${ast.returning
|
|
731
|
+
? ` RETURNING ${renderReturning(ast.returning, contract, pim)}`
|
|
664
732
|
: '';
|
|
665
733
|
|
|
666
734
|
return `${insertClause}${onConflictClause}${returningClause}`;
|
|
@@ -693,7 +761,7 @@ function renderUpdate(ast: UpdateAst, contract: PostgresContract, pim: ParamInde
|
|
|
693
761
|
|
|
694
762
|
const whereClause = ast.where ? ` WHERE ${renderWhere(ast.where, contract, pim)}` : '';
|
|
695
763
|
const returningClause = ast.returning?.length
|
|
696
|
-
? ` RETURNING ${ast.returning
|
|
764
|
+
? ` RETURNING ${renderReturning(ast.returning, contract, pim)}`
|
|
697
765
|
: '';
|
|
698
766
|
|
|
699
767
|
return `UPDATE ${table} SET ${setClauses.join(', ')}${whereClause}${returningClause}`;
|
|
@@ -703,7 +771,7 @@ function renderDelete(ast: DeleteAst, contract: PostgresContract, pim: ParamInde
|
|
|
703
771
|
const table = quoteIdentifier(ast.table.name);
|
|
704
772
|
const whereClause = ast.where ? ` WHERE ${renderWhere(ast.where, contract, pim)}` : '';
|
|
705
773
|
const returningClause = ast.returning?.length
|
|
706
|
-
? ` RETURNING ${ast.returning
|
|
774
|
+
? ` RETURNING ${renderReturning(ast.returning, contract, pim)}`
|
|
707
775
|
: '';
|
|
708
776
|
|
|
709
777
|
return `DELETE FROM ${table}${whereClause}${returningClause}`;
|
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' };
|
|
@@ -10,6 +10,7 @@ import type { StorageTypeInstance } from '@prisma-next/sql-contract/types';
|
|
|
10
10
|
import {
|
|
11
11
|
PG_BIT_CODEC_ID,
|
|
12
12
|
PG_BOOL_CODEC_ID,
|
|
13
|
+
PG_BYTEA_CODEC_ID,
|
|
13
14
|
PG_ENUM_CODEC_ID,
|
|
14
15
|
PG_FLOAT4_CODEC_ID,
|
|
15
16
|
PG_FLOAT8_CODEC_ID,
|
|
@@ -29,12 +30,6 @@ import {
|
|
|
29
30
|
SQL_CHAR_CODEC_ID,
|
|
30
31
|
SQL_VARCHAR_CODEC_ID,
|
|
31
32
|
} from '@prisma-next/target-postgres/codec-ids';
|
|
32
|
-
import {
|
|
33
|
-
extractStandardSchemaOutputJsonSchema,
|
|
34
|
-
extractStandardSchemaTypeExpression,
|
|
35
|
-
isStandardSchemaLike,
|
|
36
|
-
type StandardSchemaLike,
|
|
37
|
-
} from '../core/standard-schema';
|
|
38
33
|
|
|
39
34
|
export const textColumn = {
|
|
40
35
|
codecId: PG_TEXT_CODEC_ID,
|
|
@@ -154,6 +149,19 @@ export function varbitColumn(length: number): ColumnTypeDescriptor & {
|
|
|
154
149
|
} as const;
|
|
155
150
|
}
|
|
156
151
|
|
|
152
|
+
/**
|
|
153
|
+
* Postgres `bytea` column descriptor — variable-length binary string.
|
|
154
|
+
*
|
|
155
|
+
* Round-trips as `Uint8Array` on the JS side. The pg wire-protocol text
|
|
156
|
+
* encoding (`\x` followed by hex-encoded bytes, canonical for Postgres ≥ 9.0)
|
|
157
|
+
* and binary encoding are both handled by the underlying driver; the codec
|
|
158
|
+
* only normalizes the JS-side representation to a plain `Uint8Array` view.
|
|
159
|
+
*/
|
|
160
|
+
export const byteaColumn = {
|
|
161
|
+
codecId: PG_BYTEA_CODEC_ID,
|
|
162
|
+
nativeType: 'bytea',
|
|
163
|
+
} as const satisfies ColumnTypeDescriptor;
|
|
164
|
+
|
|
157
165
|
export function intervalColumn(precision?: number): ColumnTypeDescriptor & {
|
|
158
166
|
readonly typeParams?: { readonly precision: number };
|
|
159
167
|
} {
|
|
@@ -164,68 +172,29 @@ export function intervalColumn(precision?: number): ColumnTypeDescriptor & {
|
|
|
164
172
|
} as const;
|
|
165
173
|
}
|
|
166
174
|
|
|
175
|
+
/**
|
|
176
|
+
* Postgres `json` column descriptor — untyped raw JSON.
|
|
177
|
+
*
|
|
178
|
+
* For schema-typed JSON columns, use the per-library extension package
|
|
179
|
+
* (`@prisma-next/extension-arktype-json` ships `arktypeJson(schema)` for
|
|
180
|
+
* arktype). The schema-accepting `json(schema)` / `jsonb(schema)`
|
|
181
|
+
* overloads previously shipped from this module retired in Phase C of
|
|
182
|
+
* the codec-registry-unification project — see spec § AC-7.
|
|
183
|
+
*/
|
|
167
184
|
export const jsonColumn = {
|
|
168
185
|
codecId: PG_JSON_CODEC_ID,
|
|
169
186
|
nativeType: 'json',
|
|
170
187
|
} as const satisfies ColumnTypeDescriptor;
|
|
171
188
|
|
|
189
|
+
/**
|
|
190
|
+
* Postgres `jsonb` column descriptor — untyped raw JSONB. Same retirement
|
|
191
|
+
* note as {@link jsonColumn}.
|
|
192
|
+
*/
|
|
172
193
|
export const jsonbColumn = {
|
|
173
194
|
codecId: PG_JSONB_CODEC_ID,
|
|
174
195
|
nativeType: 'jsonb',
|
|
175
196
|
} as const satisfies ColumnTypeDescriptor;
|
|
176
197
|
|
|
177
|
-
type JsonSchemaTypeParams = {
|
|
178
|
-
readonly schemaJson: Record<string, unknown>;
|
|
179
|
-
readonly type?: string;
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
function createJsonTypeParams(schema: StandardSchemaLike): JsonSchemaTypeParams {
|
|
183
|
-
const outputSchema = extractStandardSchemaOutputJsonSchema(schema);
|
|
184
|
-
if (!outputSchema) {
|
|
185
|
-
throw new Error('JSON schema must expose ~standard.jsonSchema.output()');
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const expression = extractStandardSchemaTypeExpression(schema);
|
|
189
|
-
if (expression) {
|
|
190
|
-
return { schemaJson: outputSchema, type: expression };
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
return { schemaJson: outputSchema };
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
function createJsonColumnFactory(
|
|
197
|
-
codecId: string,
|
|
198
|
-
nativeType: string,
|
|
199
|
-
staticDescriptor: ColumnTypeDescriptor,
|
|
200
|
-
) {
|
|
201
|
-
return (schema?: StandardSchemaLike): ColumnTypeDescriptor => {
|
|
202
|
-
if (!schema) {
|
|
203
|
-
return staticDescriptor;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
if (!isStandardSchemaLike(schema)) {
|
|
207
|
-
throw new Error(`${nativeType}(schema) expects a Standard Schema value`);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
return {
|
|
211
|
-
codecId,
|
|
212
|
-
nativeType,
|
|
213
|
-
typeParams: createJsonTypeParams(schema),
|
|
214
|
-
};
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
const _json = createJsonColumnFactory(PG_JSON_CODEC_ID, 'json', jsonColumn);
|
|
219
|
-
const _jsonb = createJsonColumnFactory(PG_JSONB_CODEC_ID, 'jsonb', jsonbColumn);
|
|
220
|
-
|
|
221
|
-
export function json(schema?: StandardSchemaLike): ColumnTypeDescriptor {
|
|
222
|
-
return _json(schema);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
export function jsonb(schema?: StandardSchemaLike): ColumnTypeDescriptor {
|
|
226
|
-
return _jsonb(schema);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
198
|
export function enumType<const Values extends readonly string[]>(
|
|
230
199
|
name: string,
|
|
231
200
|
values: Values,
|
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';
|
|
@@ -8,15 +9,9 @@ import type {
|
|
|
8
9
|
RuntimeParameterizedCodecDescriptor,
|
|
9
10
|
SqlRuntimeAdapterDescriptor,
|
|
10
11
|
} from '@prisma-next/sql-runtime';
|
|
11
|
-
import { PG_JSON_CODEC_ID, PG_JSONB_CODEC_ID } from '@prisma-next/target-postgres/codec-ids';
|
|
12
12
|
import { codecDefinitions } from '@prisma-next/target-postgres/codecs';
|
|
13
|
-
import { type as arktype } from 'arktype';
|
|
14
13
|
import { createPostgresAdapter } from '../core/adapter';
|
|
15
14
|
import { postgresAdapterDescriptorMeta, postgresQueryOperations } from '../core/descriptor-meta';
|
|
16
|
-
import {
|
|
17
|
-
compileJsonSchemaValidator,
|
|
18
|
-
type JsonSchemaValidateFn,
|
|
19
|
-
} from '../core/json-schema-validator';
|
|
20
15
|
import type { PostgresContract, PostgresLoweredStatement } from '../core/types';
|
|
21
16
|
|
|
22
17
|
export interface SqlRuntimeAdapter
|
|
@@ -31,20 +26,6 @@ function createPostgresCodecRegistry(): CodecRegistry {
|
|
|
31
26
|
return registry;
|
|
32
27
|
}
|
|
33
28
|
|
|
34
|
-
const jsonTypeParamsSchema = arktype({
|
|
35
|
-
schemaJson: 'object',
|
|
36
|
-
'type?': 'string',
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
/** The inferred type params shape from the arktype schema. */
|
|
40
|
-
type JsonTypeParams = typeof jsonTypeParamsSchema.infer;
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Helper returned by the JSON/JSONB `init` hook.
|
|
44
|
-
* Contains a compiled JSON Schema validate function for runtime conformance checks.
|
|
45
|
-
*/
|
|
46
|
-
export type JsonCodecHelper = { readonly validate: JsonSchemaValidateFn };
|
|
47
|
-
|
|
48
29
|
function createPostgresMutationDefaultGenerators() {
|
|
49
30
|
return builtinGeneratorIds.map((id) => ({
|
|
50
31
|
id,
|
|
@@ -55,34 +36,40 @@ function createPostgresMutationDefaultGenerators() {
|
|
|
55
36
|
}));
|
|
56
37
|
}
|
|
57
38
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
paramsSchema: jsonTypeParamsSchema,
|
|
71
|
-
init: initJsonCodecHelper,
|
|
72
|
-
},
|
|
73
|
-
] as const satisfies ReadonlyArray<
|
|
74
|
-
RuntimeParameterizedCodecDescriptor<JsonTypeParams, JsonCodecHelper>
|
|
75
|
-
>;
|
|
39
|
+
/**
|
|
40
|
+
* Phase C of codec-registry-unification: the postgres adapter retains
|
|
41
|
+
* only static raw-JSON / raw-JSONB column descriptors. Schema-typed JSON
|
|
42
|
+
* columns ship from per-library extension packages now —
|
|
43
|
+
* `@prisma-next/extension-arktype-json` for arktype, future zod / valibot
|
|
44
|
+
* extensions when each lands. The previously-shipped
|
|
45
|
+
* `parameterizedCodecDescriptors` for `pg/json@1` / `pg/jsonb@1` retired
|
|
46
|
+
* with the schema-typed surface; the unified descriptor map auto-lifts
|
|
47
|
+
* the raw json/jsonb codecs from `codecs:` via the synthesis bridge for
|
|
48
|
+
* codec-id-keyed metadata reads.
|
|
49
|
+
*/
|
|
50
|
+
const parameterizedCodecDescriptors: ReadonlyArray<RuntimeParameterizedCodecDescriptor> = [];
|
|
76
51
|
|
|
77
52
|
const postgresRuntimeAdapterDescriptor: SqlRuntimeAdapterDescriptor<'postgres', SqlRuntimeAdapter> =
|
|
78
53
|
{
|
|
79
54
|
...postgresAdapterDescriptorMeta,
|
|
80
55
|
codecs: createPostgresCodecRegistry,
|
|
81
56
|
parameterizedCodecs: () => parameterizedCodecDescriptors,
|
|
82
|
-
queryOperations: () => postgresQueryOperations,
|
|
57
|
+
queryOperations: () => postgresQueryOperations(),
|
|
83
58
|
mutationDefaultGenerators: createPostgresMutationDefaultGenerators,
|
|
84
|
-
create(
|
|
85
|
-
|
|
59
|
+
create(stack): SqlRuntimeAdapter {
|
|
60
|
+
// The runtime `ExecutionStack` does not (yet) carry a pre-assembled
|
|
61
|
+
// `codecLookup` field the way the control `ControlStack` does, so we
|
|
62
|
+
// derive an equivalent lookup here from the stack's component metadata
|
|
63
|
+
// (target + adapter + extension packs) using the same assembly helper
|
|
64
|
+
// that `createControlStack` uses. This keeps the renderer fed with the
|
|
65
|
+
// same codec set on both planes — including extension-contributed
|
|
66
|
+
// codecs like `pg/vector@1` from `@prisma-next/extension-pgvector`.
|
|
67
|
+
const codecLookup = extractCodecLookup([
|
|
68
|
+
stack.target,
|
|
69
|
+
stack.adapter,
|
|
70
|
+
...stack.extensionPacks,
|
|
71
|
+
]);
|
|
72
|
+
return createPostgresAdapter({ codecLookup });
|
|
86
73
|
},
|
|
87
74
|
};
|
|
88
75
|
|
|
@@ -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"}
|