@rindle/sql-client 0.6.4
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/LICENSE +201 -0
- package/README.md +61 -0
- package/dist/client.d.ts +3 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +1116 -0
- package/dist/client.js.map +1 -0
- package/dist/drizzle.d.ts +49 -0
- package/dist/drizzle.d.ts.map +1 -0
- package/dist/drizzle.js +180 -0
- package/dist/drizzle.js.map +1 -0
- package/dist/errors.d.ts +29 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +33 -0
- package/dist/errors.js.map +1 -0
- package/dist/id.d.ts +5 -0
- package/dist/id.d.ts.map +1 -0
- package/dist/id.js +23 -0
- package/dist/id.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +204 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/value.d.ts +8 -0
- package/dist/value.d.ts.map +1 -0
- package/dist/value.js +122 -0
- package/dist/value.js.map +1 -0
- package/package.json +51 -0
- package/src/client.ts +1160 -0
- package/src/drizzle.ts +257 -0
- package/src/errors.ts +51 -0
- package/src/id.ts +25 -0
- package/src/index.ts +48 -0
- package/src/types.ts +234 -0
- package/src/value.ts +112 -0
package/src/value.ts
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { protocolError, valueUnsupported } from "./errors.ts";
|
|
2
|
+
import type { IntMode, SqlArgs, SqlValue, Statement, WireArgs, WireSqlValue, WireStatement } from "./types.ts";
|
|
3
|
+
|
|
4
|
+
const I64_MIN = -(1n << 63n);
|
|
5
|
+
const I64_MAX = (1n << 63n) - 1n;
|
|
6
|
+
const DECIMAL_I64 = /^(?:0|-[1-9][0-9]*|[1-9][0-9]*)$/;
|
|
7
|
+
|
|
8
|
+
function binaryKind(value: unknown): string | null {
|
|
9
|
+
if (typeof ArrayBuffer !== "undefined") {
|
|
10
|
+
if (value instanceof ArrayBuffer) return "ArrayBuffer";
|
|
11
|
+
if (ArrayBuffer.isView(value)) return value?.constructor?.name ?? "binary view";
|
|
12
|
+
}
|
|
13
|
+
if (typeof Blob !== "undefined" && value instanceof Blob) return "Blob";
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function assertI64(value: bigint, source: string): void {
|
|
18
|
+
if (value < I64_MIN || value > I64_MAX) {
|
|
19
|
+
throw valueUnsupported(`${source} is outside SQLite's signed 64-bit integer range`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Encode one public SDK value into the frozen v1 tagged JSON representation. */
|
|
24
|
+
export function encodeSqlValue(value: SqlValue): WireSqlValue {
|
|
25
|
+
if (value === null || typeof value === "string") return value;
|
|
26
|
+
if (typeof value === "boolean") return { $rindle: "i64", value: value ? "1" : "0" };
|
|
27
|
+
if (typeof value === "bigint") {
|
|
28
|
+
assertI64(value, `integer ${value.toString()}`);
|
|
29
|
+
return { $rindle: "i64", value: value.toString() };
|
|
30
|
+
}
|
|
31
|
+
if (typeof value === "number") {
|
|
32
|
+
if (Number.isNaN(value)) throw valueUnsupported("NaN is not a supported SQLite value");
|
|
33
|
+
if (value === Infinity) return { $rindle: "float", value: "Infinity" };
|
|
34
|
+
if (value === -Infinity) return { $rindle: "float", value: "-Infinity" };
|
|
35
|
+
// JavaScript has one number type, but SQLite distinguishes INTEGER and REAL storage classes.
|
|
36
|
+
// Safe integral numbers carry the exact i64 tag; non-integral and larger numeric values remain
|
|
37
|
+
// REALs. Callers that need a larger integer must use bigint so intent and precision are explicit.
|
|
38
|
+
if (Number.isSafeInteger(value)) {
|
|
39
|
+
return { $rindle: "i64", value: BigInt(value).toString() };
|
|
40
|
+
}
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const kind = binaryKind(value);
|
|
45
|
+
if (kind !== null) throw valueUnsupported(`${kind} bind values are not supported in Rindle SQL v1`);
|
|
46
|
+
throw valueUnsupported(`unsupported bind value of type ${typeof value}`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function parseWireI64(decimal: unknown): bigint {
|
|
50
|
+
if (typeof decimal !== "string" || !DECIMAL_I64.test(decimal)) {
|
|
51
|
+
throw protocolError("server returned a malformed tagged i64 value");
|
|
52
|
+
}
|
|
53
|
+
let value: bigint;
|
|
54
|
+
try {
|
|
55
|
+
value = BigInt(decimal);
|
|
56
|
+
} catch (cause) {
|
|
57
|
+
throw protocolError("server returned a malformed tagged i64 value", cause);
|
|
58
|
+
}
|
|
59
|
+
if (value < I64_MIN || value > I64_MAX) {
|
|
60
|
+
throw protocolError("server returned an out-of-range tagged i64 value");
|
|
61
|
+
}
|
|
62
|
+
return value;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Decode one frozen v1 tagged JSON value using the client's integer policy. */
|
|
66
|
+
export function decodeSqlValue(value: unknown, intMode: IntMode = "bigint"): SqlValue {
|
|
67
|
+
if (value === null || typeof value === "string") return value;
|
|
68
|
+
if (typeof value === "number") {
|
|
69
|
+
if (!Number.isFinite(value)) throw protocolError("server returned a non-finite untagged JSON number");
|
|
70
|
+
return value;
|
|
71
|
+
}
|
|
72
|
+
if (typeof value !== "object" || Array.isArray(value)) {
|
|
73
|
+
throw protocolError("server returned a malformed SQL value");
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const tagged = value as { $rindle?: unknown; value?: unknown };
|
|
77
|
+
if (tagged.$rindle === "float") {
|
|
78
|
+
if (tagged.value === "Infinity") return Infinity;
|
|
79
|
+
if (tagged.value === "-Infinity") return -Infinity;
|
|
80
|
+
throw protocolError("server returned a malformed tagged float value");
|
|
81
|
+
}
|
|
82
|
+
if (tagged.$rindle !== "i64") throw protocolError("server returned an unknown tagged SQL value");
|
|
83
|
+
|
|
84
|
+
const integer = parseWireI64(tagged.value);
|
|
85
|
+
if (intMode === "bigint") return integer;
|
|
86
|
+
if (intMode === "string") return integer.toString();
|
|
87
|
+
const number = Number(integer);
|
|
88
|
+
if (!Number.isSafeInteger(number)) {
|
|
89
|
+
throw valueUnsupported(`integer ${integer.toString()} is outside Number's safe integer range`);
|
|
90
|
+
}
|
|
91
|
+
return number;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function encodeArgs(args: SqlArgs): WireArgs {
|
|
95
|
+
if (Array.isArray(args)) return args.map((value) => encodeSqlValue(value));
|
|
96
|
+
if (args === null || typeof args !== "object") {
|
|
97
|
+
throw valueUnsupported("statement args must be a positional array or named object");
|
|
98
|
+
}
|
|
99
|
+
return Object.fromEntries(Object.entries(args).map(([name, value]) => [name, encodeSqlValue(value)]));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function encodeStatement(statement: Statement | string): WireStatement {
|
|
103
|
+
const normalized: Statement = typeof statement === "string" ? { sql: statement } : statement;
|
|
104
|
+
if (normalized === null || typeof normalized !== "object" || typeof normalized.sql !== "string") {
|
|
105
|
+
throw new TypeError("statement must be a SQL string or an object with a string sql field");
|
|
106
|
+
}
|
|
107
|
+
if (normalized.sql.length === 0) throw new TypeError("statement sql must not be empty");
|
|
108
|
+
const wire: WireStatement = { sql: normalized.sql };
|
|
109
|
+
if (normalized.args !== undefined) wire.args = encodeArgs(normalized.args);
|
|
110
|
+
if (normalized.wantRows !== undefined) wire.want_rows = normalized.wantRows;
|
|
111
|
+
return wire;
|
|
112
|
+
}
|