@rip-lang/db 0.10.0 → 1.0.2
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 +98 -259
- package/bin/rip-db +5 -10
- package/db.rip +217 -237
- package/lib/duckdb-binary.rip +34 -13
- package/lib/duckdb.mjs +694 -304
- package/package.json +10 -7
- package/PROTOCOL.md +0 -258
- package/db.html +0 -122
- package/lib/darwin-arm64/duckdb.node +0 -0
package/lib/duckdb-binary.rip
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
#
|
|
3
3
|
# Implements the binary serialization format used by DuckDB's official UI.
|
|
4
4
|
# This allows rip-db to serve responses that the DuckDB UI can understand.
|
|
5
|
-
#
|
|
6
|
-
# Protocol spec: See PROTOCOL.md in this directory
|
|
7
5
|
|
|
8
6
|
# ==============================================================================
|
|
9
7
|
# LogicalTypeId - matches DuckDB's internal type IDs
|
|
@@ -46,6 +44,9 @@ export LogicalTypeId =
|
|
|
46
44
|
UNION: 107
|
|
47
45
|
ARRAY: 108
|
|
48
46
|
|
|
47
|
+
# Shared TextEncoder instance (avoid allocating per call)
|
|
48
|
+
textEncoder = new TextEncoder()
|
|
49
|
+
|
|
49
50
|
# ==============================================================================
|
|
50
51
|
# BinarySerializer - writes the DuckDB binary format
|
|
51
52
|
# ==============================================================================
|
|
@@ -106,8 +107,7 @@ export class BinarySerializer
|
|
|
106
107
|
break
|
|
107
108
|
|
|
108
109
|
writeString: (str) ->
|
|
109
|
-
|
|
110
|
-
bytes = encoder.encode str
|
|
110
|
+
bytes = textEncoder.encode str
|
|
111
111
|
@writeVarInt bytes.length
|
|
112
112
|
@buffer.push ...bytes
|
|
113
113
|
|
|
@@ -213,21 +213,23 @@ serializeType = (s, column) ->
|
|
|
213
213
|
serializeDataChunk = (s, columns, rows) ->
|
|
214
214
|
s.writePropertyVarInt 100, rows.length
|
|
215
215
|
s.writeList 101, columns, (s, col, colIdx) ->
|
|
216
|
-
values = rows.map (row) -> row[colIdx]
|
|
216
|
+
values = rows.map (row) -> row[colIdx]
|
|
217
217
|
serializeVector s, col, values
|
|
218
218
|
s.writeEndMarker()
|
|
219
219
|
|
|
220
220
|
serializeVector = (s, column, values) ->
|
|
221
221
|
typeId = mapDuckDBType column.type
|
|
222
222
|
hasNulls = values.some (v) -> v is null or v is undefined
|
|
223
|
-
allValid = if hasNulls then 0 else 1
|
|
224
223
|
|
|
224
|
+
# allValid flag: 0 = all valid (no bitmap), non-zero = has validity bitmap
|
|
225
|
+
# The deserializer reads field 101 ONLY when allValid is truthy
|
|
225
226
|
s.writeFieldId 100
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
if not allValid
|
|
227
|
+
if hasNulls
|
|
228
|
+
s.writeUint8 1 # Has validity bitmap
|
|
229
229
|
s.writeFieldId 101
|
|
230
230
|
s.writeData createValidityBitmap values
|
|
231
|
+
else
|
|
232
|
+
s.writeUint8 0 # All valid, no bitmap needed
|
|
231
233
|
|
|
232
234
|
switch typeId
|
|
233
235
|
when LogicalTypeId.VARCHAR, LogicalTypeId.CHAR
|
|
@@ -329,6 +331,16 @@ serializeVector = (s, column, values) ->
|
|
|
329
331
|
dv.setBigInt64 i * 8, micros, true
|
|
330
332
|
s.writeData bytes
|
|
331
333
|
|
|
334
|
+
when LogicalTypeId.UUID
|
|
335
|
+
s.writeFieldId 102
|
|
336
|
+
bytes = new Uint8Array values.length * 16
|
|
337
|
+
dv = new DataView bytes.buffer
|
|
338
|
+
for v, i in values
|
|
339
|
+
{ lo, hi } = uuidToHugeint(v)
|
|
340
|
+
dv.setBigUint64 i * 16, lo, true
|
|
341
|
+
dv.setBigInt64 i * 16 + 8, hi, true
|
|
342
|
+
s.writeData bytes
|
|
343
|
+
|
|
332
344
|
else
|
|
333
345
|
s.writeList 102, values, (s, v) -> s.writeString String(v ? '')
|
|
334
346
|
|
|
@@ -339,10 +351,11 @@ serializeVector = (s, column, values) ->
|
|
|
339
351
|
# ==============================================================================
|
|
340
352
|
|
|
341
353
|
createValidityBitmap = (values) ->
|
|
342
|
-
|
|
354
|
+
# Must be uint64-aligned (8-byte chunks) — the UI reads validity with getBigUint64
|
|
355
|
+
byteCount = Math.ceil(values.length / 64) * 8
|
|
343
356
|
bitmap = new Uint8Array byteCount
|
|
344
357
|
for v, i in values
|
|
345
|
-
if v?
|
|
358
|
+
if v?
|
|
346
359
|
byteIdx = Math.floor i / 8
|
|
347
360
|
bitIdx = i % 8
|
|
348
361
|
bitmap[byteIdx] |= 1 << bitIdx
|
|
@@ -370,6 +383,14 @@ timestampToMicros = (value) ->
|
|
|
370
383
|
else
|
|
371
384
|
0n
|
|
372
385
|
|
|
386
|
+
uuidToHugeint = (uuid) ->
|
|
387
|
+
return { lo: 0n, hi: 0n } unless uuid
|
|
388
|
+
hex = String(uuid).replace(/-/g, '')
|
|
389
|
+
full = BigInt "0x#{hex}"
|
|
390
|
+
hi = (full >> 64n) ^ (1n << 63n) # XOR sign bit for DuckDB sorting
|
|
391
|
+
lo = full & ((1n << 64n) - 1n)
|
|
392
|
+
{ lo, hi }
|
|
393
|
+
|
|
373
394
|
mapDuckDBType = (typeName) ->
|
|
374
395
|
return LogicalTypeId.VARCHAR unless typeName
|
|
375
396
|
upper = String(typeName).toUpperCase()
|
|
@@ -398,7 +419,7 @@ mapDuckDBType = (typeName) ->
|
|
|
398
419
|
when 'INTERVAL' then LogicalTypeId.INTERVAL
|
|
399
420
|
when 'JSON' then LogicalTypeId.VARCHAR
|
|
400
421
|
else
|
|
401
|
-
if upper.startsWith 'DECIMAL' then LogicalTypeId.
|
|
422
|
+
if upper.startsWith 'DECIMAL' then LogicalTypeId.VARCHAR # Serialize as string to preserve exact precision
|
|
402
423
|
else if upper.startsWith 'VARCHAR' then LogicalTypeId.VARCHAR
|
|
403
424
|
else if upper.startsWith 'CHAR' then LogicalTypeId.CHAR
|
|
404
425
|
else LogicalTypeId.VARCHAR
|
|
@@ -520,6 +541,6 @@ export inferType = (value) ->
|
|
|
520
541
|
else if /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}/.test value then 'TIMESTAMP'
|
|
521
542
|
else 'VARCHAR'
|
|
522
543
|
when 'object'
|
|
523
|
-
if value instanceof Date then '
|
|
544
|
+
if value instanceof Date then 'TIMESTAMPTZ'
|
|
524
545
|
else 'VARCHAR'
|
|
525
546
|
else 'VARCHAR'
|