@prisma-next/adapter-postgres 0.5.0-dev.9 → 0.5.1
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 +14 -16
- package/dist/adapter-CBaRvhQF.mjs +52 -0
- package/dist/adapter-CBaRvhQF.mjs.map +1 -0
- package/dist/adapter.d.mts +3 -4
- package/dist/adapter.d.mts.map +1 -1
- package/dist/adapter.mjs +2 -3
- package/dist/column-types.d.mts +19 -24
- package/dist/column-types.d.mts.map +1 -1
- package/dist/column-types.mjs +20 -60
- package/dist/column-types.mjs.map +1 -1
- package/dist/control.d.mts +83 -3
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +117 -29
- package/dist/control.mjs.map +1 -1
- package/dist/{descriptor-meta-RTDzyrae.mjs → descriptor-meta-CyjnYUWG.mjs} +35 -27
- package/dist/descriptor-meta-CyjnYUWG.mjs.map +1 -0
- package/dist/operation-types.d.mts +11 -10
- package/dist/operation-types.d.mts.map +1 -1
- package/dist/operation-types.mjs +1 -1
- package/dist/runtime.d.mts +3 -11
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +19 -81
- package/dist/runtime.mjs.map +1 -1
- package/dist/{sql-renderer-pEaSP82_.mjs → sql-renderer-wTVSEy5H.mjs} +109 -48
- package/dist/sql-renderer-wTVSEy5H.mjs.map +1 -0
- package/dist/{types-CfRPdAk8.d.mts → types-B1eiuBHQ.d.mts} +12 -1
- package/dist/types-B1eiuBHQ.d.mts.map +1 -0
- package/dist/types.d.mts +1 -1
- package/dist/types.mjs +1 -1
- package/package.json +23 -23
- package/src/core/adapter.ts +36 -43
- package/src/core/codec-lookup.ts +19 -0
- package/src/core/control-adapter.ts +252 -98
- package/src/core/control-mutation-defaults.ts +24 -18
- package/src/core/descriptor-meta.ts +27 -20
- package/src/core/sql-renderer.ts +129 -66
- package/src/core/types.ts +11 -0
- package/src/exports/column-types.ts +21 -61
- package/src/exports/control.ts +3 -2
- package/src/exports/runtime.ts +27 -66
- package/src/types/operation-types.ts +19 -9
- package/dist/adapter-hNElNHo4.mjs +0 -60
- 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
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,
|
|
@@ -19,87 +21,124 @@ import {
|
|
|
19
21
|
type OrderByItem,
|
|
20
22
|
type ParamRef,
|
|
21
23
|
type ProjectionItem,
|
|
24
|
+
type RawSqlExpr,
|
|
22
25
|
type SelectAst,
|
|
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 arbitrary expression positions. Parameters bound to a codec whose `meta.db.sql.postgres.nativeType` falls in this set are emitted as plain `$N`; everything else (including `json`, `jsonb`, extension types like `vector`, and unknown user types) is emitted as `$N::<nativeType>` so the planner picks an unambiguous overload.
|
|
34
|
+
*
|
|
35
|
+
* `json` / `jsonb` are intentionally excluded despite being Postgres builtins: their operator overloads make context inference unreliable in expression positions (e.g. `$1 -> 'key'` is ambiguous between the two).
|
|
42
36
|
*
|
|
43
|
-
*
|
|
44
|
-
* TML-2310 ("Move SQL param-cast metadata onto codec descriptors").
|
|
45
|
-
* Until that lands the cast lives on the renderer rather than the codec.
|
|
37
|
+
* Spellings match the on-disk `meta.db.sql.postgres.nativeType` values in `@prisma-next/target-postgres`'s codec definitions, not the `udt_name` abbreviations that ADR 205 used as illustrative shorthand. The lookup-based cast policy compares against these strings directly.
|
|
46
38
|
*/
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
39
|
+
const POSTGRES_INFERRABLE_NATIVE_TYPES: ReadonlySet<string> = new Set([
|
|
40
|
+
// Numeric
|
|
41
|
+
'integer',
|
|
42
|
+
'smallint',
|
|
43
|
+
'bigint',
|
|
44
|
+
'real',
|
|
45
|
+
'double precision',
|
|
46
|
+
'numeric',
|
|
47
|
+
// Boolean
|
|
48
|
+
'boolean',
|
|
49
|
+
// Strings
|
|
50
|
+
'text',
|
|
51
|
+
'character',
|
|
52
|
+
'character varying',
|
|
53
|
+
// Temporal
|
|
54
|
+
'timestamp',
|
|
55
|
+
'timestamp without time zone',
|
|
56
|
+
'timestamp with time zone',
|
|
57
|
+
'time',
|
|
58
|
+
'timetz',
|
|
59
|
+
'interval',
|
|
60
|
+
// Bit strings
|
|
61
|
+
'bit',
|
|
62
|
+
'bit varying',
|
|
63
|
+
]);
|
|
64
|
+
|
|
65
|
+
function renderTypedParam(
|
|
66
|
+
index: number,
|
|
67
|
+
codecId: string | undefined,
|
|
68
|
+
codecLookup: CodecLookup,
|
|
69
|
+
): string {
|
|
70
|
+
if (codecId === undefined) {
|
|
71
|
+
return `$${index}`;
|
|
72
|
+
}
|
|
73
|
+
if (codecLookup.get(codecId) === undefined) {
|
|
74
|
+
throw new Error(
|
|
75
|
+
`Postgres lowering: ParamRef carries codecId "${codecId}" but the ` +
|
|
76
|
+
'assembled codec lookup has no entry for it. This usually indicates ' +
|
|
77
|
+
'a missing extension pack in the runtime stack — register the pack ' +
|
|
78
|
+
'that contributes this codec (e.g. `extensionPacks: [pgvectorRuntime]`), ' +
|
|
79
|
+
'or use the codec directly from `@prisma-next/target-postgres/codecs` ' +
|
|
80
|
+
"if it's a builtin.",
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
// The framework `CodecLookup.metaFor` returns the family-agnostic `CodecMeta` whose `db` is `Record<string, unknown>`. The SQL family populates a narrower shape with `db.sql.<dialect>.nativeType: string`; navigate that path defensively and string-check the leaf.
|
|
84
|
+
const meta = codecLookup.metaFor(codecId);
|
|
85
|
+
const dbRecord = meta?.db;
|
|
86
|
+
const sqlBlock = isRecord(dbRecord) ? dbRecord['sql'] : undefined;
|
|
87
|
+
const dialectBlock = isRecord(sqlBlock) ? sqlBlock['postgres'] : undefined;
|
|
88
|
+
const nativeType = isRecord(dialectBlock) ? dialectBlock['nativeType'] : undefined;
|
|
89
|
+
if (typeof nativeType === 'string' && !POSTGRES_INFERRABLE_NATIVE_TYPES.has(nativeType)) {
|
|
90
|
+
return `$${index}::${nativeType}`;
|
|
91
|
+
}
|
|
92
|
+
return `$${index}`;
|
|
58
93
|
}
|
|
59
94
|
|
|
60
|
-
function
|
|
61
|
-
|
|
62
|
-
return cast ? `$${index}::${cast}` : `$${index}`;
|
|
95
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
96
|
+
return typeof value === 'object' && value !== null;
|
|
63
97
|
}
|
|
64
98
|
|
|
65
|
-
|
|
99
|
+
/**
|
|
100
|
+
* Per-render carrier threaded through every helper. Bundles the param-index map (for `$N` numbering) and the assembled-stack `codecLookup` (for cast policy at the `renderTypedParam` chokepoint). Carrying both on a single value keeps helper signatures stable.
|
|
101
|
+
*/
|
|
102
|
+
interface ParamIndexMap {
|
|
103
|
+
readonly indexMap: Map<ParamRef, number>;
|
|
104
|
+
readonly codecLookup: CodecLookup;
|
|
105
|
+
}
|
|
66
106
|
|
|
67
107
|
/**
|
|
68
108
|
* Render a SQL query AST to a Postgres-flavored `{ sql, params }` payload.
|
|
69
109
|
*
|
|
70
|
-
* Shared between the runtime (`PostgresAdapterImpl.lower`) and control
|
|
71
|
-
* (`PostgresControlAdapter.lower`) entrypoints so emit-time and run-time
|
|
72
|
-
* paths produce byte-identical output for the same AST.
|
|
110
|
+
* Shared between the runtime (`PostgresAdapterImpl.lower`) and control (`PostgresControlAdapter.lower`) entrypoints so emit-time and run-time paths produce byte-identical output for the same AST.
|
|
73
111
|
*/
|
|
74
112
|
export function renderLoweredSql(
|
|
75
113
|
ast: AnyQueryAst,
|
|
76
114
|
contract: PostgresContract,
|
|
115
|
+
codecLookup: CodecLookup,
|
|
77
116
|
): { 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
|
-
}
|
|
117
|
+
const orderedRefs = collectOrderedParamRefs(ast);
|
|
118
|
+
const indexMap = new Map<ParamRef, number>();
|
|
119
|
+
const params: unknown[] = orderedRefs.map((ref, i) => {
|
|
120
|
+
indexMap.set(ref, i + 1);
|
|
121
|
+
return ref.value;
|
|
122
|
+
});
|
|
123
|
+
const pim: ParamIndexMap = { indexMap, codecLookup };
|
|
88
124
|
|
|
89
125
|
const node = ast;
|
|
90
126
|
let sql: string;
|
|
91
127
|
switch (node.kind) {
|
|
92
128
|
case 'select':
|
|
93
|
-
sql = renderSelect(node, contract,
|
|
129
|
+
sql = renderSelect(node, contract, pim);
|
|
94
130
|
break;
|
|
95
131
|
case 'insert':
|
|
96
|
-
sql = renderInsert(node, contract,
|
|
132
|
+
sql = renderInsert(node, contract, pim);
|
|
97
133
|
break;
|
|
98
134
|
case 'update':
|
|
99
|
-
sql = renderUpdate(node, contract,
|
|
135
|
+
sql = renderUpdate(node, contract, pim);
|
|
100
136
|
break;
|
|
101
137
|
case 'delete':
|
|
102
|
-
sql = renderDelete(node, contract,
|
|
138
|
+
sql = renderDelete(node, contract, pim);
|
|
139
|
+
break;
|
|
140
|
+
case 'raw-sql':
|
|
141
|
+
sql = renderRawSql(node, contract, pim);
|
|
103
142
|
break;
|
|
104
143
|
// v8 ignore next 4
|
|
105
144
|
default:
|
|
@@ -171,6 +210,27 @@ function renderProjection(
|
|
|
171
210
|
.join(', ');
|
|
172
211
|
}
|
|
173
212
|
|
|
213
|
+
function renderReturning(
|
|
214
|
+
items: ReadonlyArray<ProjectionItem>,
|
|
215
|
+
contract: PostgresContract,
|
|
216
|
+
pim: ParamIndexMap,
|
|
217
|
+
): string {
|
|
218
|
+
return items
|
|
219
|
+
.map((item) => {
|
|
220
|
+
if (item.expr.kind === 'column-ref') {
|
|
221
|
+
const rendered = renderColumn(item.expr);
|
|
222
|
+
return item.expr.column === item.alias
|
|
223
|
+
? rendered
|
|
224
|
+
: `${rendered} AS ${quoteIdentifier(item.alias)}`;
|
|
225
|
+
}
|
|
226
|
+
if (item.expr.kind === 'literal') {
|
|
227
|
+
return `${renderLiteral(item.expr)} AS ${quoteIdentifier(item.alias)}`;
|
|
228
|
+
}
|
|
229
|
+
return `${renderExpr(item.expr, contract, pim)} AS ${quoteIdentifier(item.alias)}`;
|
|
230
|
+
})
|
|
231
|
+
.join(', ');
|
|
232
|
+
}
|
|
233
|
+
|
|
174
234
|
function renderDistinctPrefix(
|
|
175
235
|
distinct: true | undefined,
|
|
176
236
|
distinctOn: ReadonlyArray<AnyExpression> | undefined,
|
|
@@ -241,15 +301,9 @@ function renderNullCheck(
|
|
|
241
301
|
}
|
|
242
302
|
|
|
243
303
|
/**
|
|
244
|
-
* Atomic expression kinds whose rendered SQL is already self-delimited
|
|
245
|
-
* (a column reference, parameter, literal, function call, aggregate, etc.)
|
|
246
|
-
* and therefore does not need surrounding parentheses when used as the
|
|
247
|
-
* left operand of a postfix predicate like `IS NULL` or `IS NOT NULL`,
|
|
248
|
-
* or as either operand of a binary infix operator.
|
|
304
|
+
* Atomic expression kinds whose rendered SQL is already self-delimited (a column reference, parameter, literal, function call, aggregate, etc.) and therefore does not need surrounding parentheses when used as the left operand of a postfix predicate like `IS NULL` or `IS NOT NULL`, or as either operand of a binary infix operator.
|
|
249
305
|
*
|
|
250
|
-
* Anything not in this set is treated as composite (binary, AND/OR/NOT,
|
|
251
|
-
* EXISTS, nested IS NULL, subqueries, operation templates) and gets
|
|
252
|
-
* wrapped to preserve grouping.
|
|
306
|
+
* Anything not in this set is treated as composite (binary, AND/OR/NOT, EXISTS, nested IS NULL, subqueries, operation templates) and gets wrapped to preserve grouping.
|
|
253
307
|
*/
|
|
254
308
|
function isAtomicExpressionKind(kind: AnyExpression['kind']): boolean {
|
|
255
309
|
switch (kind) {
|
|
@@ -457,11 +511,11 @@ function renderExpr(expr: AnyExpression, contract: PostgresContract, pim: ParamI
|
|
|
457
511
|
}
|
|
458
512
|
|
|
459
513
|
function renderParamRef(ref: ParamRef, pim: ParamIndexMap): string {
|
|
460
|
-
const index = pim.get(ref);
|
|
514
|
+
const index = pim.indexMap.get(ref);
|
|
461
515
|
if (index === undefined) {
|
|
462
516
|
throw new Error('ParamRef not found in index map');
|
|
463
517
|
}
|
|
464
|
-
return renderTypedParam(index, ref.codecId);
|
|
518
|
+
return renderTypedParam(index, ref.codecId, pim.codecLookup);
|
|
465
519
|
}
|
|
466
520
|
|
|
467
521
|
function renderLiteral(expr: LiteralExpr): string {
|
|
@@ -503,12 +557,7 @@ function renderOperation(
|
|
|
503
557
|
return renderExpr(arg, contract, pim);
|
|
504
558
|
});
|
|
505
559
|
|
|
506
|
-
// Resolve `{{self}}` and `{{argN}}` from the original template in a single
|
|
507
|
-
// pass. Doing this with sequential `String.prototype.replace` calls is
|
|
508
|
-
// unsafe: a substituted fragment can itself contain text that matches a
|
|
509
|
-
// later token (e.g. an arg literal containing the substring `{{arg1}}`),
|
|
510
|
-
// and the next iteration would corrupt it. A single regex callback never
|
|
511
|
-
// re-scans already-substituted output.
|
|
560
|
+
// Resolve `{{self}}` and `{{argN}}` from the original template in a single pass. Doing this with sequential `String.prototype.replace` calls is unsafe: a substituted fragment can itself contain text that matches a later token (e.g. an arg literal containing the substring `{{arg1}}`), and the next iteration would corrupt it. A single regex callback never re-scans already-substituted output.
|
|
512
561
|
return expr.lowering.template.replace(
|
|
513
562
|
/\{\{self\}\}|\{\{arg(\d+)\}\}/g,
|
|
514
563
|
(token, argIndex: string | undefined) => {
|
|
@@ -660,7 +709,7 @@ function renderInsert(ast: InsertAst, contract: PostgresContract, pim: ParamInde
|
|
|
660
709
|
})()
|
|
661
710
|
: '';
|
|
662
711
|
const returningClause = ast.returning?.length
|
|
663
|
-
? ` RETURNING ${ast.returning
|
|
712
|
+
? ` RETURNING ${renderReturning(ast.returning, contract, pim)}`
|
|
664
713
|
: '';
|
|
665
714
|
|
|
666
715
|
return `${insertClause}${onConflictClause}${returningClause}`;
|
|
@@ -693,7 +742,7 @@ function renderUpdate(ast: UpdateAst, contract: PostgresContract, pim: ParamInde
|
|
|
693
742
|
|
|
694
743
|
const whereClause = ast.where ? ` WHERE ${renderWhere(ast.where, contract, pim)}` : '';
|
|
695
744
|
const returningClause = ast.returning?.length
|
|
696
|
-
? ` RETURNING ${ast.returning
|
|
745
|
+
? ` RETURNING ${renderReturning(ast.returning, contract, pim)}`
|
|
697
746
|
: '';
|
|
698
747
|
|
|
699
748
|
return `UPDATE ${table} SET ${setClauses.join(', ')}${whereClause}${returningClause}`;
|
|
@@ -703,8 +752,22 @@ function renderDelete(ast: DeleteAst, contract: PostgresContract, pim: ParamInde
|
|
|
703
752
|
const table = quoteIdentifier(ast.table.name);
|
|
704
753
|
const whereClause = ast.where ? ` WHERE ${renderWhere(ast.where, contract, pim)}` : '';
|
|
705
754
|
const returningClause = ast.returning?.length
|
|
706
|
-
? ` RETURNING ${ast.returning
|
|
755
|
+
? ` RETURNING ${renderReturning(ast.returning, contract, pim)}`
|
|
707
756
|
: '';
|
|
708
757
|
|
|
709
758
|
return `DELETE FROM ${table}${whereClause}${returningClause}`;
|
|
710
759
|
}
|
|
760
|
+
|
|
761
|
+
function renderRawSql(ast: RawSqlExpr, contract: PostgresContract, pim: ParamIndexMap): string {
|
|
762
|
+
const out: string[] = [];
|
|
763
|
+
for (let i = 0; i < ast.fragments.length; i++) {
|
|
764
|
+
out.push(ast.fragments[i] ?? '');
|
|
765
|
+
if (i < ast.args.length) {
|
|
766
|
+
const arg = ast.args[i];
|
|
767
|
+
if (arg !== undefined) {
|
|
768
|
+
out.push(renderExpr(arg, contract, pim));
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
return out.join('');
|
|
773
|
+
}
|
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' };
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Column type descriptors for Postgres adapter.
|
|
3
3
|
*
|
|
4
|
-
* These descriptors provide both codecId and nativeType for use in contract authoring.
|
|
5
|
-
* They are derived from the same source of truth as codec definitions and manifests.
|
|
4
|
+
* These descriptors provide both codecId and nativeType for use in contract authoring. They are derived from the same source of truth as codec definitions and manifests.
|
|
6
5
|
*/
|
|
7
6
|
|
|
8
|
-
import type { ColumnTypeDescriptor } from '@prisma-next/
|
|
7
|
+
import type { ColumnTypeDescriptor } from '@prisma-next/framework-components/codec';
|
|
9
8
|
import type { StorageTypeInstance } from '@prisma-next/sql-contract/types';
|
|
10
9
|
import {
|
|
11
10
|
PG_BIT_CODEC_ID,
|
|
12
11
|
PG_BOOL_CODEC_ID,
|
|
12
|
+
PG_BYTEA_CODEC_ID,
|
|
13
13
|
PG_ENUM_CODEC_ID,
|
|
14
14
|
PG_FLOAT4_CODEC_ID,
|
|
15
15
|
PG_FLOAT8_CODEC_ID,
|
|
@@ -29,12 +29,6 @@ import {
|
|
|
29
29
|
SQL_CHAR_CODEC_ID,
|
|
30
30
|
SQL_VARCHAR_CODEC_ID,
|
|
31
31
|
} from '@prisma-next/target-postgres/codec-ids';
|
|
32
|
-
import {
|
|
33
|
-
extractStandardSchemaOutputJsonSchema,
|
|
34
|
-
extractStandardSchemaTypeExpression,
|
|
35
|
-
isStandardSchemaLike,
|
|
36
|
-
type StandardSchemaLike,
|
|
37
|
-
} from '../core/standard-schema';
|
|
38
32
|
|
|
39
33
|
export const textColumn = {
|
|
40
34
|
codecId: PG_TEXT_CODEC_ID,
|
|
@@ -154,6 +148,16 @@ export function varbitColumn(length: number): ColumnTypeDescriptor & {
|
|
|
154
148
|
} as const;
|
|
155
149
|
}
|
|
156
150
|
|
|
151
|
+
/**
|
|
152
|
+
* Postgres `bytea` column descriptor — variable-length binary string.
|
|
153
|
+
*
|
|
154
|
+
* Round-trips as `Uint8Array` on the JS side. The pg wire-protocol text encoding (`\x` followed by hex-encoded bytes, canonical for Postgres ≥ 9.0) and binary encoding are both handled by the underlying driver; the codec only normalizes the JS-side representation to a plain `Uint8Array` view.
|
|
155
|
+
*/
|
|
156
|
+
export const byteaColumn = {
|
|
157
|
+
codecId: PG_BYTEA_CODEC_ID,
|
|
158
|
+
nativeType: 'bytea',
|
|
159
|
+
} as const satisfies ColumnTypeDescriptor;
|
|
160
|
+
|
|
157
161
|
export function intervalColumn(precision?: number): ColumnTypeDescriptor & {
|
|
158
162
|
readonly typeParams?: { readonly precision: number };
|
|
159
163
|
} {
|
|
@@ -164,68 +168,24 @@ export function intervalColumn(precision?: number): ColumnTypeDescriptor & {
|
|
|
164
168
|
} as const;
|
|
165
169
|
}
|
|
166
170
|
|
|
171
|
+
/**
|
|
172
|
+
* Postgres `json` column descriptor — untyped raw JSON.
|
|
173
|
+
*
|
|
174
|
+
* For schema-typed JSON columns, use the per-library extension package (`@prisma-next/extension-arktype-json` ships `arktypeJson(schema)` for arktype). The schema-accepting `json(schema)` / `jsonb(schema)` overloads previously shipped from this module retired in Phase C of the codec-registry-unification project — see spec § AC-7.
|
|
175
|
+
*/
|
|
167
176
|
export const jsonColumn = {
|
|
168
177
|
codecId: PG_JSON_CODEC_ID,
|
|
169
178
|
nativeType: 'json',
|
|
170
179
|
} as const satisfies ColumnTypeDescriptor;
|
|
171
180
|
|
|
181
|
+
/**
|
|
182
|
+
* Postgres `jsonb` column descriptor — untyped raw JSONB. Same retirement note as {@link jsonColumn}.
|
|
183
|
+
*/
|
|
172
184
|
export const jsonbColumn = {
|
|
173
185
|
codecId: PG_JSONB_CODEC_ID,
|
|
174
186
|
nativeType: 'jsonb',
|
|
175
187
|
} as const satisfies ColumnTypeDescriptor;
|
|
176
188
|
|
|
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
189
|
export function enumType<const Values extends readonly string[]>(
|
|
230
190
|
name: string,
|
|
231
191
|
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,88 +1,49 @@
|
|
|
1
1
|
import type { GeneratedValueSpec } from '@prisma-next/contract/types';
|
|
2
|
+
import { timestampNowRuntimeGenerator } from '@prisma-next/family-sql/runtime';
|
|
3
|
+
import { extractCodecLookup } from '@prisma-next/framework-components/control';
|
|
2
4
|
import type { RuntimeAdapterInstance } from '@prisma-next/framework-components/execution';
|
|
3
5
|
import { builtinGeneratorIds } from '@prisma-next/ids';
|
|
4
6
|
import { generateId } from '@prisma-next/ids/runtime';
|
|
5
|
-
import type { Adapter, AnyQueryAst
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
RuntimeParameterizedCodecDescriptor,
|
|
9
|
-
SqlRuntimeAdapterDescriptor,
|
|
10
|
-
} from '@prisma-next/sql-runtime';
|
|
11
|
-
import { PG_JSON_CODEC_ID, PG_JSONB_CODEC_ID } from '@prisma-next/target-postgres/codec-ids';
|
|
12
|
-
import { codecDefinitions } from '@prisma-next/target-postgres/codecs';
|
|
13
|
-
import { type as arktype } from 'arktype';
|
|
7
|
+
import type { Adapter, AnyQueryAst } from '@prisma-next/sql-relational-core/ast';
|
|
8
|
+
import type { SqlRuntimeAdapterDescriptor } from '@prisma-next/sql-runtime';
|
|
9
|
+
import { postgresCodecRegistry } from '@prisma-next/target-postgres/codecs';
|
|
14
10
|
import { createPostgresAdapter } from '../core/adapter';
|
|
15
11
|
import { postgresAdapterDescriptorMeta, postgresQueryOperations } from '../core/descriptor-meta';
|
|
16
|
-
import {
|
|
17
|
-
compileJsonSchemaValidator,
|
|
18
|
-
type JsonSchemaValidateFn,
|
|
19
|
-
} from '../core/json-schema-validator';
|
|
20
12
|
import type { PostgresContract, PostgresLoweredStatement } from '../core/types';
|
|
21
13
|
|
|
22
14
|
export interface SqlRuntimeAdapter
|
|
23
15
|
extends RuntimeAdapterInstance<'sql', 'postgres'>,
|
|
24
16
|
Adapter<AnyQueryAst, PostgresContract, PostgresLoweredStatement> {}
|
|
25
17
|
|
|
26
|
-
function createPostgresCodecRegistry(): CodecRegistry {
|
|
27
|
-
const registry = createCodecRegistry();
|
|
28
|
-
for (const definition of Object.values(codecDefinitions)) {
|
|
29
|
-
registry.register(definition.codec);
|
|
30
|
-
}
|
|
31
|
-
return registry;
|
|
32
|
-
}
|
|
33
|
-
|
|
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
18
|
function createPostgresMutationDefaultGenerators() {
|
|
49
|
-
return
|
|
50
|
-
id
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
19
|
+
return [
|
|
20
|
+
...builtinGeneratorIds.map((id) => ({
|
|
21
|
+
id,
|
|
22
|
+
generate: (params?: Record<string, unknown>) => {
|
|
23
|
+
const spec: GeneratedValueSpec = params ? { id, params } : { id };
|
|
24
|
+
return generateId(spec);
|
|
25
|
+
},
|
|
26
|
+
stability: 'field' as const,
|
|
27
|
+
})),
|
|
28
|
+
timestampNowRuntimeGenerator(),
|
|
29
|
+
];
|
|
56
30
|
}
|
|
57
31
|
|
|
58
|
-
function initJsonCodecHelper(params: JsonTypeParams): JsonCodecHelper {
|
|
59
|
-
return { validate: compileJsonSchemaValidator(params.schemaJson as Record<string, unknown>) };
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const parameterizedCodecDescriptors = [
|
|
63
|
-
{
|
|
64
|
-
codecId: PG_JSON_CODEC_ID,
|
|
65
|
-
paramsSchema: jsonTypeParamsSchema,
|
|
66
|
-
init: initJsonCodecHelper,
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
codecId: PG_JSONB_CODEC_ID,
|
|
70
|
-
paramsSchema: jsonTypeParamsSchema,
|
|
71
|
-
init: initJsonCodecHelper,
|
|
72
|
-
},
|
|
73
|
-
] as const satisfies ReadonlyArray<
|
|
74
|
-
RuntimeParameterizedCodecDescriptor<JsonTypeParams, JsonCodecHelper>
|
|
75
|
-
>;
|
|
76
|
-
|
|
77
32
|
const postgresRuntimeAdapterDescriptor: SqlRuntimeAdapterDescriptor<'postgres', SqlRuntimeAdapter> =
|
|
78
33
|
{
|
|
79
34
|
...postgresAdapterDescriptorMeta,
|
|
80
|
-
codecs:
|
|
81
|
-
|
|
82
|
-
queryOperations: () => postgresQueryOperations,
|
|
35
|
+
codecs: () => Array.from(postgresCodecRegistry.values()),
|
|
36
|
+
queryOperations: () => postgresQueryOperations(),
|
|
83
37
|
mutationDefaultGenerators: createPostgresMutationDefaultGenerators,
|
|
84
|
-
create(
|
|
85
|
-
|
|
38
|
+
create(stack): SqlRuntimeAdapter {
|
|
39
|
+
// The runtime `ExecutionStack` does not (yet) carry a pre-assembled `codecLookup` field the way the control `ControlStack` does, so we derive an equivalent lookup here from the stack's component metadata (target + adapter + extension packs) using the same assembly helper that `createControlStack` uses. This keeps the renderer fed with the same codec set on both planes — including extension-contributed codecs like
|
|
40
|
+
// `pg/vector@1` from `@prisma-next/extension-pgvector`.
|
|
41
|
+
const codecLookup = extractCodecLookup([
|
|
42
|
+
stack.target,
|
|
43
|
+
stack.adapter,
|
|
44
|
+
...stack.extensionPacks,
|
|
45
|
+
]);
|
|
46
|
+
return createPostgresAdapter({ codecLookup });
|
|
86
47
|
},
|
|
87
48
|
};
|
|
88
49
|
|
|
@@ -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,60 +0,0 @@
|
|
|
1
|
-
import { t as renderLoweredSql } from "./sql-renderer-pEaSP82_.mjs";
|
|
2
|
-
import { createCodecRegistry } from "@prisma-next/sql-relational-core/ast";
|
|
3
|
-
import { codecDefinitions } from "@prisma-next/target-postgres/codecs";
|
|
4
|
-
import { ifDefined } from "@prisma-next/utils/defined";
|
|
5
|
-
|
|
6
|
-
//#region src/core/adapter.ts
|
|
7
|
-
const defaultCapabilities = Object.freeze({
|
|
8
|
-
postgres: {
|
|
9
|
-
orderBy: true,
|
|
10
|
-
limit: true,
|
|
11
|
-
lateral: true,
|
|
12
|
-
jsonAgg: true,
|
|
13
|
-
returning: true
|
|
14
|
-
},
|
|
15
|
-
sql: {
|
|
16
|
-
enums: true,
|
|
17
|
-
returning: true,
|
|
18
|
-
defaultInInsert: true
|
|
19
|
-
}
|
|
20
|
-
});
|
|
21
|
-
const parameterizedCodecs = Object.values(codecDefinitions).map((definition) => definition.codec).filter((codec) => codec.paramsSchema !== void 0).map((codec) => Object.freeze({
|
|
22
|
-
codecId: codec.id,
|
|
23
|
-
paramsSchema: codec.paramsSchema,
|
|
24
|
-
...ifDefined("init", codec.init)
|
|
25
|
-
}));
|
|
26
|
-
var PostgresAdapterImpl = class {
|
|
27
|
-
familyId = "sql";
|
|
28
|
-
targetId = "postgres";
|
|
29
|
-
profile;
|
|
30
|
-
codecRegistry = (() => {
|
|
31
|
-
const registry = createCodecRegistry();
|
|
32
|
-
for (const definition of Object.values(codecDefinitions)) registry.register(definition.codec);
|
|
33
|
-
return registry;
|
|
34
|
-
})();
|
|
35
|
-
constructor(options) {
|
|
36
|
-
this.profile = Object.freeze({
|
|
37
|
-
id: options?.profileId ?? "postgres/default@1",
|
|
38
|
-
target: "postgres",
|
|
39
|
-
capabilities: defaultCapabilities,
|
|
40
|
-
codecs: () => this.codecRegistry,
|
|
41
|
-
readMarkerStatement: () => ({
|
|
42
|
-
sql: "select core_hash, profile_hash, contract_json, canonical_version, updated_at, app_tag, meta from prisma_contract.marker where id = $1",
|
|
43
|
-
params: [1]
|
|
44
|
-
})
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
parameterizedCodecs() {
|
|
48
|
-
return parameterizedCodecs;
|
|
49
|
-
}
|
|
50
|
-
lower(ast, context) {
|
|
51
|
-
return renderLoweredSql(ast, context.contract);
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
function createPostgresAdapter(options) {
|
|
55
|
-
return Object.freeze(new PostgresAdapterImpl(options));
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
//#endregion
|
|
59
|
-
export { createPostgresAdapter as t };
|
|
60
|
-
//# sourceMappingURL=adapter-hNElNHo4.mjs.map
|