@evolu/common 8.6.1 → 8.7.0
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/src/Buffer.d.ts +67 -8
- package/dist/src/Buffer.d.ts.map +1 -1
- package/dist/src/Buffer.js +722 -15
- package/dist/src/Sqlite.d.ts +23 -9
- package/dist/src/Sqlite.d.ts.map +1 -1
- package/dist/src/Sqlite.js +14 -9
- package/dist/src/local-first/Db.d.ts.map +1 -1
- package/dist/src/local-first/Db.js +1 -0
- package/dist/src/local-first/Protocol.d.ts +19 -5
- package/dist/src/local-first/Protocol.d.ts.map +1 -1
- package/dist/src/local-first/Protocol.js +28 -35
- package/dist/src/local-first/Query.d.ts +2 -3
- package/dist/src/local-first/Query.d.ts.map +1 -1
- package/dist/src/local-first/Query.js +1 -1
- package/dist/src/local-first/Schema.d.ts +15 -1
- package/dist/src/local-first/Schema.d.ts.map +1 -1
- package/dist/src/local-first/Schema.js +3 -2
- package/dist/src/local-first/Storage.d.ts +2 -2
- package/dist/src/local-first/Storage.d.ts.map +1 -1
- package/package.json +1 -2
- package/src/Buffer.ts +966 -22
- package/src/Sqlite.ts +34 -16
- package/src/local-first/Db.ts +3 -1
- package/src/local-first/Protocol.ts +30 -42
- package/src/local-first/Query.ts +5 -5
- package/src/local-first/Schema.ts +22 -7
package/src/Sqlite.ts
CHANGED
|
@@ -8,19 +8,19 @@ import type { Brand } from "./Brand.ts";
|
|
|
8
8
|
import { bytesToHex, hexToBytes } from "./Buffer.ts";
|
|
9
9
|
import type { EncryptionKey } from "./Crypto.ts";
|
|
10
10
|
import type { Eq } from "./Eq.ts";
|
|
11
|
-
import { createEqObject,
|
|
11
|
+
import { createEqObject, eqString, eqUint8Array } from "./Eq.ts";
|
|
12
12
|
import { disposable } from "./Function.ts";
|
|
13
13
|
import { createMutableRecord, objectToEntries } from "./Object.ts";
|
|
14
14
|
import type { Result } from "./Result.ts";
|
|
15
15
|
import { ok } from "./Result.ts";
|
|
16
|
-
import {
|
|
16
|
+
import { type Task, testCreateRun, type TestRunDep } from "./Task.ts";
|
|
17
17
|
import {
|
|
18
18
|
array,
|
|
19
19
|
type ArrayType,
|
|
20
|
+
FiniteNumber,
|
|
20
21
|
type InferType,
|
|
21
22
|
type Name,
|
|
22
23
|
Null,
|
|
23
|
-
Number,
|
|
24
24
|
object,
|
|
25
25
|
type ObjectType,
|
|
26
26
|
record,
|
|
@@ -79,7 +79,7 @@ export interface SqliteTransaction {
|
|
|
79
79
|
/** Represents a SQL query to be executed on a {@link Sqlite} database. */
|
|
80
80
|
export interface SqliteQuery {
|
|
81
81
|
readonly sql: SafeSql;
|
|
82
|
-
readonly parameters:
|
|
82
|
+
readonly parameters: SqliteQueryParameters;
|
|
83
83
|
readonly options?: SqliteQueryOptions;
|
|
84
84
|
}
|
|
85
85
|
|
|
@@ -92,20 +92,38 @@ export type SafeSql = string & Brand<"SafeSql">;
|
|
|
92
92
|
/**
|
|
93
93
|
* A value that can be stored in {@link Sqlite}.
|
|
94
94
|
*
|
|
95
|
+
* Numeric values use {@link FiniteNumber} because JavaScript numbers also
|
|
96
|
+
* include `NaN` and infinities. SQLite binds `NaN` as `NULL`, while JSON
|
|
97
|
+
* serialization converts all non-finite numbers to `null`. Restricting numbers
|
|
98
|
+
* to finite values preserves them across storage and query serialization.
|
|
99
|
+
*
|
|
95
100
|
* Note that Evolu can't support Int64 because expo-sqlite (and some others) do
|
|
96
101
|
* not support it.
|
|
97
102
|
*/
|
|
98
103
|
export const SqliteValue = /*#__PURE__*/ union(
|
|
104
|
+
FiniteNumber,
|
|
99
105
|
Null,
|
|
100
106
|
String,
|
|
101
|
-
Number,
|
|
102
107
|
Uint8Array,
|
|
103
108
|
);
|
|
104
109
|
export type SqliteValue = typeof SqliteValue.Output;
|
|
105
110
|
|
|
106
|
-
/**
|
|
107
|
-
export const
|
|
108
|
-
|
|
111
|
+
/** Parameters of a {@link SqliteQuery}. */
|
|
112
|
+
export const SqliteQueryParameters = /*#__PURE__*/ array(SqliteValue);
|
|
113
|
+
export type SqliteQueryParameters = typeof SqliteQueryParameters.Output;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* A value used in {@link sql} template parameters and {@link Sqlite} query
|
|
117
|
+
* results.
|
|
118
|
+
*
|
|
119
|
+
* It differs from {@link SqliteValue} only by using `number` instead of
|
|
120
|
+
* {@link FiniteNumber}.
|
|
121
|
+
*/
|
|
122
|
+
export type SqliteValueInput = typeof SqliteValue.Input;
|
|
123
|
+
|
|
124
|
+
/** Equality comparison for {@link SqliteValueInput}. */
|
|
125
|
+
export const eqSqliteValue: Eq<SqliteValueInput> = (x, y) =>
|
|
126
|
+
Uint8Array.is(x) && Uint8Array.is(y) ? eqUint8Array(x, y) : x === y;
|
|
109
127
|
|
|
110
128
|
/** Options for configuring {@link SqliteQuery} execution behavior. */
|
|
111
129
|
export interface SqliteQueryOptions {
|
|
@@ -139,7 +157,7 @@ export const sqliteQueryToSqliteQueryString = (
|
|
|
139
157
|
query: SqliteQuery,
|
|
140
158
|
): SqliteQueryString => {
|
|
141
159
|
const params = query.parameters.map((value) =>
|
|
142
|
-
value
|
|
160
|
+
Uint8Array.is(value)
|
|
143
161
|
? (["b", bytesToHex(value)] as const)
|
|
144
162
|
: (["j", value] as const),
|
|
145
163
|
);
|
|
@@ -157,7 +175,9 @@ export const sqliteQueryStringToSqliteQuery = (
|
|
|
157
175
|
): SqliteQuery => {
|
|
158
176
|
const [sql, paramsArr, optionsArr] = JSON.parse(query) as [
|
|
159
177
|
SafeSql,
|
|
160
|
-
Array<
|
|
178
|
+
Array<
|
|
179
|
+
readonly ["b", string] | readonly ["j", string | FiniteNumber | null]
|
|
180
|
+
>,
|
|
161
181
|
Array<Array<string | number | null>>,
|
|
162
182
|
];
|
|
163
183
|
|
|
@@ -184,9 +204,9 @@ export interface SqliteExecResult<R extends SqliteRow = SqliteRow> {
|
|
|
184
204
|
|
|
185
205
|
/**
|
|
186
206
|
* A row returned from a {@link Sqlite} query, mapping column names to
|
|
187
|
-
* {@link
|
|
207
|
+
* {@link SqliteValueInput}.
|
|
188
208
|
*/
|
|
189
|
-
export type SqliteRow = Record<string,
|
|
209
|
+
export type SqliteRow = Record<string, SqliteValueInput>;
|
|
190
210
|
|
|
191
211
|
/**
|
|
192
212
|
* SQLite driver interface.
|
|
@@ -423,7 +443,7 @@ export interface RawSql extends Typed<"RawSql"> {
|
|
|
423
443
|
}
|
|
424
444
|
|
|
425
445
|
/** A parameter accepted by the {@link sql} tagged template. */
|
|
426
|
-
export type SqlTemplateParam =
|
|
446
|
+
export type SqlTemplateParam = SqliteValueInput | SqlIdentifier | RawSql;
|
|
427
447
|
|
|
428
448
|
/**
|
|
429
449
|
* Creates a safe SQL query using a tagged template literal.
|
|
@@ -484,7 +504,7 @@ export const sql = (
|
|
|
484
504
|
sql += param.sql;
|
|
485
505
|
} else {
|
|
486
506
|
sql += "?";
|
|
487
|
-
values.push(param);
|
|
507
|
+
values.push(SqliteValue.orThrow(param));
|
|
488
508
|
}
|
|
489
509
|
}
|
|
490
510
|
}
|
|
@@ -647,8 +667,6 @@ export const getSqliteSnapshot = (deps: SqliteDep): SqliteSnapshot => {
|
|
|
647
667
|
*
|
|
648
668
|
* See: https://www.sqlite.org/quirks.html#no_separate_boolean_datatype
|
|
649
669
|
*
|
|
650
|
-
* ## Tips
|
|
651
|
-
*
|
|
652
670
|
* - Use {@link sqliteTrue} and {@link sqliteFalse} constants for better
|
|
653
671
|
* readability.
|
|
654
672
|
* - Use {@link booleanToSqliteBoolean} and {@link sqliteBooleanToBoolean} for
|
package/src/local-first/Db.ts
CHANGED
|
@@ -45,6 +45,7 @@ import { callback, type Run, type Task } from "../Task.ts";
|
|
|
45
45
|
import { Millis, millisToDateIso, type TimeDep } from "../Time.ts";
|
|
46
46
|
import {
|
|
47
47
|
assertType,
|
|
48
|
+
type FiniteNumber,
|
|
48
49
|
Id,
|
|
49
50
|
IdBytes,
|
|
50
51
|
idBytesToId,
|
|
@@ -942,7 +943,8 @@ const dbChangeToColumns = (change: DbChange, now: Millis) => {
|
|
|
942
943
|
if (change.isDelete != null) {
|
|
943
944
|
values = appendToArray(values, [
|
|
944
945
|
"isDeleted",
|
|
945
|
-
|
|
946
|
+
// SQLite boolean values are fixed to the finite numbers 0 and 1.
|
|
947
|
+
booleanToSqliteBoolean(change.isDelete) as FiniteNumber,
|
|
946
948
|
]);
|
|
947
949
|
}
|
|
948
950
|
|
|
@@ -170,14 +170,11 @@
|
|
|
170
170
|
* initiator/non-initiator terminology instead, and consolidate into a single
|
|
171
171
|
* `applyProtocolMessage` function with conditional arguments to reduce code
|
|
172
172
|
* duplication.
|
|
173
|
-
* - Replace try-catch with Result + new Error (to preserve stacktraces). Measure
|
|
174
|
-
* Result overhead, it should be super small.
|
|
175
173
|
* - Allow clients to broadcast messages that are not persisted by relays. This
|
|
176
174
|
* would enable real-time ephemeral data (like cursor positions, typing
|
|
177
175
|
* indicators) to be forwarded by relays without storage overhead.
|
|
178
176
|
*/
|
|
179
177
|
|
|
180
|
-
import { Packr } from "msgpackr";
|
|
181
178
|
import {
|
|
182
179
|
createMutableArray,
|
|
183
180
|
isNonEmptyArray,
|
|
@@ -190,6 +187,8 @@ import {
|
|
|
190
187
|
bytesToHex,
|
|
191
188
|
bytesToUtf8,
|
|
192
189
|
createBuffer,
|
|
190
|
+
decodeJsonValue,
|
|
191
|
+
encodeJsonValue,
|
|
193
192
|
hexToBytes,
|
|
194
193
|
utf8ToBytes,
|
|
195
194
|
} from "../Buffer.ts";
|
|
@@ -217,6 +216,7 @@ import {
|
|
|
217
216
|
base64UrlToUint8Array,
|
|
218
217
|
between,
|
|
219
218
|
DateIso,
|
|
219
|
+
FiniteNumber,
|
|
220
220
|
Id,
|
|
221
221
|
IdBytes,
|
|
222
222
|
idBytesToId,
|
|
@@ -226,7 +226,6 @@ import {
|
|
|
226
226
|
Json,
|
|
227
227
|
jsonToJsonValue,
|
|
228
228
|
NonNegativeInt,
|
|
229
|
-
Number,
|
|
230
229
|
onePositiveInt,
|
|
231
230
|
PositiveInt,
|
|
232
231
|
type Typed,
|
|
@@ -271,13 +270,7 @@ import {
|
|
|
271
270
|
timestampToTimestampBytes,
|
|
272
271
|
} from "./Timestamp.ts";
|
|
273
272
|
|
|
274
|
-
|
|
275
|
-
* Evolu uses MessagePack for numbers and JSONs.
|
|
276
|
-
*
|
|
277
|
-
* - `variableMapSize: true` - More compact maps, ~5-10% slower encoding
|
|
278
|
-
* - `useRecords: false` - Standard MessagePack without extensions
|
|
279
|
-
*/
|
|
280
|
-
const packr = new Packr({ variableMapSize: true, useRecords: false });
|
|
273
|
+
const jsonBuffer = createBuffer();
|
|
281
274
|
|
|
282
275
|
const minProtocolMessageMaxSize = 1_000_000;
|
|
283
276
|
const maxProtocolMessageMaxSize = 100_000_000;
|
|
@@ -1775,33 +1768,16 @@ const decodeId = (buffer: Buffer): Id => {
|
|
|
1775
1768
|
};
|
|
1776
1769
|
|
|
1777
1770
|
/**
|
|
1778
|
-
* Evolu uses MessagePack to handle
|
|
1779
|
-
*
|
|
1771
|
+
* Evolu uses MessagePack to handle finite numbers except for NonNegativeInt.
|
|
1772
|
+
* For NonNegativeInt, Evolu provides more efficient encoding.
|
|
1780
1773
|
*/
|
|
1781
|
-
export const encodeNumber = (buffer: Buffer, number:
|
|
1782
|
-
buffer
|
|
1774
|
+
export const encodeNumber = (buffer: Buffer, number: FiniteNumber): void => {
|
|
1775
|
+
encodeJsonValue(buffer, number);
|
|
1783
1776
|
};
|
|
1784
1777
|
|
|
1785
|
-
export const decodeNumber = (buffer: Buffer):
|
|
1786
|
-
|
|
1787
|
-
let end: unknown;
|
|
1788
|
-
|
|
1789
|
-
packr.unpackMultiple(
|
|
1790
|
-
buffer.unwrap(),
|
|
1791
|
-
(n: unknown, _: unknown, e: unknown) => {
|
|
1792
|
-
number = n;
|
|
1793
|
-
end = e;
|
|
1794
|
-
return false;
|
|
1795
|
-
},
|
|
1796
|
-
);
|
|
1797
|
-
|
|
1798
|
-
const endResult = NonNegativeInt.fromUnknown(end);
|
|
1799
|
-
if (!endResult.ok) throw new ProtocolDecodeError(endResult.error.type);
|
|
1800
|
-
|
|
1801
|
-
const numberResult = Number.fromUnknown(number);
|
|
1778
|
+
export const decodeNumber = (buffer: Buffer): FiniteNumber => {
|
|
1779
|
+
const numberResult = FiniteNumber.fromUnknown(decodeJsonValue(buffer));
|
|
1802
1780
|
if (!numberResult.ok) throw new ProtocolDecodeError(numberResult.error.type);
|
|
1803
|
-
|
|
1804
|
-
buffer.shiftN(endResult.value);
|
|
1805
1781
|
return numberResult.value;
|
|
1806
1782
|
};
|
|
1807
1783
|
|
|
@@ -2140,7 +2116,7 @@ export const encodeSqliteValue = (buffer: Buffer, value: SqliteValue): void => {
|
|
|
2140
2116
|
buffer,
|
|
2141
2117
|
ProtocolValueType.DateIsoWithNegativeTime,
|
|
2142
2118
|
);
|
|
2143
|
-
encodeNumber(buffer, time);
|
|
2119
|
+
encodeNumber(buffer, FiniteNumber.orThrow(time));
|
|
2144
2120
|
}
|
|
2145
2121
|
return;
|
|
2146
2122
|
}
|
|
@@ -2157,10 +2133,16 @@ export const encodeSqliteValue = (buffer: Buffer, value: SqliteValue): void => {
|
|
|
2157
2133
|
// Some valid JSON strings like "-0E0" get normalized to "0" during parsing,
|
|
2158
2134
|
// which would cause data corruption if we don't verify round-trip safety.
|
|
2159
2135
|
if (json.ok && JSON.stringify(jsonToJsonValue(json.value)) === value) {
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2136
|
+
jsonBuffer.reset();
|
|
2137
|
+
try {
|
|
2138
|
+
encodeJsonValue(jsonBuffer, jsonToJsonValue(json.value));
|
|
2139
|
+
const jsonBytes = jsonBuffer.unwrap();
|
|
2140
|
+
encodeNonNegativeInt(buffer, ProtocolValueType.Json);
|
|
2141
|
+
encodeLength(buffer, jsonBytes);
|
|
2142
|
+
buffer.extend(jsonBytes);
|
|
2143
|
+
} finally {
|
|
2144
|
+
jsonBuffer.reset();
|
|
2145
|
+
}
|
|
2164
2146
|
return;
|
|
2165
2147
|
}
|
|
2166
2148
|
|
|
@@ -2179,7 +2161,9 @@ export const encodeSqliteValue = (buffer: Buffer, value: SqliteValue): void => {
|
|
|
2179
2161
|
}
|
|
2180
2162
|
|
|
2181
2163
|
case "number": {
|
|
2182
|
-
|
|
2164
|
+
// Negative zero is a non-negative integer in JavaScript, but integer
|
|
2165
|
+
// encoding would lose its observable sign.
|
|
2166
|
+
if (!globalThis.Object.is(value, -0) && NonNegativeInt.is(value)) {
|
|
2183
2167
|
if (isSmallInt(value)) {
|
|
2184
2168
|
encodeNonNegativeInt(buffer, value);
|
|
2185
2169
|
return;
|
|
@@ -2229,8 +2213,12 @@ export const decodeSqliteValue = (buffer: Buffer): SqliteValue => {
|
|
|
2229
2213
|
|
|
2230
2214
|
case ProtocolValueType.Json: {
|
|
2231
2215
|
const length = decodeLength(buffer);
|
|
2232
|
-
const
|
|
2233
|
-
|
|
2216
|
+
const lengthBeforeDecoding = buffer.getLength();
|
|
2217
|
+
const value = decodeJsonValue(buffer);
|
|
2218
|
+
if (lengthBeforeDecoding - buffer.getLength() !== length) {
|
|
2219
|
+
throw new ProtocolDecodeError("Invalid JSON MessagePack length");
|
|
2220
|
+
}
|
|
2221
|
+
return JSON.stringify(value);
|
|
2234
2222
|
}
|
|
2235
2223
|
|
|
2236
2224
|
case ProtocolValueType.DateIsoWithNonNegativeTime:
|
package/src/local-first/Query.ts
CHANGED
|
@@ -26,8 +26,8 @@ import type { Brand } from "../Brand.ts";
|
|
|
26
26
|
import { createRandomBytes } from "../Crypto.ts";
|
|
27
27
|
import type { ReadonlyRecord } from "../Object.ts";
|
|
28
28
|
import { createMutableRecord, isPlainObject } from "../Object.ts";
|
|
29
|
-
import type { SqliteQueryString } from "../Sqlite.ts";
|
|
30
|
-
import { eqSqliteValue
|
|
29
|
+
import type { SqliteQueryString, SqliteValueInput } from "../Sqlite.ts";
|
|
30
|
+
import { eqSqliteValue } from "../Sqlite.ts";
|
|
31
31
|
import { createId, String } from "../Type.ts";
|
|
32
32
|
import type { EvoluSchema } from "./Schema.ts";
|
|
33
33
|
|
|
@@ -107,7 +107,7 @@ export type InferRow<T extends Query> =
|
|
|
107
107
|
|
|
108
108
|
export interface Row {
|
|
109
109
|
readonly [key: string]:
|
|
110
|
-
|
|
|
110
|
+
| SqliteValueInput
|
|
111
111
|
// for evoluJsonObjectFrom
|
|
112
112
|
| Row
|
|
113
113
|
// for evoluJsonArrayFrom
|
|
@@ -400,8 +400,8 @@ export const makePatches = (
|
|
|
400
400
|
for (const key in previousRow)
|
|
401
401
|
if (
|
|
402
402
|
!eqSqliteValue(
|
|
403
|
-
previousRow[key] as
|
|
404
|
-
nextRow[key] as
|
|
403
|
+
previousRow[key] as SqliteValueInput,
|
|
404
|
+
nextRow[key] as SqliteValueInput,
|
|
405
405
|
)
|
|
406
406
|
) {
|
|
407
407
|
replaceAtPatches.push({ op: "replaceAt", value: nextRow, index: i });
|
|
@@ -19,11 +19,14 @@ import {
|
|
|
19
19
|
type SqliteIndex,
|
|
20
20
|
type SqliteQuery,
|
|
21
21
|
type SqliteQueryOptions,
|
|
22
|
+
SqliteQueryParameters,
|
|
22
23
|
type SqliteSchema,
|
|
23
24
|
SqliteValue,
|
|
24
25
|
} from "../Sqlite.ts";
|
|
25
26
|
import {
|
|
27
|
+
assertType,
|
|
26
28
|
DateIso,
|
|
29
|
+
type FiniteNumber,
|
|
27
30
|
type Id,
|
|
28
31
|
IdBytes,
|
|
29
32
|
type InferType,
|
|
@@ -54,6 +57,11 @@ export type AnyStandardSchemaV1 = StandardSchemaV1<any, any>;
|
|
|
54
57
|
* Column types are Standard Schema v1 compatible — use Evolu Type, Zod,
|
|
55
58
|
* Valibot, ArkType, or any library that implements Standard Schema.
|
|
56
59
|
*
|
|
60
|
+
* Each column schema's inferred output must be compatible with SQLite. Numeric
|
|
61
|
+
* outputs must be assignable to {@link FiniteNumber}. Standard Schema does not
|
|
62
|
+
* standardize nominal brands, so a library-specific finite validator whose
|
|
63
|
+
* output remains `number` must brand its validated output compatibly.
|
|
64
|
+
*
|
|
57
65
|
* Table schema defines columns that are required for table rows. For optional
|
|
58
66
|
* columns, use a schema whose output type includes `null`.
|
|
59
67
|
*
|
|
@@ -63,7 +71,9 @@ export type AnyStandardSchemaV1 = StandardSchemaV1<any, any>;
|
|
|
63
71
|
* import * as z from "zod";
|
|
64
72
|
* import {
|
|
65
73
|
* assertOk,
|
|
74
|
+
* assertType,
|
|
66
75
|
* assertTrue,
|
|
76
|
+
* type FiniteNumber,
|
|
67
77
|
* id,
|
|
68
78
|
* NonEmptyTrimmedString100,
|
|
69
79
|
* nullOr,
|
|
@@ -84,10 +94,17 @@ export type AnyStandardSchemaV1 = StandardSchemaV1<any, any>;
|
|
|
84
94
|
* assertOk(Schema.todo.title.fromUnknown("Write docs"), "Write docs");
|
|
85
95
|
*
|
|
86
96
|
* // Zod, or another Standard Schema library
|
|
97
|
+
* // Zod 4 numbers are finite by default; Evolu Type Number models all JavaScript numbers.
|
|
98
|
+
* const ZodFiniteNumber = z
|
|
99
|
+
* .number()
|
|
100
|
+
* .transform((value): FiniteNumber => value as FiniteNumber);
|
|
101
|
+
* assertType<FiniteNumber, z.output<typeof ZodFiniteNumber>>();
|
|
102
|
+
*
|
|
87
103
|
* const ZodSchema = {
|
|
88
104
|
* todo: {
|
|
89
105
|
* id: TodoId,
|
|
90
106
|
* title: z.string().min(1).max(100),
|
|
107
|
+
* position: ZodFiniteNumber,
|
|
91
108
|
* isCompleted: z.union([z.literal(0), z.literal(1)]).nullable(),
|
|
92
109
|
* },
|
|
93
110
|
* };
|
|
@@ -377,11 +394,10 @@ export type ValidateColumnTypes<S extends EvoluSchema> =
|
|
|
377
394
|
? TableName extends keyof S
|
|
378
395
|
? keyof S[TableName] extends infer ColumnName
|
|
379
396
|
? ColumnName extends keyof S[TableName]
|
|
380
|
-
? StandardSchemaV1.InferOutput<
|
|
381
|
-
|
|
382
|
-
> extends SqliteValue
|
|
397
|
+
? StandardSchemaV1.InferOutput<S[TableName][ColumnName]> extends
|
|
398
|
+
SqliteValue | SqliteBoolean
|
|
383
399
|
? never
|
|
384
|
-
: SchemaValidationError<`Table "${TableName & string}" column "${ColumnName & string}" type is not compatible with SQLite. Column types must extend SqliteValue (string,
|
|
400
|
+
: SchemaValidationError<`Table "${TableName & string}" column "${ColumnName & string}" type is not compatible with SQLite. Column types must extend SqliteValue (string, FiniteNumber, Uint8Array, or null).`>
|
|
385
401
|
: never
|
|
386
402
|
: never
|
|
387
403
|
: never
|
|
@@ -492,11 +508,10 @@ export const createQueryBuilder = <S extends EvoluSchema>(
|
|
|
492
508
|
): CreateQuery<S> => {
|
|
493
509
|
const createQuery: CreateQuery<S> = (queryCallback, options) => {
|
|
494
510
|
const compiledQuery = queryCallback(kysely as never).compile();
|
|
511
|
+
assertType(SqliteQueryParameters, compiledQuery.parameters);
|
|
495
512
|
const sqliteQuery: SqliteQuery = {
|
|
496
513
|
sql: compiledQuery.sql as SafeSql,
|
|
497
|
-
parameters: compiledQuery.parameters
|
|
498
|
-
SqliteQuery["parameters"]
|
|
499
|
-
>,
|
|
514
|
+
parameters: compiledQuery.parameters,
|
|
500
515
|
...(options && { options }),
|
|
501
516
|
};
|
|
502
517
|
|