@prisma-next/target-sqlite 0.5.0-dev.9 → 0.6.0-dev.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/dist/codec-ids-CYwMu3-4.d.mts +13 -0
- package/dist/codec-ids-CYwMu3-4.d.mts.map +1 -0
- package/dist/codec-ids-CuUxYcd0.mjs +13 -0
- package/dist/codec-ids-CuUxYcd0.mjs.map +1 -0
- package/dist/codec-ids.d.mts +2 -0
- package/dist/codec-ids.mjs +2 -0
- package/dist/codec-types-xLeyb_u4.d.mts +23 -0
- package/dist/codec-types-xLeyb_u4.d.mts.map +1 -0
- package/dist/codec-types.d.mts +3 -0
- package/dist/codec-types.mjs +2 -0
- package/dist/codecs-DEjc7dem.d.mts +203 -0
- package/dist/codecs-DEjc7dem.d.mts.map +1 -0
- package/dist/codecs-DVnHtVWW.mjs +220 -0
- package/dist/codecs-DVnHtVWW.mjs.map +1 -0
- package/dist/codecs.d.mts +2 -0
- package/dist/codecs.mjs +13 -0
- package/dist/codecs.mjs.map +1 -0
- package/dist/control.d.mts +4 -3
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +427 -5
- package/dist/control.mjs.map +1 -1
- package/dist/default-normalizer-3Fccw7yw.mjs +69 -0
- package/dist/default-normalizer-3Fccw7yw.mjs.map +1 -0
- package/dist/default-normalizer.d.mts +7 -0
- package/dist/default-normalizer.d.mts.map +1 -0
- package/dist/default-normalizer.mjs +2 -0
- package/dist/descriptor-meta-CE2Kbn9b.mjs +17 -0
- package/dist/descriptor-meta-CE2Kbn9b.mjs.map +1 -0
- package/dist/migration.d.mts +85 -0
- package/dist/migration.d.mts.map +1 -0
- package/dist/migration.mjs +49 -0
- package/dist/migration.mjs.map +1 -0
- package/dist/native-type-normalizer-BlN5XfD-.mjs +14 -0
- package/dist/native-type-normalizer-BlN5XfD-.mjs.map +1 -0
- package/dist/native-type-normalizer.d.mts +11 -0
- package/dist/native-type-normalizer.d.mts.map +1 -0
- package/dist/native-type-normalizer.mjs +2 -0
- package/dist/op-factory-call-DRKKURAO.mjs +279 -0
- package/dist/op-factory-call-DRKKURAO.mjs.map +1 -0
- package/dist/op-factory-call.d.mts +151 -0
- package/dist/op-factory-call.d.mts.map +1 -0
- package/dist/op-factory-call.mjs +2 -0
- package/dist/pack.d.mts +35 -1
- package/dist/pack.d.mts.map +1 -1
- package/dist/pack.mjs +2 -3
- package/dist/planner-A7dqS0u6.mjs +522 -0
- package/dist/planner-A7dqS0u6.mjs.map +1 -0
- package/dist/planner-produced-sqlite-migration-CI9LdXPr.d.mts +29 -0
- package/dist/planner-produced-sqlite-migration-CI9LdXPr.d.mts.map +1 -0
- package/dist/planner-produced-sqlite-migration-C_TzWbT0.mjs +110 -0
- package/dist/planner-produced-sqlite-migration-C_TzWbT0.mjs.map +1 -0
- package/dist/planner-produced-sqlite-migration.d.mts +2 -0
- package/dist/planner-produced-sqlite-migration.mjs +2 -0
- package/dist/planner-target-details-Bm71XPKb.mjs +15 -0
- package/dist/planner-target-details-Bm71XPKb.mjs.map +1 -0
- package/dist/planner-target-details-vhvZDWK1.d.mts +12 -0
- package/dist/planner-target-details-vhvZDWK1.d.mts.map +1 -0
- package/dist/planner-target-details.d.mts +2 -0
- package/dist/planner-target-details.mjs +2 -0
- package/dist/planner.d.mts +59 -0
- package/dist/planner.d.mts.map +1 -0
- package/dist/planner.mjs +2 -0
- package/dist/render-ops-CSRDT4YL.mjs +8 -0
- package/dist/render-ops-CSRDT4YL.mjs.map +1 -0
- package/dist/render-ops.d.mts +10 -0
- package/dist/render-ops.d.mts.map +1 -0
- package/dist/render-ops.mjs +2 -0
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +4 -8
- package/dist/runtime.mjs.map +1 -1
- package/dist/shared-qLsgTOZs.d.mts +69 -0
- package/dist/shared-qLsgTOZs.d.mts.map +1 -0
- package/dist/sql-utils-DhevMgef.mjs +35 -0
- package/dist/sql-utils-DhevMgef.mjs.map +1 -0
- package/dist/sql-utils.d.mts +22 -0
- package/dist/sql-utils.d.mts.map +1 -0
- package/dist/sql-utils.mjs +2 -0
- package/dist/sqlite-migration-BBJktVVw.mjs +16 -0
- package/dist/sqlite-migration-BBJktVVw.mjs.map +1 -0
- package/dist/sqlite-migration-DAb2NEX6.d.mts +17 -0
- package/dist/sqlite-migration-DAb2NEX6.d.mts.map +1 -0
- package/dist/statement-builders-Dne-LkAV.mjs +158 -0
- package/dist/statement-builders-Dne-LkAV.mjs.map +1 -0
- package/dist/statement-builders.d.mts +68 -0
- package/dist/statement-builders.d.mts.map +1 -0
- package/dist/statement-builders.mjs +2 -0
- package/dist/tables-D84zfPZI.mjs +403 -0
- package/dist/tables-D84zfPZI.mjs.map +1 -0
- package/package.json +33 -11
- package/src/core/authoring.ts +9 -0
- package/src/core/codec-helpers.ts +11 -0
- package/src/core/codec-ids.ts +13 -0
- package/src/core/codecs.ts +337 -0
- package/src/core/control-target.ts +53 -11
- package/src/core/default-normalizer.ts +92 -0
- package/src/core/descriptor-meta.ts +5 -1
- package/src/core/migrations/issue-planner.ts +586 -0
- package/src/core/migrations/op-factory-call.ts +369 -0
- package/src/core/migrations/operations/columns.ts +62 -0
- package/src/core/migrations/operations/data-transform.ts +51 -0
- package/src/core/migrations/operations/indexes.ts +52 -0
- package/src/core/migrations/operations/raw.ts +12 -0
- package/src/core/migrations/operations/shared.ts +120 -0
- package/src/core/migrations/operations/tables.ts +388 -0
- package/src/core/migrations/planner-ddl-builders.ts +142 -0
- package/src/core/migrations/planner-produced-sqlite-migration.ts +70 -0
- package/src/core/migrations/planner-strategies.ts +231 -0
- package/src/core/migrations/planner-target-details.ts +33 -0
- package/src/core/migrations/planner.ts +183 -0
- package/src/core/migrations/render-ops.ts +15 -0
- package/src/core/migrations/render-typescript.ts +91 -0
- package/src/core/migrations/runner.ts +724 -0
- package/src/core/migrations/sqlite-migration.ts +13 -0
- package/src/core/migrations/statement-builders.ts +212 -0
- package/src/core/native-type-normalizer.ts +9 -0
- package/src/core/registry.ts +11 -0
- package/src/core/runtime-target.ts +1 -3
- package/src/core/sql-utils.ts +47 -0
- package/src/exports/codec-ids.ts +13 -0
- package/src/exports/codec-types.ts +43 -0
- package/src/exports/codecs.ts +20 -0
- package/src/exports/control.ts +1 -0
- package/src/exports/default-normalizer.ts +1 -0
- package/src/exports/migration.ts +24 -0
- package/src/exports/native-type-normalizer.ts +1 -0
- package/src/exports/op-factory-call.ts +12 -0
- package/src/exports/planner-produced-sqlite-migration.ts +4 -0
- package/src/exports/planner-target-details.ts +2 -0
- package/src/exports/planner.ts +2 -0
- package/src/exports/render-ops.ts +1 -0
- package/src/exports/sql-utils.ts +1 -0
- package/src/exports/statement-builders.ts +12 -0
- package/dist/descriptor-meta-DbuuziYA.mjs +0 -14
- package/dist/descriptor-meta-DbuuziYA.mjs.map +0 -1
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native SQLite target codecs (TML-2357). Mirrors the Postgres codec class form in `packages/3-targets/3-targets/postgres/src/core/codecs.ts`.
|
|
3
|
+
*
|
|
4
|
+
* Each codec ships as three artifacts:
|
|
5
|
+
*
|
|
6
|
+
* 1. A `SqliteXCodec` class extending {@link CodecImpl} that wraps the encode/decode/encodeJson/decodeJson conversions inline. SQLite's runtime conversions are simple enough that there is no shared helper module; the class bodies are the single source of truth. 2. A `SqliteXDescriptor` class extending {@link CodecDescriptorImpl} declaring the codec id, traits, target types, and params schema. SQLite codecs do not carry
|
|
7
|
+
* `meta` (no per-target native-type meta today) and are all non-parameterized. 3. A per-codec column helper (`sqliteXColumn`) that calls `descriptor.factory()` directly and packages the result into a {@link ColumnSpec} via the framework {@link column} packager. The helper is tied to its descriptor with `satisfies ColumnHelperFor` + `ColumnHelperForStrict` (every SQLite codec's resolved type is well-defined).
|
|
8
|
+
*
|
|
9
|
+
* After TML-2357 this is the canonical source of SQLite codec metadata and runtime behaviour — the legacy `mkCodec` / `defineCodec` carriers (and the parallel `byScalar` / `codecDescriptorDefinitions` collection exports) retired with the deletion sweep.
|
|
10
|
+
*
|
|
11
|
+
* Audit: every SQLite codec is non-parameterized and parameter-stateless; `factory()` takes no params (`P = void`) and returns a fresh codec constructed solely from `this`.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type { JsonValue } from '@prisma-next/contract/types';
|
|
15
|
+
import {
|
|
16
|
+
type AnyCodecDescriptor,
|
|
17
|
+
type CodecCallContext,
|
|
18
|
+
CodecDescriptorImpl,
|
|
19
|
+
CodecImpl,
|
|
20
|
+
type CodecInstanceContext,
|
|
21
|
+
type ColumnHelperFor,
|
|
22
|
+
type ColumnHelperForStrict,
|
|
23
|
+
column,
|
|
24
|
+
voidParamsSchema,
|
|
25
|
+
} from '@prisma-next/framework-components/codec';
|
|
26
|
+
import {
|
|
27
|
+
sqlCharDescriptor,
|
|
28
|
+
sqlFloatDescriptor,
|
|
29
|
+
sqlIntDescriptor,
|
|
30
|
+
sqlVarcharDescriptor,
|
|
31
|
+
} from '@prisma-next/sql-relational-core/ast';
|
|
32
|
+
import {
|
|
33
|
+
SQLITE_BIGINT_CODEC_ID,
|
|
34
|
+
SQLITE_BLOB_CODEC_ID,
|
|
35
|
+
SQLITE_DATETIME_CODEC_ID,
|
|
36
|
+
SQLITE_INTEGER_CODEC_ID,
|
|
37
|
+
SQLITE_JSON_CODEC_ID,
|
|
38
|
+
SQLITE_REAL_CODEC_ID,
|
|
39
|
+
SQLITE_TEXT_CODEC_ID,
|
|
40
|
+
} from './codec-ids';
|
|
41
|
+
|
|
42
|
+
export class SqliteTextCodec extends CodecImpl<
|
|
43
|
+
typeof SQLITE_TEXT_CODEC_ID,
|
|
44
|
+
readonly ['equality', 'order', 'textual'],
|
|
45
|
+
string,
|
|
46
|
+
string
|
|
47
|
+
> {
|
|
48
|
+
async encode(value: string, _ctx: CodecCallContext): Promise<string> {
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
async decode(wire: string, _ctx: CodecCallContext): Promise<string> {
|
|
52
|
+
return wire;
|
|
53
|
+
}
|
|
54
|
+
encodeJson(value: string): JsonValue {
|
|
55
|
+
return value;
|
|
56
|
+
}
|
|
57
|
+
decodeJson(json: JsonValue): string {
|
|
58
|
+
return json as string;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export class SqliteTextDescriptor extends CodecDescriptorImpl<void> {
|
|
63
|
+
override readonly codecId = SQLITE_TEXT_CODEC_ID;
|
|
64
|
+
override readonly traits = ['equality', 'order', 'textual'] as const;
|
|
65
|
+
override readonly targetTypes = ['text'] as const;
|
|
66
|
+
override readonly paramsSchema = voidParamsSchema;
|
|
67
|
+
override factory(): (ctx: CodecInstanceContext) => SqliteTextCodec {
|
|
68
|
+
return () => new SqliteTextCodec(this);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export const sqliteTextDescriptor = new SqliteTextDescriptor();
|
|
73
|
+
|
|
74
|
+
export const sqliteTextColumn = () =>
|
|
75
|
+
column(sqliteTextDescriptor.factory(), sqliteTextDescriptor.codecId, undefined, 'text');
|
|
76
|
+
|
|
77
|
+
sqliteTextColumn satisfies ColumnHelperFor<SqliteTextDescriptor>;
|
|
78
|
+
sqliteTextColumn satisfies ColumnHelperForStrict<SqliteTextDescriptor>;
|
|
79
|
+
|
|
80
|
+
export class SqliteIntegerCodec extends CodecImpl<
|
|
81
|
+
typeof SQLITE_INTEGER_CODEC_ID,
|
|
82
|
+
readonly ['equality', 'order', 'numeric'],
|
|
83
|
+
number,
|
|
84
|
+
number
|
|
85
|
+
> {
|
|
86
|
+
async encode(value: number, _ctx: CodecCallContext): Promise<number> {
|
|
87
|
+
return value;
|
|
88
|
+
}
|
|
89
|
+
async decode(wire: number, _ctx: CodecCallContext): Promise<number> {
|
|
90
|
+
return wire;
|
|
91
|
+
}
|
|
92
|
+
encodeJson(value: number): JsonValue {
|
|
93
|
+
return value;
|
|
94
|
+
}
|
|
95
|
+
decodeJson(json: JsonValue): number {
|
|
96
|
+
return json as number;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export class SqliteIntegerDescriptor extends CodecDescriptorImpl<void> {
|
|
101
|
+
override readonly codecId = SQLITE_INTEGER_CODEC_ID;
|
|
102
|
+
override readonly traits = ['equality', 'order', 'numeric'] as const;
|
|
103
|
+
override readonly targetTypes = ['integer'] as const;
|
|
104
|
+
override readonly paramsSchema = voidParamsSchema;
|
|
105
|
+
override factory(): (ctx: CodecInstanceContext) => SqliteIntegerCodec {
|
|
106
|
+
return () => new SqliteIntegerCodec(this);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export const sqliteIntegerDescriptor = new SqliteIntegerDescriptor();
|
|
111
|
+
|
|
112
|
+
export const sqliteIntegerColumn = () =>
|
|
113
|
+
column(sqliteIntegerDescriptor.factory(), sqliteIntegerDescriptor.codecId, undefined, 'integer');
|
|
114
|
+
|
|
115
|
+
sqliteIntegerColumn satisfies ColumnHelperFor<SqliteIntegerDescriptor>;
|
|
116
|
+
sqliteIntegerColumn satisfies ColumnHelperForStrict<SqliteIntegerDescriptor>;
|
|
117
|
+
|
|
118
|
+
export class SqliteRealCodec extends CodecImpl<
|
|
119
|
+
typeof SQLITE_REAL_CODEC_ID,
|
|
120
|
+
readonly ['equality', 'order', 'numeric'],
|
|
121
|
+
number,
|
|
122
|
+
number
|
|
123
|
+
> {
|
|
124
|
+
async encode(value: number, _ctx: CodecCallContext): Promise<number> {
|
|
125
|
+
return value;
|
|
126
|
+
}
|
|
127
|
+
async decode(wire: number, _ctx: CodecCallContext): Promise<number> {
|
|
128
|
+
return wire;
|
|
129
|
+
}
|
|
130
|
+
encodeJson(value: number): JsonValue {
|
|
131
|
+
return value;
|
|
132
|
+
}
|
|
133
|
+
decodeJson(json: JsonValue): number {
|
|
134
|
+
return json as number;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export class SqliteRealDescriptor extends CodecDescriptorImpl<void> {
|
|
139
|
+
override readonly codecId = SQLITE_REAL_CODEC_ID;
|
|
140
|
+
override readonly traits = ['equality', 'order', 'numeric'] as const;
|
|
141
|
+
override readonly targetTypes = ['real'] as const;
|
|
142
|
+
override readonly paramsSchema = voidParamsSchema;
|
|
143
|
+
override factory(): (ctx: CodecInstanceContext) => SqliteRealCodec {
|
|
144
|
+
return () => new SqliteRealCodec(this);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export const sqliteRealDescriptor = new SqliteRealDescriptor();
|
|
149
|
+
|
|
150
|
+
export const sqliteRealColumn = () =>
|
|
151
|
+
column(sqliteRealDescriptor.factory(), sqliteRealDescriptor.codecId, undefined, 'real');
|
|
152
|
+
|
|
153
|
+
sqliteRealColumn satisfies ColumnHelperFor<SqliteRealDescriptor>;
|
|
154
|
+
sqliteRealColumn satisfies ColumnHelperForStrict<SqliteRealDescriptor>;
|
|
155
|
+
|
|
156
|
+
export class SqliteBlobCodec extends CodecImpl<
|
|
157
|
+
typeof SQLITE_BLOB_CODEC_ID,
|
|
158
|
+
readonly ['equality'],
|
|
159
|
+
Uint8Array,
|
|
160
|
+
Uint8Array
|
|
161
|
+
> {
|
|
162
|
+
async encode(value: Uint8Array, _ctx: CodecCallContext): Promise<Uint8Array> {
|
|
163
|
+
return value;
|
|
164
|
+
}
|
|
165
|
+
async decode(wire: Uint8Array, _ctx: CodecCallContext): Promise<Uint8Array> {
|
|
166
|
+
return wire;
|
|
167
|
+
}
|
|
168
|
+
encodeJson(value: Uint8Array): JsonValue {
|
|
169
|
+
return Buffer.from(value).toString('base64');
|
|
170
|
+
}
|
|
171
|
+
decodeJson(json: JsonValue): Uint8Array {
|
|
172
|
+
if (typeof json !== 'string') {
|
|
173
|
+
throw new TypeError('sqlite/blob@1 contract value must be a base64 string');
|
|
174
|
+
}
|
|
175
|
+
return new Uint8Array(Buffer.from(json, 'base64'));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export class SqliteBlobDescriptor extends CodecDescriptorImpl<void> {
|
|
180
|
+
override readonly codecId = SQLITE_BLOB_CODEC_ID;
|
|
181
|
+
override readonly traits = ['equality'] as const;
|
|
182
|
+
override readonly targetTypes = ['blob'] as const;
|
|
183
|
+
override readonly paramsSchema = voidParamsSchema;
|
|
184
|
+
override factory(): (ctx: CodecInstanceContext) => SqliteBlobCodec {
|
|
185
|
+
return () => new SqliteBlobCodec(this);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export const sqliteBlobDescriptor = new SqliteBlobDescriptor();
|
|
190
|
+
|
|
191
|
+
export const sqliteBlobColumn = () =>
|
|
192
|
+
column(sqliteBlobDescriptor.factory(), sqliteBlobDescriptor.codecId, undefined, 'blob');
|
|
193
|
+
|
|
194
|
+
sqliteBlobColumn satisfies ColumnHelperFor<SqliteBlobDescriptor>;
|
|
195
|
+
sqliteBlobColumn satisfies ColumnHelperForStrict<SqliteBlobDescriptor>;
|
|
196
|
+
|
|
197
|
+
export class SqliteDatetimeCodec extends CodecImpl<
|
|
198
|
+
typeof SQLITE_DATETIME_CODEC_ID,
|
|
199
|
+
readonly ['equality', 'order'],
|
|
200
|
+
string,
|
|
201
|
+
Date
|
|
202
|
+
> {
|
|
203
|
+
// Reject `Invalid Date` (NaN-time) at every decode ingress so consumers never receive a Date object whose downstream operations silently produce NaN. Mirrors the stricter ISO-8601 validation on the postgres timestamp helpers.
|
|
204
|
+
private parseDate(value: string): Date {
|
|
205
|
+
const date = new Date(value);
|
|
206
|
+
if (Number.isNaN(date.getTime())) {
|
|
207
|
+
throw new TypeError(`sqlite/datetime@1 value must be a valid ISO-8601 string: ${value}`);
|
|
208
|
+
}
|
|
209
|
+
return date;
|
|
210
|
+
}
|
|
211
|
+
async encode(value: Date, _ctx: CodecCallContext): Promise<string> {
|
|
212
|
+
return value.toISOString();
|
|
213
|
+
}
|
|
214
|
+
async decode(wire: string, _ctx: CodecCallContext): Promise<Date> {
|
|
215
|
+
return this.parseDate(wire);
|
|
216
|
+
}
|
|
217
|
+
encodeJson(value: Date): JsonValue {
|
|
218
|
+
return value.toISOString();
|
|
219
|
+
}
|
|
220
|
+
decodeJson(json: JsonValue): Date {
|
|
221
|
+
if (typeof json !== 'string') {
|
|
222
|
+
throw new TypeError('sqlite/datetime@1 contract value must be an ISO-8601 string');
|
|
223
|
+
}
|
|
224
|
+
return this.parseDate(json);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export class SqliteDatetimeDescriptor extends CodecDescriptorImpl<void> {
|
|
229
|
+
override readonly codecId = SQLITE_DATETIME_CODEC_ID;
|
|
230
|
+
override readonly traits = ['equality', 'order'] as const;
|
|
231
|
+
override readonly targetTypes = ['text'] as const;
|
|
232
|
+
override readonly paramsSchema = voidParamsSchema;
|
|
233
|
+
override factory(): (ctx: CodecInstanceContext) => SqliteDatetimeCodec {
|
|
234
|
+
return () => new SqliteDatetimeCodec(this);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export const sqliteDatetimeDescriptor = new SqliteDatetimeDescriptor();
|
|
239
|
+
|
|
240
|
+
export const sqliteDatetimeColumn = () =>
|
|
241
|
+
column(sqliteDatetimeDescriptor.factory(), sqliteDatetimeDescriptor.codecId, undefined, 'text');
|
|
242
|
+
|
|
243
|
+
sqliteDatetimeColumn satisfies ColumnHelperFor<SqliteDatetimeDescriptor>;
|
|
244
|
+
sqliteDatetimeColumn satisfies ColumnHelperForStrict<SqliteDatetimeDescriptor>;
|
|
245
|
+
|
|
246
|
+
export class SqliteJsonCodec extends CodecImpl<
|
|
247
|
+
typeof SQLITE_JSON_CODEC_ID,
|
|
248
|
+
readonly ['equality'],
|
|
249
|
+
string | JsonValue,
|
|
250
|
+
JsonValue
|
|
251
|
+
> {
|
|
252
|
+
async encode(value: JsonValue, _ctx: CodecCallContext): Promise<string> {
|
|
253
|
+
return JSON.stringify(value);
|
|
254
|
+
}
|
|
255
|
+
async decode(wire: string | JsonValue, _ctx: CodecCallContext): Promise<JsonValue> {
|
|
256
|
+
return typeof wire === 'string' ? (JSON.parse(wire) as JsonValue) : wire;
|
|
257
|
+
}
|
|
258
|
+
encodeJson(value: JsonValue): JsonValue {
|
|
259
|
+
return value;
|
|
260
|
+
}
|
|
261
|
+
decodeJson(json: JsonValue): JsonValue {
|
|
262
|
+
return json;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export class SqliteJsonDescriptor extends CodecDescriptorImpl<void> {
|
|
267
|
+
override readonly codecId = SQLITE_JSON_CODEC_ID;
|
|
268
|
+
override readonly traits = ['equality'] as const;
|
|
269
|
+
override readonly targetTypes = ['text'] as const;
|
|
270
|
+
override readonly paramsSchema = voidParamsSchema;
|
|
271
|
+
override factory(): (ctx: CodecInstanceContext) => SqliteJsonCodec {
|
|
272
|
+
return () => new SqliteJsonCodec(this);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export const sqliteJsonDescriptor = new SqliteJsonDescriptor();
|
|
277
|
+
|
|
278
|
+
export const sqliteJsonColumn = () =>
|
|
279
|
+
column(sqliteJsonDescriptor.factory(), sqliteJsonDescriptor.codecId, undefined, 'text');
|
|
280
|
+
|
|
281
|
+
sqliteJsonColumn satisfies ColumnHelperFor<SqliteJsonDescriptor>;
|
|
282
|
+
sqliteJsonColumn satisfies ColumnHelperForStrict<SqliteJsonDescriptor>;
|
|
283
|
+
|
|
284
|
+
export class SqliteBigintCodec extends CodecImpl<
|
|
285
|
+
typeof SQLITE_BIGINT_CODEC_ID,
|
|
286
|
+
readonly ['equality', 'order', 'numeric'],
|
|
287
|
+
number | bigint,
|
|
288
|
+
bigint
|
|
289
|
+
> {
|
|
290
|
+
async encode(value: bigint, _ctx: CodecCallContext): Promise<number | bigint> {
|
|
291
|
+
return value;
|
|
292
|
+
}
|
|
293
|
+
async decode(wire: number | bigint, _ctx: CodecCallContext): Promise<bigint> {
|
|
294
|
+
return BigInt(wire);
|
|
295
|
+
}
|
|
296
|
+
encodeJson(value: bigint): JsonValue {
|
|
297
|
+
return value.toString();
|
|
298
|
+
}
|
|
299
|
+
decodeJson(json: JsonValue): bigint {
|
|
300
|
+
if (typeof json !== 'string' && typeof json !== 'number') {
|
|
301
|
+
throw new TypeError('sqlite/bigint@1 contract value must be a string or number');
|
|
302
|
+
}
|
|
303
|
+
return BigInt(json);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
export class SqliteBigintDescriptor extends CodecDescriptorImpl<void> {
|
|
308
|
+
override readonly codecId = SQLITE_BIGINT_CODEC_ID;
|
|
309
|
+
override readonly traits = ['equality', 'order', 'numeric'] as const;
|
|
310
|
+
override readonly targetTypes = ['integer'] as const;
|
|
311
|
+
override readonly paramsSchema = voidParamsSchema;
|
|
312
|
+
override factory(): (ctx: CodecInstanceContext) => SqliteBigintCodec {
|
|
313
|
+
return () => new SqliteBigintCodec(this);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
export const sqliteBigintDescriptor = new SqliteBigintDescriptor();
|
|
318
|
+
|
|
319
|
+
export const sqliteBigintColumn = () =>
|
|
320
|
+
column(sqliteBigintDescriptor.factory(), sqliteBigintDescriptor.codecId, undefined, 'integer');
|
|
321
|
+
|
|
322
|
+
sqliteBigintColumn satisfies ColumnHelperFor<SqliteBigintDescriptor>;
|
|
323
|
+
sqliteBigintColumn satisfies ColumnHelperForStrict<SqliteBigintDescriptor>;
|
|
324
|
+
|
|
325
|
+
export const codecDescriptors: readonly AnyCodecDescriptor[] = [
|
|
326
|
+
sqlCharDescriptor,
|
|
327
|
+
sqlVarcharDescriptor,
|
|
328
|
+
sqlIntDescriptor,
|
|
329
|
+
sqlFloatDescriptor,
|
|
330
|
+
sqliteTextDescriptor,
|
|
331
|
+
sqliteIntegerDescriptor,
|
|
332
|
+
sqliteRealDescriptor,
|
|
333
|
+
sqliteBlobDescriptor,
|
|
334
|
+
sqliteDatetimeDescriptor,
|
|
335
|
+
sqliteJsonDescriptor,
|
|
336
|
+
sqliteBigintDescriptor,
|
|
337
|
+
];
|
|
@@ -1,18 +1,60 @@
|
|
|
1
|
+
import type { ColumnDefault, Contract } from '@prisma-next/contract/types';
|
|
2
|
+
import type {
|
|
3
|
+
SqlControlFamilyInstance,
|
|
4
|
+
SqlControlTargetDescriptor,
|
|
5
|
+
} from '@prisma-next/family-sql/control';
|
|
6
|
+
import { contractToSchemaIR } from '@prisma-next/family-sql/control';
|
|
1
7
|
import type {
|
|
2
|
-
ControlTargetDescriptor,
|
|
3
8
|
ControlTargetInstance,
|
|
9
|
+
MigrationPlanner,
|
|
10
|
+
MigrationRunner,
|
|
4
11
|
} from '@prisma-next/framework-components/control';
|
|
12
|
+
import type { SqlStorage, StorageColumn } from '@prisma-next/sql-contract/types';
|
|
5
13
|
import { sqliteTargetDescriptorMeta } from './descriptor-meta';
|
|
14
|
+
import { createSqliteMigrationPlanner } from './migrations/planner';
|
|
15
|
+
import { renderDefaultLiteral } from './migrations/planner-ddl-builders';
|
|
16
|
+
import type { SqlitePlanTargetDetails } from './migrations/planner-target-details';
|
|
17
|
+
import { createSqliteMigrationRunner } from './migrations/runner';
|
|
18
|
+
|
|
19
|
+
function sqliteRenderDefault(def: ColumnDefault, _column: StorageColumn): string {
|
|
20
|
+
if (def.kind === 'function') {
|
|
21
|
+
if (def.expression === 'now()') {
|
|
22
|
+
return "datetime('now')";
|
|
23
|
+
}
|
|
24
|
+
return def.expression;
|
|
25
|
+
}
|
|
26
|
+
return renderDefaultLiteral(def.value);
|
|
27
|
+
}
|
|
6
28
|
|
|
7
|
-
const sqliteControlTargetDescriptor:
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
>
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
29
|
+
const sqliteControlTargetDescriptor: SqlControlTargetDescriptor<'sqlite', SqlitePlanTargetDetails> =
|
|
30
|
+
{
|
|
31
|
+
...sqliteTargetDescriptorMeta,
|
|
32
|
+
migrations: {
|
|
33
|
+
createPlanner(_family: SqlControlFamilyInstance): MigrationPlanner<'sql', 'sqlite'> {
|
|
34
|
+
return createSqliteMigrationPlanner();
|
|
35
|
+
},
|
|
36
|
+
createRunner(family) {
|
|
37
|
+
return createSqliteMigrationRunner(family) as MigrationRunner<'sql', 'sqlite'>;
|
|
38
|
+
},
|
|
39
|
+
contractToSchema(contract, _frameworkComponents) {
|
|
40
|
+
return contractToSchemaIR(contract as Contract<SqlStorage> | null, {
|
|
41
|
+
annotationNamespace: 'sqlite',
|
|
42
|
+
renderDefault: sqliteRenderDefault,
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
create(): ControlTargetInstance<'sql', 'sqlite'> {
|
|
47
|
+
return {
|
|
48
|
+
familyId: 'sql',
|
|
49
|
+
targetId: 'sqlite',
|
|
50
|
+
};
|
|
51
|
+
},
|
|
52
|
+
createPlanner(_family: SqlControlFamilyInstance) {
|
|
53
|
+
return createSqliteMigrationPlanner();
|
|
54
|
+
},
|
|
55
|
+
createRunner(family) {
|
|
56
|
+
return createSqliteMigrationRunner(family);
|
|
57
|
+
},
|
|
58
|
+
};
|
|
17
59
|
|
|
18
60
|
export default sqliteControlTargetDescriptor;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalizes SQLite's stored default expressions back into the
|
|
3
|
+
* `ColumnDefault` shape the verifier compares against. Lives target-side
|
|
4
|
+
* (mirroring Postgres's `target-postgres/src/core/default-normalizer.ts`)
|
|
5
|
+
* so both the control adapter (`SqliteControlAdapter.introspect`) and the
|
|
6
|
+
* planner / runner schema-verify path can consume it without
|
|
7
|
+
* `target-sqlite` reaching into `adapter-sqlite`.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { ColumnDefault } from '@prisma-next/contract/types';
|
|
11
|
+
|
|
12
|
+
const NULL_PATTERN = /^NULL$/i;
|
|
13
|
+
const INTEGER_PATTERN = /^-?\d+$/;
|
|
14
|
+
const REAL_PATTERN = /^-?\d+\.\d+(?:[eE][+-]?\d+)?$/;
|
|
15
|
+
const HEX_PATTERN = /^0[xX][\dA-Fa-f]+$/;
|
|
16
|
+
const STRING_LITERAL_PATTERN = /^'((?:[^']|'')*)'$/;
|
|
17
|
+
|
|
18
|
+
function isNumericLiteral(value: string): boolean {
|
|
19
|
+
return INTEGER_PATTERN.test(value) || REAL_PATTERN.test(value) || HEX_PATTERN.test(value);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Strips a single matched wrapping pair of outer parens from `s`. Conservative:
|
|
24
|
+
* only strips when the leading `(` is matched by the trailing `)` (so
|
|
25
|
+
* `(a) + (b)` is returned unchanged). Mirrors SQLite's own
|
|
26
|
+
* `pragma_table_info.dflt_value` normalization for expression defaults, and
|
|
27
|
+
* is shared with the recreate-table postcheck builder so both sides agree
|
|
28
|
+
* on the canonical form.
|
|
29
|
+
*/
|
|
30
|
+
export function stripOuterParens(s: string): string {
|
|
31
|
+
if (!s.startsWith('(') || !s.endsWith(')')) return s;
|
|
32
|
+
let depth = 0;
|
|
33
|
+
for (let i = 0; i < s.length; i++) {
|
|
34
|
+
if (s[i] === '(') depth += 1;
|
|
35
|
+
else if (s[i] === ')') {
|
|
36
|
+
depth -= 1;
|
|
37
|
+
if (depth === 0 && i < s.length - 1) return s;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return s.slice(1, -1);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function parseSqliteDefault(
|
|
44
|
+
rawDefault: string,
|
|
45
|
+
nativeType?: string,
|
|
46
|
+
): ColumnDefault | undefined {
|
|
47
|
+
let trimmed = rawDefault.trim();
|
|
48
|
+
|
|
49
|
+
// Strip outer parentheses that SQLite adds around expressions. Iterate to
|
|
50
|
+
// fixpoint so accidental double-wrapping (e.g. `((expr))`) collapses too.
|
|
51
|
+
while (true) {
|
|
52
|
+
const stripped = stripOuterParens(trimmed).trim();
|
|
53
|
+
if (stripped === trimmed) break;
|
|
54
|
+
trimmed = stripped;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// SQLite has several spellings for "current timestamp" — `CURRENT_TIMESTAMP`
|
|
58
|
+
// (keyword) and `datetime('now')` / `datetime("now")` (function call). The
|
|
59
|
+
// contract authoring side canonicalizes `dbgenerated("CURRENT_TIMESTAMP")`
|
|
60
|
+
// (and friends) to `now()` via `lowerDbgenerated`; mirror that here so a
|
|
61
|
+
// schema produced by either spelling round-trips to the same canonical
|
|
62
|
+
// form for verification.
|
|
63
|
+
const lower = trimmed.toLowerCase();
|
|
64
|
+
if (lower === 'current_timestamp' || lower === "datetime('now')" || lower === 'datetime("now")') {
|
|
65
|
+
return { kind: 'function', expression: 'now()' };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (NULL_PATTERN.test(trimmed)) {
|
|
69
|
+
return { kind: 'literal', value: null };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// SQLite integers are 64-bit, so values outside the JS safe-integer range can't
|
|
73
|
+
// be faithfully represented as `number`. Mirror `parsePostgresDefault`'s bigint
|
|
74
|
+
// handling: parse as JS `number` when safe, fall back to the raw text otherwise.
|
|
75
|
+
if (isNumericLiteral(trimmed)) {
|
|
76
|
+
const num = Number(trimmed);
|
|
77
|
+
if (!Number.isFinite(num)) return undefined;
|
|
78
|
+
if (nativeType?.toLowerCase() === 'integer' && !Number.isSafeInteger(num)) {
|
|
79
|
+
return { kind: 'literal', value: trimmed };
|
|
80
|
+
}
|
|
81
|
+
return { kind: 'literal', value: num };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const stringMatch = trimmed.match(STRING_LITERAL_PATTERN);
|
|
85
|
+
if (stringMatch?.[1] !== undefined) {
|
|
86
|
+
const unescaped = stringMatch[1].replace(/''/g, "'");
|
|
87
|
+
return { kind: 'literal', value: unescaped };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Unrecognized expression — preserve as function
|
|
91
|
+
return { kind: 'function', expression: trimmed };
|
|
92
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { CodecTypes } from '
|
|
1
|
+
import type { CodecTypes } from '../exports/codec-types';
|
|
2
|
+
import { sqliteAuthoringFieldPresets } from './authoring';
|
|
2
3
|
|
|
3
4
|
const sqliteTargetDescriptorMetaBase = {
|
|
4
5
|
kind: 'target',
|
|
@@ -7,6 +8,9 @@ const sqliteTargetDescriptorMetaBase = {
|
|
|
7
8
|
id: 'sqlite',
|
|
8
9
|
version: '0.0.1',
|
|
9
10
|
capabilities: {},
|
|
11
|
+
authoring: {
|
|
12
|
+
field: sqliteAuthoringFieldPresets,
|
|
13
|
+
},
|
|
10
14
|
} as const;
|
|
11
15
|
|
|
12
16
|
export const sqliteTargetDescriptorMeta: typeof sqliteTargetDescriptorMetaBase & {
|