@remit/drizzle-sqlite-schema 0.0.34 → 0.0.36
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/schema.d.ts +338 -387
- package/dist/schema.js +29 -30
- package/dist/types.d.ts +81 -1
- package/dist/types.js +136 -6
- package/package.json +1 -4
- package/schema.ts +36 -40
- package/types.ts +150 -6
package/types.ts
CHANGED
|
@@ -1,20 +1,156 @@
|
|
|
1
1
|
import { customType } from "drizzle-orm/sqlite-core";
|
|
2
|
-
import short from "short-uuid";
|
|
3
2
|
|
|
4
|
-
const
|
|
3
|
+
const base36Digits = "0123456789abcdefghijklmnopqrstuvwxyz";
|
|
4
|
+
const hexDigits = "0123456789abcdef";
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
const base36Values = ((): Int8Array => {
|
|
7
|
+
const table = new Int8Array(128).fill(-1);
|
|
8
|
+
for (let i = 0; i < base36Digits.length; i += 1) table[base36Digits.charCodeAt(i)] = i;
|
|
9
|
+
return table;
|
|
10
|
+
})();
|
|
11
|
+
|
|
12
|
+
const hexValues = ((): Int8Array => {
|
|
13
|
+
const table = new Int8Array(128).fill(-1);
|
|
14
|
+
for (let i = 0; i < hexDigits.length; i += 1) {
|
|
15
|
+
table[hexDigits.charCodeAt(i)] = i;
|
|
16
|
+
table[hexDigits.toUpperCase().charCodeAt(i)] = i;
|
|
17
|
+
}
|
|
18
|
+
return table;
|
|
19
|
+
})();
|
|
20
|
+
|
|
21
|
+
const hexOctets = ((): string[] => {
|
|
22
|
+
const table: string[] = [];
|
|
23
|
+
for (let i = 0; i < 256; i += 1) table.push(i.toString(16).padStart(2, "0"));
|
|
24
|
+
return table;
|
|
25
|
+
})();
|
|
26
|
+
|
|
27
|
+
const base36Scales = [1, 36, 1296, 46656, 1679616, 60466176];
|
|
28
|
+
|
|
29
|
+
function readBase36(id: string, start: number, count: number): number {
|
|
30
|
+
let value = 0;
|
|
31
|
+
for (let i = start; i < start + count; i += 1) {
|
|
32
|
+
const code = id.charCodeAt(i);
|
|
33
|
+
const digit = code < 128 ? base36Values[code] : -1;
|
|
34
|
+
if (digit < 0) throw new Error(`Not a base36 uuid: ${id}`);
|
|
35
|
+
value = value * 36 + digit;
|
|
36
|
+
}
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function scaleAndAdd(limbs: Uint32Array, scale: number, addend: number): number {
|
|
41
|
+
let carry = addend;
|
|
42
|
+
for (let i = 7; i >= 0; i -= 1) {
|
|
43
|
+
const product = limbs[i] * scale + carry;
|
|
44
|
+
const low = product % 65536;
|
|
45
|
+
limbs[i] = low;
|
|
46
|
+
carry = (product - low) / 65536;
|
|
47
|
+
}
|
|
48
|
+
return carry;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function base36ToBytes(id: string): Uint8Array {
|
|
52
|
+
if (id.length === 0 || id.length > 25) throw new Error(`Not a base36 uuid: ${id}`);
|
|
53
|
+
const limbs = new Uint32Array(8);
|
|
54
|
+
const head = id.length % 5;
|
|
55
|
+
if (head > 0 && scaleAndAdd(limbs, base36Scales[head], readBase36(id, 0, head)) !== 0) {
|
|
56
|
+
throw new Error(`base36 uuid does not fit in 128 bits: ${id}`);
|
|
57
|
+
}
|
|
58
|
+
for (let cursor = head; cursor < id.length; cursor += 5) {
|
|
59
|
+
if (scaleAndAdd(limbs, 60466176, readBase36(id, cursor, 5)) !== 0) {
|
|
60
|
+
throw new Error(`base36 uuid does not fit in 128 bits: ${id}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const bytes = new Uint8Array(16);
|
|
64
|
+
for (let i = 0; i < 8; i += 1) {
|
|
65
|
+
bytes[i * 2] = limbs[i] >>> 8;
|
|
66
|
+
bytes[i * 2 + 1] = limbs[i] & 0xff;
|
|
67
|
+
}
|
|
68
|
+
return bytes;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function bytesToBase36(bytes: Uint8Array): string {
|
|
72
|
+
if (bytes.length !== 16) throw new Error(`Not a 16-byte uuid: ${bytes.length} bytes`);
|
|
73
|
+
const limbs = new Uint32Array(8);
|
|
74
|
+
for (let i = 0; i < 8; i += 1) limbs[i] = (bytes[i * 2] << 8) | bytes[i * 2 + 1];
|
|
75
|
+
let id = "";
|
|
76
|
+
for (let chunk = 0; chunk < 5; chunk += 1) {
|
|
77
|
+
let remainder = 0;
|
|
78
|
+
for (let i = 0; i < 8; i += 1) {
|
|
79
|
+
const current = remainder * 65536 + limbs[i];
|
|
80
|
+
const quotient = Math.floor(current / 60466176);
|
|
81
|
+
limbs[i] = quotient;
|
|
82
|
+
remainder = current - quotient * 60466176;
|
|
83
|
+
}
|
|
84
|
+
let piece = "";
|
|
85
|
+
for (let i = 0; i < 5; i += 1) {
|
|
86
|
+
const digit = remainder % 36;
|
|
87
|
+
piece = base36Digits[digit] + piece;
|
|
88
|
+
remainder = (remainder - digit) / 36;
|
|
89
|
+
}
|
|
90
|
+
id = piece + id;
|
|
91
|
+
}
|
|
92
|
+
return id;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function uuidToBytes(uuid: string): Uint8Array {
|
|
96
|
+
const bytes = new Uint8Array(16);
|
|
97
|
+
let cursor = 0;
|
|
98
|
+
for (let i = 0; i < 16; i += 1) {
|
|
99
|
+
if (uuid.charCodeAt(cursor) === 45) cursor += 1;
|
|
100
|
+
const high = readHex(uuid, cursor);
|
|
101
|
+
const low = readHex(uuid, cursor + 1);
|
|
102
|
+
bytes[i] = (high << 4) | low;
|
|
103
|
+
cursor += 2;
|
|
104
|
+
}
|
|
105
|
+
if (cursor !== uuid.length) throw new Error(`Not a uuid: ${uuid}`);
|
|
106
|
+
return bytes;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function readHex(uuid: string, index: number): number {
|
|
110
|
+
const code = uuid.charCodeAt(index);
|
|
111
|
+
const value = code < 128 ? hexValues[code] : -1;
|
|
112
|
+
if (value < 0) throw new Error(`Not a uuid: ${uuid}`);
|
|
113
|
+
return value;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function bytesToUuid(bytes: Uint8Array): string {
|
|
117
|
+
return `${hexOctets[bytes[0]]}${hexOctets[bytes[1]]}${hexOctets[bytes[2]]}${hexOctets[bytes[3]]}-${hexOctets[bytes[4]]}${hexOctets[bytes[5]]}-${hexOctets[bytes[6]]}${hexOctets[bytes[7]]}-${hexOctets[bytes[8]]}${hexOctets[bytes[9]]}-${hexOctets[bytes[10]]}${hexOctets[bytes[11]]}${hexOctets[bytes[12]]}${hexOctets[bytes[13]]}${hexOctets[bytes[14]]}${hexOctets[bytes[15]]}`;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** UUID column stored as text in the 36-character hyphenated form, reads/writes as base36 */
|
|
121
|
+
export const canonicalUuid = customType<{
|
|
122
|
+
data: string;
|
|
123
|
+
driverData: string;
|
|
124
|
+
}>({
|
|
125
|
+
dataType: () => "text",
|
|
126
|
+
toDriver: (value: string): string => bytesToUuid(base36ToBytes(value)),
|
|
127
|
+
fromDriver: (value: string): string => bytesToBase36(uuidToBytes(value)),
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
/** UUID column stored as text in the 25-character base36 form, reads/writes as base36 */
|
|
7
131
|
export const base36Uuid = customType<{
|
|
8
132
|
data: string;
|
|
9
133
|
driverData: string;
|
|
10
134
|
}>({
|
|
11
135
|
dataType: () => "text",
|
|
12
|
-
|
|
13
|
-
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
/** UUID column stored as a 16-byte blob, reads/writes as base36 */
|
|
139
|
+
export const rawUuid = customType<{
|
|
140
|
+
data: string;
|
|
141
|
+
driverData: Uint8Array;
|
|
142
|
+
}>({
|
|
143
|
+
dataType: () => "blob",
|
|
144
|
+
toDriver: (value: string): Uint8Array => base36ToBytes(value),
|
|
145
|
+
fromDriver: (value: Uint8Array): string => bytesToBase36(value),
|
|
14
146
|
});
|
|
15
147
|
|
|
16
148
|
export function generateBase36Id(): string {
|
|
17
|
-
|
|
149
|
+
const bytes = new Uint8Array(16);
|
|
150
|
+
crypto.getRandomValues(bytes);
|
|
151
|
+
bytes[6] = (bytes[6] & 0x0f) | 0x40;
|
|
152
|
+
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
|
153
|
+
return bytesToBase36(bytes);
|
|
18
154
|
}
|
|
19
155
|
|
|
20
156
|
export const nullableText = customType<{
|
|
@@ -40,3 +176,11 @@ export const nullableReal = customType<{
|
|
|
40
176
|
dataType: () => "real",
|
|
41
177
|
fromDriver: (v) => v ?? undefined,
|
|
42
178
|
});
|
|
179
|
+
|
|
180
|
+
export const nullableBlob = customType<{
|
|
181
|
+
data: Uint8Array | undefined;
|
|
182
|
+
driverData: Uint8Array | null;
|
|
183
|
+
}>({
|
|
184
|
+
dataType: () => "blob",
|
|
185
|
+
fromDriver: (v) => v ?? undefined,
|
|
186
|
+
});
|