-
Notifications
You must be signed in to change notification settings - Fork 265
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
205 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
/** | ||
* A collection of items | ||
*/ | ||
export interface AztecCollection<T, K extends string> { | ||
/** | ||
* The size of the collection | ||
*/ | ||
size: number; | ||
|
||
/** | ||
* Adds values to the collection | ||
* @param vals - The values to push to the end of the array | ||
*/ | ||
insert(...vals: T[]): Promise<number[]>; | ||
|
||
/** | ||
* Deletes items from the collection | ||
* @param ids - The ids of the items to delete | ||
*/ | ||
delete(...ids: number[]): Promise<void>; | ||
|
||
/** | ||
* Gets an item by id | ||
* @param id - The id of the item to get | ||
*/ | ||
get(id: number): T | undefined; | ||
|
||
/** | ||
* Gets a subset of items by an index | ||
* @param indexName - The name of the index | ||
* @param key - The key to get the item by | ||
*/ | ||
entriesByIndex(indexName: K, key: string): IterableIterator<[number, T]>; | ||
|
||
/** | ||
* Iterates over the array with indexes. | ||
*/ | ||
entries(): IterableIterator<[number, T]>; | ||
|
||
/** | ||
* Iterates over the array. | ||
*/ | ||
values(): IterableIterator<T>; | ||
|
||
/** | ||
* Iterates over the array. | ||
*/ | ||
[Symbol.iterator](): IterableIterator<T>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
import { Database, Key } from 'lmdb'; | ||
|
||
import { AztecArray } from '../interfaces/array.js'; | ||
import { AztecCollection } from '../interfaces/collection.js'; | ||
import { AztecMultiMap } from '../interfaces/map.js'; | ||
import { AztecSingleton } from '../interfaces/singleton.js'; | ||
import { AztecKVStore } from '../interfaces/store.js'; | ||
|
||
/** Maps an object to a value to be indexed by */ | ||
type IndexFn<T> = (item: T) => string; | ||
|
||
/** Internal structure to reference indexes */ | ||
type Index<T> = { | ||
/** Mapping function */ | ||
fn: IndexFn<T>; | ||
/** Map */ | ||
map: AztecMultiMap<string, number>; | ||
}; | ||
|
||
/** | ||
* A collection | ||
*/ | ||
export class LmdbAztecCollection<T, K extends string> implements AztecCollection<T, K> { | ||
#db: Database; | ||
#items: AztecArray<T | undefined>; | ||
#deletedCount: AztecSingleton<number>; | ||
#indexes = new Map<K, Index<T>>(); | ||
|
||
constructor(store: AztecKVStore, db: Database<unknown, Key>, name: string, indexFns: Record<K, (item: T) => string>) { | ||
this.#db = db; | ||
this.#items = store.createArray(name + ':' + 'items'); | ||
this.#deletedCount = store.createSingleton(name + ':' + 'deletedCount'); | ||
|
||
for (const [name, fn] of Object.entries<(item: T) => string>(indexFns)) { | ||
this.#indexes.set(name as K, { | ||
fn, | ||
map: store.createMultiMap(name + ':index:' + name), | ||
}); | ||
} | ||
} | ||
|
||
get size(): number { | ||
return this.#items.length - (this.#deletedCount.get() ?? 0); | ||
} | ||
|
||
get(id: number): T | undefined { | ||
return this.#items.at(id); | ||
} | ||
|
||
*entriesByIndex(indexName: K, key: string): IterableIterator<[number, T]> { | ||
const index = this.#indexes.get(indexName); | ||
|
||
if (typeof index === 'undefined') { | ||
throw new Error(`Index ${indexName} does not exist`); | ||
} | ||
|
||
const ids = index.map.getValues(key); | ||
for (const id of ids) { | ||
const item = this.#items.at(id); | ||
if (typeof item === 'undefined') { | ||
continue; | ||
} | ||
|
||
yield [id, item]; | ||
} | ||
} | ||
|
||
insert(...items: T[]): Promise<number[]> { | ||
return this.#db.transaction(() => { | ||
const length = this.#items.length; | ||
const ids: number[] = []; | ||
void this.#items.push(...items); | ||
|
||
for (const [index, item] of items.entries()) { | ||
const id = length + index; | ||
ids.push(id); | ||
for (const index of this.#indexes.values()) { | ||
const key = index.fn(item); | ||
void index.map.set(key, id); | ||
} | ||
} | ||
|
||
return ids; | ||
}); | ||
} | ||
|
||
delete(...ids: number[]): Promise<void> { | ||
return this.#db.transaction(() => { | ||
for (const id of ids) { | ||
const item = this.#items.at(id); | ||
|
||
if (typeof item === 'undefined') { | ||
continue; | ||
} | ||
|
||
for (const index of this.#indexes.values()) { | ||
const key = index.fn(item); | ||
void index.map.delete(key); | ||
} | ||
|
||
void this.#items.setAt(id, undefined); | ||
} | ||
|
||
void this.#deletedCount.set((this.#deletedCount.get() ?? 0) + ids.length); | ||
}); | ||
} | ||
|
||
*entries(): IterableIterator<[number, T]> { | ||
for (const entry of this.#items.entries()) { | ||
if (entry[1] === null) { | ||
continue; | ||
} | ||
|
||
yield entry as [number, T]; | ||
} | ||
} | ||
|
||
*values(): IterableIterator<T> { | ||
for (const [_, item] of this.entries()) { | ||
yield item; | ||
} | ||
} | ||
|
||
[Symbol.iterator](): IterableIterator<T> { | ||
return this.values(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters