xitdb 0.1.0 → 0.2.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.
Files changed (63) hide show
  1. package/dist/core-buffered-file.d.ts +41 -0
  2. package/dist/core-file.d.ts +18 -0
  3. package/dist/core-memory.d.ts +36 -0
  4. package/dist/core.d.ts +23 -0
  5. package/dist/database.d.ts +244 -0
  6. package/dist/exceptions.d.ts +51 -0
  7. package/dist/hasher.d.ts +9 -0
  8. package/dist/index.d.ts +26 -0
  9. package/dist/index.js +429 -266
  10. package/dist/read-array-list.d.ts +13 -0
  11. package/dist/read-counted-hash-map.d.ts +7 -0
  12. package/dist/read-counted-hash-set.d.ts +7 -0
  13. package/dist/read-cursor.d.ts +57 -0
  14. package/dist/read-hash-map.d.ts +27 -0
  15. package/dist/read-hash-set.d.ts +18 -0
  16. package/dist/read-linked-array-list.d.ts +13 -0
  17. package/dist/slot-pointer.d.ts +7 -0
  18. package/dist/slot.d.ts +15 -0
  19. package/{src/slotted.ts → dist/slotted.d.ts} +1 -2
  20. package/dist/tag.d.ts +17 -0
  21. package/dist/write-array-list.d.ts +16 -0
  22. package/dist/write-counted-hash-map.d.ts +7 -0
  23. package/dist/write-counted-hash-set.d.ts +7 -0
  24. package/dist/write-cursor.d.ts +36 -0
  25. package/dist/write-hash-map.d.ts +25 -0
  26. package/dist/write-hash-set.d.ts +19 -0
  27. package/dist/write-linked-array-list.d.ts +19 -0
  28. package/dist/writeable-data.d.ts +20 -0
  29. package/package.json +12 -1
  30. package/.claude/settings.local.json +0 -9
  31. package/bun.lock +0 -24
  32. package/bunfig.toml +0 -1
  33. package/example/README.md +0 -46
  34. package/example/dump.ts +0 -201
  35. package/src/core-buffered-file.ts +0 -226
  36. package/src/core-file.ts +0 -137
  37. package/src/core-memory.ts +0 -179
  38. package/src/core.ts +0 -25
  39. package/src/database.ts +0 -2232
  40. package/src/exceptions.ts +0 -31
  41. package/src/hasher.ts +0 -52
  42. package/src/index.ts +0 -110
  43. package/src/read-array-list.ts +0 -45
  44. package/src/read-counted-hash-map.ts +0 -28
  45. package/src/read-counted-hash-set.ts +0 -28
  46. package/src/read-cursor.ts +0 -546
  47. package/src/read-hash-map.ts +0 -117
  48. package/src/read-hash-set.ts +0 -70
  49. package/src/read-linked-array-list.ts +0 -45
  50. package/src/slot-pointer.ts +0 -15
  51. package/src/slot.ts +0 -51
  52. package/src/tag.ts +0 -23
  53. package/src/write-array-list.ts +0 -65
  54. package/src/write-counted-hash-map.ts +0 -31
  55. package/src/write-counted-hash-set.ts +0 -31
  56. package/src/write-cursor.ts +0 -166
  57. package/src/write-hash-map.ts +0 -129
  58. package/src/write-hash-set.ts +0 -86
  59. package/src/write-linked-array-list.ts +0 -80
  60. package/src/writeable-data.ts +0 -67
  61. package/tests/database.test.ts +0 -2519
  62. package/tests/fixtures/test.db +0 -0
  63. package/tsconfig.json +0 -17
@@ -1,546 +0,0 @@
1
- import { Tag } from './tag';
2
- import { Slot } from './slot';
3
- import { SlotPointer } from './slot-pointer';
4
- import type { Slotted } from './slotted';
5
- import {
6
- Database,
7
- WriteMode,
8
- ArrayListHeader,
9
- LinkedArrayListHeader,
10
- KeyValuePair,
11
- type PathPart,
12
- ArrayListGet,
13
- INDEX_BLOCK_SIZE,
14
- LINKED_ARRAY_LIST_INDEX_BLOCK_SIZE,
15
- SLOT_COUNT,
16
- LinkedArrayListSlot,
17
- } from './database';
18
- import {
19
- UnexpectedTagException,
20
- StreamTooLongException,
21
- EndOfStreamException,
22
- InvalidOffsetException,
23
- KeyNotFoundException,
24
- ExpectedUnsignedLongException,
25
- } from './exceptions';
26
- import { Bytes } from './writeable-data';
27
-
28
- export class KeyValuePairCursor {
29
- constructor(
30
- public valueCursor: ReadCursor,
31
- public keyCursor: ReadCursor,
32
- public hash: Uint8Array
33
- ) {}
34
- }
35
-
36
- export class ReadCursor implements Slotted {
37
- public slotPtr: SlotPointer;
38
- public db: Database;
39
-
40
- constructor(slotPtr: SlotPointer, db: Database) {
41
- this.slotPtr = slotPtr;
42
- this.db = db;
43
- }
44
-
45
- slot(): Slot {
46
- return this.slotPtr.slot;
47
- }
48
-
49
- async readPath(path: PathPart[]): Promise<ReadCursor | null> {
50
- try {
51
- const slotPtr = await this.db.readSlotPointer(WriteMode.READ_ONLY, path, 0, this.slotPtr);
52
- return new ReadCursor(slotPtr, this.db);
53
- } catch (e) {
54
- if (e instanceof KeyNotFoundException) {
55
- return null;
56
- }
57
- throw e;
58
- }
59
- }
60
-
61
- async readPathSlot(path: PathPart[]): Promise<Slot | null> {
62
- try {
63
- const slotPtr = await this.db.readSlotPointer(WriteMode.READ_ONLY, path, 0, this.slotPtr);
64
- if (!slotPtr.slot.empty()) {
65
- return slotPtr.slot;
66
- } else {
67
- return null;
68
- }
69
- } catch (e) {
70
- if (e instanceof KeyNotFoundException) {
71
- return null;
72
- }
73
- throw e;
74
- }
75
- }
76
-
77
- readUint(): number {
78
- if (this.slotPtr.slot.tag !== Tag.UINT) {
79
- throw new UnexpectedTagException();
80
- }
81
- if (this.slotPtr.slot.value < 0n) throw new ExpectedUnsignedLongException();
82
- return Number(this.slotPtr.slot.value);
83
- }
84
-
85
- readInt(): number {
86
- if (this.slotPtr.slot.tag !== Tag.INT) {
87
- throw new UnexpectedTagException();
88
- }
89
- return Number(this.slotPtr.slot.value);
90
- }
91
-
92
- readFloat(): number {
93
- if (this.slotPtr.slot.tag !== Tag.FLOAT) {
94
- throw new UnexpectedTagException();
95
- }
96
- const buffer = new ArrayBuffer(8);
97
- const view = new DataView(buffer);
98
- // Write value as 8 bytes big-endian (using BigInt operations)
99
- view.setBigInt64(0, this.slotPtr.slot.value, false);
100
- return view.getFloat64(0, false);
101
- }
102
-
103
- async readBytes(maxSizeMaybe: number | null = null): Promise<Uint8Array> {
104
- const bytesObj = await this.readBytesObject(maxSizeMaybe);
105
- return bytesObj.value;
106
- }
107
-
108
- async readBytesObject(maxSizeMaybe: number | null = null): Promise<Bytes> {
109
- const reader = this.db.core.reader();
110
-
111
- switch (this.slotPtr.slot.tag) {
112
- case Tag.NONE:
113
- return new Bytes(new Uint8Array(0));
114
- case Tag.BYTES: {
115
- await this.db.core.seek(Number(this.slotPtr.slot.value));
116
- const valueSize = await reader.readLong();
117
-
118
- if (maxSizeMaybe !== null && valueSize > maxSizeMaybe) {
119
- throw new StreamTooLongException();
120
- }
121
-
122
- const startPosition = this.db.core.position();
123
-
124
- const value = new Uint8Array(valueSize);
125
- await reader.readFully(value);
126
-
127
- let formatTag: Uint8Array | null = null;
128
- if (this.slotPtr.slot.full) {
129
- await this.db.core.seek(startPosition + valueSize);
130
- formatTag = new Uint8Array(2);
131
- await reader.readFully(formatTag);
132
- }
133
-
134
- return new Bytes(value, formatTag);
135
- }
136
- case Tag.SHORT_BYTES: {
137
- const buffer = new ArrayBuffer(8);
138
- const view = new DataView(buffer);
139
- // Write value as 8 bytes big-endian (using BigInt operations)
140
- view.setBigInt64(0, this.slotPtr.slot.value, false);
141
- const bytes = new Uint8Array(buffer);
142
-
143
- const totalSize = this.slotPtr.slot.full ? bytes.length - 2 : bytes.length;
144
-
145
- let valueSize = 0;
146
- for (const b of bytes) {
147
- if (b === 0 || valueSize === totalSize) break;
148
- valueSize += 1;
149
- }
150
-
151
- if (maxSizeMaybe !== null && valueSize > maxSizeMaybe) {
152
- throw new StreamTooLongException();
153
- }
154
-
155
- let formatTag: Uint8Array | null = null;
156
- if (this.slotPtr.slot.full) {
157
- formatTag = bytes.slice(totalSize, bytes.length);
158
- }
159
-
160
- return new Bytes(bytes.slice(0, valueSize), formatTag);
161
- }
162
- default:
163
- throw new UnexpectedTagException();
164
- }
165
- }
166
-
167
- async readKeyValuePair(): Promise<KeyValuePairCursor> {
168
- const reader = this.db.core.reader();
169
-
170
- if (this.slotPtr.slot.tag !== Tag.KV_PAIR) {
171
- throw new UnexpectedTagException();
172
- }
173
-
174
- await this.db.core.seek(Number(this.slotPtr.slot.value));
175
- const kvPairBytes = new Uint8Array(KeyValuePair.length(this.db.header.hashSize));
176
- await reader.readFully(kvPairBytes);
177
- const kvPair = KeyValuePair.fromBytes(kvPairBytes, this.db.header.hashSize);
178
-
179
- const hashPos = Number(this.slotPtr.slot.value);
180
- const keySlotPos = hashPos + this.db.header.hashSize;
181
- const valueSlotPos = keySlotPos + Slot.LENGTH;
182
-
183
- return new KeyValuePairCursor(
184
- new ReadCursor(new SlotPointer(valueSlotPos, kvPair.valueSlot), this.db),
185
- new ReadCursor(new SlotPointer(keySlotPos, kvPair.keySlot), this.db),
186
- kvPair.hash
187
- );
188
- }
189
-
190
- async reader(): Promise<Reader> {
191
- const reader = this.db.core.reader();
192
-
193
- switch (this.slotPtr.slot.tag) {
194
- case Tag.BYTES: {
195
- await this.db.core.seek(Number(this.slotPtr.slot.value));
196
- const size = await reader.readLong();
197
- const startPosition = this.db.core.position();
198
- return new Reader(this, size, startPosition, 0);
199
- }
200
- case Tag.SHORT_BYTES: {
201
- const buffer = new ArrayBuffer(8);
202
- const view = new DataView(buffer);
203
- // Write value as 8 bytes big-endian (using BigInt operations)
204
- view.setBigInt64(0, this.slotPtr.slot.value, false);
205
- const bytes = new Uint8Array(buffer);
206
-
207
- const totalSize = this.slotPtr.slot.full ? bytes.length - 2 : bytes.length;
208
-
209
- let valueSize = 0;
210
- for (const b of bytes) {
211
- if (b === 0 || valueSize === totalSize) break;
212
- valueSize += 1;
213
- }
214
-
215
- const startPosition = this.slotPtr.position! + 1;
216
- return new Reader(this, valueSize, startPosition, 0);
217
- }
218
- default:
219
- throw new UnexpectedTagException();
220
- }
221
- }
222
-
223
- async count(): Promise<number> {
224
- const reader = this.db.core.reader();
225
- switch (this.slotPtr.slot.tag) {
226
- case Tag.NONE:
227
- return 0;
228
- case Tag.ARRAY_LIST: {
229
- await this.db.core.seek(Number(this.slotPtr.slot.value));
230
- const headerBytes = new Uint8Array(ArrayListHeader.LENGTH);
231
- await reader.readFully(headerBytes);
232
- const header = ArrayListHeader.fromBytes(headerBytes);
233
- return header.size;
234
- }
235
- case Tag.LINKED_ARRAY_LIST: {
236
- await this.db.core.seek(Number(this.slotPtr.slot.value));
237
- const headerBytes = new Uint8Array(LinkedArrayListHeader.LENGTH);
238
- await reader.readFully(headerBytes);
239
- const header = LinkedArrayListHeader.fromBytes(headerBytes);
240
- return header.size;
241
- }
242
- case Tag.BYTES: {
243
- await this.db.core.seek(Number(this.slotPtr.slot.value));
244
- return reader.readLong();
245
- }
246
- case Tag.SHORT_BYTES: {
247
- const buffer = new ArrayBuffer(8);
248
- const view = new DataView(buffer);
249
- // Write value as 8 bytes big-endian (using BigInt operations)
250
- view.setBigInt64(0, this.slotPtr.slot.value, false);
251
- const bytes = new Uint8Array(buffer);
252
-
253
- const totalSize = this.slotPtr.slot.full ? bytes.length - 2 : bytes.length;
254
-
255
- let size = 0;
256
- for (const b of bytes) {
257
- if (b === 0 || size === totalSize) break;
258
- size += 1;
259
- }
260
- return size;
261
- }
262
- case Tag.COUNTED_HASH_MAP:
263
- case Tag.COUNTED_HASH_SET: {
264
- await this.db.core.seek(Number(this.slotPtr.slot.value));
265
- return reader.readLong();
266
- }
267
- default:
268
- throw new UnexpectedTagException();
269
- }
270
- }
271
-
272
- async *[Symbol.asyncIterator](): AsyncIterator<ReadCursor> {
273
- const iterator = new CursorIterator(this);
274
- await iterator.init();
275
- while (await iterator.hasNext()) {
276
- const next = await iterator.next();
277
- if (next !== null) {
278
- yield next;
279
- }
280
- }
281
- }
282
-
283
- iterator(): CursorIterator {
284
- return new CursorIterator(this);
285
- }
286
- }
287
-
288
- export class Reader {
289
- parent: ReadCursor;
290
- size: number;
291
- startPosition: number;
292
- relativePosition: number;
293
-
294
- constructor(parent: ReadCursor, size: number, startPosition: number, relativePosition: number) {
295
- this.parent = parent;
296
- this.size = size;
297
- this.startPosition = startPosition;
298
- this.relativePosition = relativePosition;
299
- }
300
-
301
- async read(buffer: Uint8Array): Promise<number> {
302
- if (this.size < this.relativePosition) throw new EndOfStreamException();
303
- await this.parent.db.core.seek(this.startPosition + this.relativePosition);
304
- const readSize = Math.min(buffer.length, this.size - this.relativePosition);
305
- if (readSize === 0) return -1;
306
- const reader = this.parent.db.core.reader();
307
- const tempBuffer = new Uint8Array(readSize);
308
- await reader.readFully(tempBuffer);
309
- buffer.set(tempBuffer);
310
- this.relativePosition += readSize;
311
- return readSize;
312
- }
313
-
314
- async readFully(buffer: Uint8Array): Promise<void> {
315
- if (this.size < this.relativePosition || this.size - this.relativePosition < buffer.length) {
316
- throw new EndOfStreamException();
317
- }
318
- await this.parent.db.core.seek(this.startPosition + this.relativePosition);
319
- const reader = this.parent.db.core.reader();
320
- await reader.readFully(buffer);
321
- this.relativePosition += buffer.length;
322
- }
323
-
324
- async readByte(): Promise<number> {
325
- const bytes = new Uint8Array(1);
326
- await this.readFully(bytes);
327
- return bytes[0];
328
- }
329
-
330
- async readShort(): Promise<number> {
331
- const readSize = 2;
332
- const bytes = new Uint8Array(readSize);
333
- await this.readFully(bytes);
334
- const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
335
- return view.getInt16(0, false);
336
- }
337
-
338
- async readInt(): Promise<number> {
339
- const readSize = 4;
340
- const bytes = new Uint8Array(readSize);
341
- await this.readFully(bytes);
342
- const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
343
- return view.getInt32(0, false);
344
- }
345
-
346
- async readLong(): Promise<number> {
347
- const readSize = 8;
348
- const bytes = new Uint8Array(readSize);
349
- await this.readFully(bytes);
350
- const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
351
- return Number(view.getBigInt64(0, false));
352
- }
353
-
354
- seek(position: number): void {
355
- if (position > this.size) {
356
- throw new InvalidOffsetException();
357
- }
358
- this.relativePosition = position;
359
- }
360
- }
361
-
362
- class IteratorLevel {
363
- position: number;
364
- block: Slot[];
365
- index: number;
366
-
367
- constructor(position: number, block: Slot[], index: number) {
368
- this.position = position;
369
- this.block = block;
370
- this.index = index;
371
- }
372
- }
373
-
374
- export class CursorIterator {
375
- cursor: ReadCursor;
376
- size: number = 0;
377
- index: number = 0;
378
- private stack: IteratorLevel[] = [];
379
- private nextCursorMaybe: ReadCursor | null = null;
380
- private initialized: boolean = false;
381
-
382
- constructor(cursor: ReadCursor) {
383
- this.cursor = cursor;
384
- }
385
-
386
- async init(): Promise<void> {
387
- if (this.initialized) return;
388
- this.initialized = true;
389
-
390
- switch (this.cursor.slotPtr.slot.tag) {
391
- case Tag.NONE:
392
- this.size = 0;
393
- this.index = 0;
394
- this.stack = [];
395
- break;
396
- case Tag.ARRAY_LIST: {
397
- const position = Number(this.cursor.slotPtr.slot.value);
398
- await this.cursor.db.core.seek(position);
399
- const reader = this.cursor.db.core.reader();
400
- const headerBytes = new Uint8Array(ArrayListHeader.LENGTH);
401
- await reader.readFully(headerBytes);
402
- const header = ArrayListHeader.fromBytes(headerBytes);
403
- this.size = await this.cursor.count();
404
- this.index = 0;
405
- this.stack = await this.initStack(this.cursor, header.ptr, INDEX_BLOCK_SIZE);
406
- break;
407
- }
408
- case Tag.LINKED_ARRAY_LIST: {
409
- const position = Number(this.cursor.slotPtr.slot.value);
410
- await this.cursor.db.core.seek(position);
411
- const reader = this.cursor.db.core.reader();
412
- const headerBytes = new Uint8Array(LinkedArrayListHeader.LENGTH);
413
- await reader.readFully(headerBytes);
414
- const header = LinkedArrayListHeader.fromBytes(headerBytes);
415
- this.size = await this.cursor.count();
416
- this.index = 0;
417
- this.stack = await this.initStack(this.cursor, header.ptr, LINKED_ARRAY_LIST_INDEX_BLOCK_SIZE);
418
- break;
419
- }
420
- case Tag.HASH_MAP:
421
- case Tag.HASH_SET:
422
- this.size = 0;
423
- this.index = 0;
424
- this.stack = await this.initStack(this.cursor, Number(this.cursor.slotPtr.slot.value), INDEX_BLOCK_SIZE);
425
- break;
426
- case Tag.COUNTED_HASH_MAP:
427
- case Tag.COUNTED_HASH_SET:
428
- this.size = 0;
429
- this.index = 0;
430
- this.stack = await this.initStack(this.cursor, Number(this.cursor.slotPtr.slot.value) + 8, INDEX_BLOCK_SIZE);
431
- break;
432
- default:
433
- throw new UnexpectedTagException();
434
- }
435
- }
436
-
437
- private async initStack(cursor: ReadCursor, position: number, blockSize: number): Promise<IteratorLevel[]> {
438
- await cursor.db.core.seek(position);
439
- const reader = cursor.db.core.reader();
440
- const indexBlockBytes = new Uint8Array(blockSize);
441
- await reader.readFully(indexBlockBytes);
442
-
443
- const indexBlock: Slot[] = new Array(SLOT_COUNT);
444
- const slotSize = blockSize / SLOT_COUNT;
445
- for (let i = 0; i < SLOT_COUNT; i++) {
446
- const slotBytes = indexBlockBytes.slice(i * slotSize, i * slotSize + Slot.LENGTH);
447
- indexBlock[i] = Slot.fromBytes(slotBytes);
448
- }
449
-
450
- return [new IteratorLevel(position, indexBlock, 0)];
451
- }
452
-
453
- async hasNext(): Promise<boolean> {
454
- await this.init();
455
-
456
- switch (this.cursor.slotPtr.slot.tag) {
457
- case Tag.NONE:
458
- return false;
459
- case Tag.ARRAY_LIST:
460
- return this.index < this.size;
461
- case Tag.LINKED_ARRAY_LIST:
462
- return this.index < this.size;
463
- case Tag.HASH_MAP:
464
- case Tag.HASH_SET:
465
- case Tag.COUNTED_HASH_MAP:
466
- case Tag.COUNTED_HASH_SET:
467
- if (this.nextCursorMaybe === null) {
468
- this.nextCursorMaybe = await this.nextInternal(INDEX_BLOCK_SIZE);
469
- }
470
- return this.nextCursorMaybe !== null;
471
- default:
472
- return false;
473
- }
474
- }
475
-
476
- async next(): Promise<ReadCursor | null> {
477
- await this.init();
478
-
479
- switch (this.cursor.slotPtr.slot.tag) {
480
- case Tag.NONE:
481
- return null;
482
- case Tag.ARRAY_LIST:
483
- if (!(await this.hasNext())) return null;
484
- this.index += 1;
485
- return this.nextInternal(INDEX_BLOCK_SIZE);
486
- case Tag.LINKED_ARRAY_LIST:
487
- if (!(await this.hasNext())) return null;
488
- this.index += 1;
489
- return this.nextInternal(LINKED_ARRAY_LIST_INDEX_BLOCK_SIZE);
490
- case Tag.HASH_MAP:
491
- case Tag.HASH_SET:
492
- case Tag.COUNTED_HASH_MAP:
493
- case Tag.COUNTED_HASH_SET:
494
- if (this.nextCursorMaybe !== null) {
495
- const nextCursor = this.nextCursorMaybe;
496
- this.nextCursorMaybe = null;
497
- return nextCursor;
498
- } else {
499
- return this.nextInternal(INDEX_BLOCK_SIZE);
500
- }
501
- default:
502
- throw new UnexpectedTagException();
503
- }
504
- }
505
-
506
- private async nextInternal(blockSize: number): Promise<ReadCursor | null> {
507
- while (this.stack.length > 0) {
508
- const level = this.stack[this.stack.length - 1];
509
- if (level.index === level.block.length) {
510
- this.stack.pop();
511
- if (this.stack.length > 0) {
512
- this.stack[this.stack.length - 1].index += 1;
513
- }
514
- continue;
515
- } else {
516
- const nextSlot = level.block[level.index];
517
- if (nextSlot.tag === Tag.INDEX) {
518
- const nextPos = Number(nextSlot.value);
519
- await this.cursor.db.core.seek(nextPos);
520
- const reader = this.cursor.db.core.reader();
521
- const indexBlockBytes = new Uint8Array(blockSize);
522
- await reader.readFully(indexBlockBytes);
523
-
524
- const indexBlock: Slot[] = new Array(SLOT_COUNT);
525
- const slotSize = blockSize / SLOT_COUNT;
526
- for (let i = 0; i < SLOT_COUNT; i++) {
527
- const slotBytes = indexBlockBytes.slice(i * slotSize, i * slotSize + Slot.LENGTH);
528
- indexBlock[i] = Slot.fromBytes(slotBytes);
529
- }
530
-
531
- this.stack.push(new IteratorLevel(nextPos, indexBlock, 0));
532
- continue;
533
- } else {
534
- this.stack[this.stack.length - 1].index += 1;
535
- if (!nextSlot.empty()) {
536
- const position = level.position + level.index * Slot.LENGTH;
537
- return new ReadCursor(new SlotPointer(position, nextSlot), this.cursor.db);
538
- } else {
539
- continue;
540
- }
541
- }
542
- }
543
- }
544
- return null;
545
- }
546
- }
@@ -1,117 +0,0 @@
1
- import { Tag } from './tag';
2
- import { Slot } from './slot';
3
- import type { Slotted } from './slotted';
4
- import { ReadCursor, CursorIterator, KeyValuePairCursor } from './read-cursor';
5
- import { HashMapGet, HashMapGetValue, HashMapGetKey, HashMapGetKVPair } from './database';
6
- import { UnexpectedTagException } from './exceptions';
7
- import { Bytes } from './writeable-data';
8
-
9
- export class ReadHashMap implements Slotted {
10
- public cursor!: ReadCursor;
11
-
12
- protected constructor() {}
13
-
14
- static async create(cursor: ReadCursor): Promise<ReadHashMap> {
15
- const map = new ReadHashMap();
16
- switch (cursor.slotPtr.slot.tag) {
17
- case Tag.NONE:
18
- case Tag.HASH_MAP:
19
- case Tag.HASH_SET:
20
- map.cursor = cursor;
21
- break;
22
- default:
23
- throw new UnexpectedTagException();
24
- }
25
- return map;
26
- }
27
-
28
- slot(): Slot {
29
- return this.cursor.slot();
30
- }
31
-
32
- iterator(): CursorIterator {
33
- return this.cursor.iterator();
34
- }
35
-
36
- async *[Symbol.asyncIterator](): AsyncIterator<ReadCursor> {
37
- yield* this.cursor;
38
- }
39
-
40
- // Methods that take a string key and hash it
41
- async getCursorByString(key: string): Promise<ReadCursor | null> {
42
- const hash = await this.cursor.db.hasher.digest(new TextEncoder().encode(key));
43
- return this.getCursor(hash);
44
- }
45
-
46
- async getSlotByString(key: string): Promise<Slot | null> {
47
- const hash = await this.cursor.db.hasher.digest(new TextEncoder().encode(key));
48
- return this.getSlot(hash);
49
- }
50
-
51
- async getKeyCursorByString(key: string): Promise<ReadCursor | null> {
52
- const hash = await this.cursor.db.hasher.digest(new TextEncoder().encode(key));
53
- return this.getKeyCursor(hash);
54
- }
55
-
56
- async getKeySlotByString(key: string): Promise<Slot | null> {
57
- const hash = await this.cursor.db.hasher.digest(new TextEncoder().encode(key));
58
- return this.getKeySlot(hash);
59
- }
60
-
61
- async getKeyValuePairByString(key: string): Promise<KeyValuePairCursor | null> {
62
- const hash = await this.cursor.db.hasher.digest(new TextEncoder().encode(key));
63
- return this.getKeyValuePair(hash);
64
- }
65
-
66
- // Methods that take Bytes key and hash it
67
- async getCursorByBytes(key: Bytes): Promise<ReadCursor | null> {
68
- const hash = await this.cursor.db.hasher.digest(key.value);
69
- return this.getCursor(hash);
70
- }
71
-
72
- async getSlotByBytes(key: Bytes): Promise<Slot | null> {
73
- const hash = await this.cursor.db.hasher.digest(key.value);
74
- return this.getSlot(hash);
75
- }
76
-
77
- async getKeyCursorByBytes(key: Bytes): Promise<ReadCursor | null> {
78
- const hash = await this.cursor.db.hasher.digest(key.value);
79
- return this.getKeyCursor(hash);
80
- }
81
-
82
- async getKeySlotByBytes(key: Bytes): Promise<Slot | null> {
83
- const hash = await this.cursor.db.hasher.digest(key.value);
84
- return this.getKeySlot(hash);
85
- }
86
-
87
- async getKeyValuePairByBytes(key: Bytes): Promise<KeyValuePairCursor | null> {
88
- const hash = await this.cursor.db.hasher.digest(key.value);
89
- return this.getKeyValuePair(hash);
90
- }
91
-
92
- // Methods that take hash directly
93
- async getCursor(hash: Uint8Array): Promise<ReadCursor | null> {
94
- return this.cursor.readPath([new HashMapGet(new HashMapGetValue(hash))]);
95
- }
96
-
97
- async getSlot(hash: Uint8Array): Promise<Slot | null> {
98
- return this.cursor.readPathSlot([new HashMapGet(new HashMapGetValue(hash))]);
99
- }
100
-
101
- async getKeyCursor(hash: Uint8Array): Promise<ReadCursor | null> {
102
- return this.cursor.readPath([new HashMapGet(new HashMapGetKey(hash))]);
103
- }
104
-
105
- async getKeySlot(hash: Uint8Array): Promise<Slot | null> {
106
- return this.cursor.readPathSlot([new HashMapGet(new HashMapGetKey(hash))]);
107
- }
108
-
109
- async getKeyValuePair(hash: Uint8Array): Promise<KeyValuePairCursor | null> {
110
- const cursor = await this.cursor.readPath([new HashMapGet(new HashMapGetKVPair(hash))]);
111
- if (cursor === null) {
112
- return null;
113
- } else {
114
- return cursor.readKeyValuePair();
115
- }
116
- }
117
- }