@xyo-network/diviner-boundwitness-indexeddb 5.1.22 → 5.1.24

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/Schema.ts","../../src/Config.ts","../../src/Diviner.ts"],"sourcesContent":["import { BoundWitnessDivinerSchema } from '@xyo-network/diviner-boundwitness-model'\n\nexport const IndexedDbBoundWitnessDivinerSchema = `${BoundWitnessDivinerSchema}.indexeddb` as const\nexport type IndexedDbBoundWitnessDivinerSchema = typeof IndexedDbBoundWitnessDivinerSchema\n","import type { IndexDescription } from '@xyo-network/archivist-model'\nimport type { DivinerConfig } from '@xyo-network/diviner-model'\n\nimport { IndexedDbBoundWitnessDivinerSchema } from './Schema.ts'\n\nexport const IndexedDbBoundWitnessDivinerConfigSchema = `${IndexedDbBoundWitnessDivinerSchema}.config` as const\nexport type IndexedDbBoundWitnessDivinerConfigSchema = typeof IndexedDbBoundWitnessDivinerConfigSchema\n\nexport type IndexedDbBoundWitnessDivinerConfig = DivinerConfig<{\n /**\n * The database name\n */\n dbName?: string\n /**\n * The version of the DB, defaults to 1\n */\n dbVersion?: number\n schema: IndexedDbBoundWitnessDivinerConfigSchema\n /**\n * The storage configuration\n * // TODO: Hoist to main diviner config\n */\n storage?: {\n /**\n * The indexes to create on the object store\n */\n indexes?: IndexDescription[]\n }\n /**\n * The name of the object store\n */\n storeName?: string\n}>\n","/// <reference lib=\"dom\" />\n\nimport { containsAll } from '@xylabs/array'\nimport { assertEx } from '@xylabs/assert'\nimport { exists } from '@xylabs/exists'\nimport { IndexedDbArchivist } from '@xyo-network/archivist-indexeddb'\nimport type { BoundWitness } from '@xyo-network/boundwitness-model'\nimport { isBoundWitness } from '@xyo-network/boundwitness-model'\nimport { BoundWitnessDiviner } from '@xyo-network/diviner-boundwitness-abstract'\nimport type { BoundWitnessDivinerQueryPayload } from '@xyo-network/diviner-boundwitness-model'\nimport { isBoundWitnessDivinerQueryPayload } from '@xyo-network/diviner-boundwitness-model'\nimport type {\n Schema, Sequence, WithStorageMeta,\n} from '@xyo-network/payload-model'\nimport type { IDBPCursorWithValue, IDBPDatabase } from 'idb'\nimport { openDB } from 'idb'\n\nimport { IndexedDbBoundWitnessDivinerConfigSchema } from './Config.ts'\nimport type { IndexedDbBoundWitnessDivinerParams } from './Params.ts'\n\ninterface BoundWitnessStore {\n [s: string]: WithStorageMeta<BoundWitness>\n}\n\ntype ValueFilter = (bw?: BoundWitness | null) => boolean\n\nconst bwValueFilter = (\n key: keyof Pick<BoundWitness, 'addresses' | 'payload_hashes' | 'payload_schemas'>,\n values?: string[],\n): ValueFilter | undefined => {\n if (!values || values?.length === 0) return undefined\n return (bw) => {\n if (!bw) return false\n return containsAll(bw[key], values)\n }\n}\n\nexport class IndexedDbBoundWitnessDiviner<\n TParams extends IndexedDbBoundWitnessDivinerParams = IndexedDbBoundWitnessDivinerParams,\n TIn extends BoundWitnessDivinerQueryPayload = BoundWitnessDivinerQueryPayload,\n TOut extends BoundWitness = BoundWitness,\n> extends BoundWitnessDiviner<TParams, TIn, TOut> {\n static override readonly configSchemas: Schema[] = [...super.configSchemas, IndexedDbBoundWitnessDivinerConfigSchema]\n static override readonly defaultConfigSchema: Schema = IndexedDbBoundWitnessDivinerConfigSchema\n\n /**\n * The database name. If not supplied via config, it defaults\n * to the archivist's name and if archivist's name is not supplied,\n * it defaults to `archivist`. This behavior\n * biases towards a single, isolated DB per archivist which seems to\n * make the most sense for 99% of use cases.\n */\n get dbName() {\n return this.config?.dbName ?? this.config?.archivist ?? IndexedDbArchivist.defaultDbName\n }\n\n /**\n * The database version. If not supplied via config, it defaults to the archivist default version.\n */\n get dbVersion() {\n return this.config?.dbVersion ?? IndexedDbArchivist.defaultDbVersion\n }\n\n /**\n * The name of the object store. If not supplied via config, it defaults\n * to `payloads`.\n */\n get storeName() {\n return this.config?.storeName ?? IndexedDbArchivist.defaultStoreName\n }\n\n protected override async divineHandler(payloads?: TIn[]): Promise<TOut[]> {\n const query = payloads?.find(isBoundWitnessDivinerQueryPayload)\n if (!query) return []\n const result = await this.tryUseDb(async (db) => {\n const {\n addresses, payload_hashes, payload_schemas, limit, cursor, order,\n } = query\n const tx = db.transaction(this.storeName, 'readonly')\n const store = tx.objectStore(this.storeName)\n const results: TOut[] = []\n const parsedCursor = cursor\n const parsedLimit = limit ?? 10\n const valueFilters: ValueFilter[] = [\n isBoundWitness,\n bwValueFilter('addresses', addresses),\n bwValueFilter('payload_hashes', payload_hashes),\n bwValueFilter('payload_schemas', payload_schemas),\n ].filter(exists)\n const direction: IDBCursorDirection = order === 'desc' ? 'prev' : 'next'\n\n // Iterate all records using the sequence index\n const sequenceIndex = assertEx(store.index(IndexedDbArchivist.sequenceIndexName), () => 'Failed to get sequence index')\n let dbCursor: IDBPCursorWithValue<BoundWitnessStore, [string], string, string, 'readonly'> | null\n = await sequenceIndex.openCursor(null, direction)\n\n // If a cursor was supplied\n if (parsedCursor !== undefined) {\n let currentSequence: Sequence | undefined\n // Skip records until the supplied cursor offset is reached\n while (dbCursor && currentSequence !== parsedCursor) {\n // Find the sequence of the current record\n const current: WithStorageMeta<BoundWitness> = dbCursor.value\n currentSequence = current?._sequence\n // Advance one record beyond the cursor\n dbCursor = await dbCursor.advance(1)\n }\n }\n\n // Collect results up to the limit\n while (dbCursor && results.length < parsedLimit) {\n const value = dbCursor.value\n if (value) {\n // If we're filtering on more than just the schema\n if (valueFilters.length > 0) {\n // Ensure all filters pass\n if (valueFilters.every(filter => filter(value))) {\n // Then save the value\n results.push(value)\n }\n } else {\n // Otherwise just save the value\n results.push(value)\n }\n }\n try {\n dbCursor = await dbCursor.continue()\n } catch {\n break\n }\n }\n await tx.done\n // Remove any metadata before returning to the client\n return results\n })\n return result ?? []\n }\n\n protected override async startHandler() {\n await super.startHandler()\n // NOTE: Do not eager initialize the DB here. It will cause the\n // DB to be created by this process and then the DB will be\n // in a bad state for other processes that need to create the DB.\n }\n\n /**\n * Checks that the desired DB/objectStore exists and is initialized to the correct version\n * @returns The initialized DB or undefined if it does not exist in the desired state\n */\n private async tryGetInitializedDb(): Promise<IDBPDatabase<BoundWitnessStore> | undefined> {\n // Enumerate the DBs\n const dbs = await indexedDB.databases()\n // Check that the DB exists at the desired version\n const dbExists = dbs.some((db) => {\n return db.name === this.dbName\n })\n // If the DB exists at the desired version\n if (dbExists) {\n // If the db does exist, open it\n const db = await openDB<BoundWitnessStore>(this.dbName)\n // Check that the desired objectStore exists\n const storeExists = db.objectStoreNames.contains(this.storeName)\n // If the correct db/version/objectStore exists\n if (storeExists) {\n return db\n } else {\n // Otherwise close the db so the process that is going to update the\n // db can open it\n db.close()\n }\n }\n }\n\n /**\n * Executes a callback with the initialized DB and then closes the db\n * @param callback The method to execute with the initialized DB\n * @returns\n */\n private async tryUseDb<T>(callback: (db: IDBPDatabase<BoundWitnessStore>) => Promise<T> | T): Promise<T | undefined> {\n // Get the initialized DB\n const db = await this.tryGetInitializedDb()\n if (db) {\n try {\n // Perform the callback\n return await callback(db)\n } finally {\n // Close the DB\n db.close()\n }\n }\n return undefined\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/Schema.ts","../../src/Config.ts","../../src/Diviner.ts"],"sourcesContent":["import { BoundWitnessDivinerSchema } from '@xyo-network/diviner-boundwitness-model'\n\nexport const IndexedDbBoundWitnessDivinerSchema = `${BoundWitnessDivinerSchema}.indexeddb` as const\nexport type IndexedDbBoundWitnessDivinerSchema = typeof IndexedDbBoundWitnessDivinerSchema\n","import type { IndexDescription } from '@xyo-network/archivist-model'\nimport type { DivinerConfig } from '@xyo-network/diviner-model'\n\nimport { IndexedDbBoundWitnessDivinerSchema } from './Schema.ts'\n\nexport const IndexedDbBoundWitnessDivinerConfigSchema = `${IndexedDbBoundWitnessDivinerSchema}.config` as const\nexport type IndexedDbBoundWitnessDivinerConfigSchema = typeof IndexedDbBoundWitnessDivinerConfigSchema\n\nexport type IndexedDbBoundWitnessDivinerConfig = DivinerConfig<{\n /**\n * The database name\n */\n dbName?: string\n /**\n * The version of the DB, defaults to 1\n */\n dbVersion?: number\n schema: IndexedDbBoundWitnessDivinerConfigSchema\n /**\n * The storage configuration\n * // TODO: Hoist to main diviner config\n */\n storage?: {\n /**\n * The indexes to create on the object store\n */\n indexes?: IndexDescription[]\n }\n /**\n * The name of the object store\n */\n storeName?: string\n}>\n","/// <reference lib=\"dom\" />\n\nimport { containsAll } from '@xylabs/array'\nimport { assertEx } from '@xylabs/assert'\nimport { exists } from '@xylabs/exists'\nimport { IndexedDbArchivist } from '@xyo-network/archivist-indexeddb'\nimport type { BoundWitness } from '@xyo-network/boundwitness-model'\nimport { isBoundWitness } from '@xyo-network/boundwitness-model'\nimport { BoundWitnessDiviner } from '@xyo-network/diviner-boundwitness-abstract'\nimport type { BoundWitnessDivinerQueryPayload } from '@xyo-network/diviner-boundwitness-model'\nimport { isBoundWitnessDivinerQueryPayload } from '@xyo-network/diviner-boundwitness-model'\nimport type {\n Schema, Sequence, WithStorageMeta,\n} from '@xyo-network/payload-model'\nimport type { IDBPCursorWithValue, IDBPDatabase } from 'idb'\nimport { openDB } from 'idb'\n\nimport { IndexedDbBoundWitnessDivinerConfigSchema } from './Config.ts'\nimport type { IndexedDbBoundWitnessDivinerParams } from './Params.ts'\n\ninterface BoundWitnessStore {\n [s: string]: WithStorageMeta<BoundWitness>\n}\n\ntype ValueFilter = (bw?: BoundWitness | null) => boolean\n\nconst bwValueFilter = (\n key: keyof Pick<BoundWitness, 'addresses' | 'payload_hashes' | 'payload_schemas'>,\n values?: string[],\n): ValueFilter | undefined => {\n if (!values || values?.length === 0) return undefined\n return (bw) => {\n if (!bw) return false\n return containsAll(bw[key], values)\n }\n}\n\nexport class IndexedDbBoundWitnessDiviner<\n TParams extends IndexedDbBoundWitnessDivinerParams = IndexedDbBoundWitnessDivinerParams,\n TIn extends BoundWitnessDivinerQueryPayload = BoundWitnessDivinerQueryPayload,\n TOut extends BoundWitness = BoundWitness,\n> extends BoundWitnessDiviner<TParams, TIn, TOut> {\n static override readonly configSchemas: Schema[] = [...super.configSchemas, IndexedDbBoundWitnessDivinerConfigSchema]\n static override readonly defaultConfigSchema: Schema = IndexedDbBoundWitnessDivinerConfigSchema\n\n /**\n * The database name. If not supplied via config, it defaults\n * to the archivist's name and if archivist's name is not supplied,\n * it defaults to `archivist`. This behavior\n * biases towards a single, isolated DB per archivist which seems to\n * make the most sense for 99% of use cases.\n */\n get dbName() {\n return this.config?.dbName ?? this.config?.archivist ?? IndexedDbArchivist.defaultDbName\n }\n\n /**\n * The database version. If not supplied via config, it defaults to the archivist default version.\n */\n get dbVersion() {\n return this.config?.dbVersion ?? IndexedDbArchivist.defaultDbVersion\n }\n\n /**\n * The name of the object store. If not supplied via config, it defaults\n * to `payloads`.\n */\n get storeName() {\n return this.config?.storeName ?? IndexedDbArchivist.defaultStoreName\n }\n\n protected override async divineHandler(payloads?: TIn[]): Promise<TOut[]> {\n const query = payloads?.find(isBoundWitnessDivinerQueryPayload)\n if (!query) return []\n const result = await this.tryUseDb(async (db) => {\n const {\n addresses, payload_hashes, payload_schemas, limit, cursor, order,\n } = query\n const tx = db.transaction(this.storeName, 'readonly')\n const store = tx.objectStore(this.storeName)\n const results: TOut[] = []\n const parsedCursor = cursor\n const parsedLimit = limit ?? 10\n const valueFilters: ValueFilter[] = [\n isBoundWitness,\n bwValueFilter('addresses', addresses),\n bwValueFilter('payload_hashes', payload_hashes),\n bwValueFilter('payload_schemas', payload_schemas),\n ].filter(exists)\n const direction: IDBCursorDirection = order === 'desc' ? 'prev' : 'next'\n\n // Iterate all records using the sequence index\n const sequenceIndex = assertEx(store.index(IndexedDbArchivist.sequenceIndexName), () => 'Failed to get sequence index')\n let dbCursor: IDBPCursorWithValue<BoundWitnessStore, [string], string, string, 'readonly'> | null\n = await sequenceIndex.openCursor(null, direction)\n\n // If a cursor was supplied\n if (parsedCursor !== undefined) {\n let currentSequence: Sequence | undefined\n // Skip records until the supplied cursor offset is reached\n while (dbCursor && currentSequence !== parsedCursor) {\n // Find the sequence of the current record\n const current: WithStorageMeta<BoundWitness> = dbCursor.value\n currentSequence = current?._sequence\n // Advance one record beyond the cursor\n dbCursor = await dbCursor.advance(1)\n }\n }\n\n // Collect results up to the limit\n while (dbCursor && results.length < parsedLimit) {\n const value = dbCursor.value\n if (value) {\n // If we're filtering on more than just the schema\n if (valueFilters.length > 0) {\n // Ensure all filters pass\n if (valueFilters.every(filter => filter(value))) {\n // Then save the value\n results.push(value)\n }\n } else {\n // Otherwise just save the value\n results.push(value)\n }\n }\n try {\n dbCursor = await dbCursor.continue()\n } catch {\n break\n }\n }\n await tx.done\n // Remove any metadata before returning to the client\n return results\n })\n return result ?? []\n }\n\n protected override async startHandler() {\n await super.startHandler()\n // Do not eager initialize the DB here. It will cause the\n // DB to be created by this process and then the DB will be\n // in a bad state for other processes that need to create the DB.\n }\n\n /**\n * Checks that the desired DB/objectStore exists and is initialized to the correct version\n * @returns The initialized DB or undefined if it does not exist in the desired state\n */\n private async tryGetInitializedDb(): Promise<IDBPDatabase<BoundWitnessStore> | undefined> {\n // Enumerate the DBs\n const dbs = await indexedDB.databases()\n // Check that the DB exists at the desired version\n const dbExists = dbs.some((db) => {\n return db.name === this.dbName\n })\n // If the DB exists at the desired version\n if (dbExists) {\n // If the db does exist, open it\n const db = await openDB<BoundWitnessStore>(this.dbName)\n // Check that the desired objectStore exists\n const storeExists = db.objectStoreNames.contains(this.storeName)\n // If the correct db/version/objectStore exists\n if (storeExists) {\n return db\n } else {\n // Otherwise close the db so the process that is going to update the\n // db can open it\n db.close()\n }\n }\n }\n\n /**\n * Executes a callback with the initialized DB and then closes the db\n * @param callback The method to execute with the initialized DB\n * @returns\n */\n private async tryUseDb<T>(callback: (db: IDBPDatabase<BoundWitnessStore>) => Promise<T> | T): Promise<T | undefined> {\n // Get the initialized DB\n const db = await this.tryGetInitializedDb()\n if (db) {\n try {\n // Perform the callback\n return await callback(db)\n } finally {\n // Close the DB\n db.close()\n }\n }\n return undefined\n }\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xyo-network/diviner-boundwitness-indexeddb",
3
- "version": "5.1.22",
3
+ "version": "5.1.24",
4
4
  "description": "Primary SDK for using XYO Protocol 2.0",
5
5
  "homepage": "https://xyo.network",
6
6
  "bugs": {
@@ -30,34 +30,37 @@
30
30
  "types": "dist/browser/index.d.ts",
31
31
  "files": [
32
32
  "dist",
33
- "src"
33
+ "src",
34
+ "!**/*.bench.*",
35
+ "!**/*.spec.*",
36
+ "!**/*.test.*"
34
37
  ],
35
38
  "dependencies": {
36
- "@xylabs/array": "~5.0.24",
37
- "@xylabs/assert": "~5.0.24",
38
- "@xylabs/exists": "~5.0.24",
39
- "@xyo-network/archivist-indexeddb": "~5.1.22",
40
- "@xyo-network/archivist-model": "~5.1.22",
41
- "@xyo-network/boundwitness-model": "~5.1.22",
42
- "@xyo-network/diviner-boundwitness-abstract": "~5.1.22",
43
- "@xyo-network/diviner-boundwitness-model": "~5.1.22",
44
- "@xyo-network/diviner-model": "~5.1.22",
45
- "@xyo-network/module-model": "~5.1.22",
46
- "@xyo-network/payload-model": "~5.1.22",
39
+ "@xylabs/array": "~5.0.37",
40
+ "@xylabs/assert": "~5.0.37",
41
+ "@xylabs/exists": "~5.0.37",
42
+ "@xyo-network/archivist-indexeddb": "~5.1.24",
43
+ "@xyo-network/archivist-model": "~5.1.24",
44
+ "@xyo-network/boundwitness-model": "~5.1.24",
45
+ "@xyo-network/diviner-boundwitness-abstract": "~5.1.24",
46
+ "@xyo-network/diviner-boundwitness-model": "~5.1.24",
47
+ "@xyo-network/diviner-model": "~5.1.24",
48
+ "@xyo-network/module-model": "~5.1.24",
49
+ "@xyo-network/payload-model": "~5.1.24",
47
50
  "idb": "~8.0.3"
48
51
  },
49
52
  "devDependencies": {
50
- "@xylabs/delay": "~5.0.24",
53
+ "@xylabs/delay": "~5.0.37",
51
54
  "@xylabs/ts-scripts-yarn3": "~7.2.8",
52
55
  "@xylabs/tsconfig": "~7.2.8",
53
- "@xylabs/vitest-extended": "~5.0.24",
54
- "@xyo-network/archivist-indexeddb": "~5.1.22",
55
- "@xyo-network/boundwitness-builder": "~5.1.22",
56
- "@xyo-network/node-memory": "~5.1.22",
57
- "@xyo-network/payload-builder": "~5.1.22",
56
+ "@xylabs/vitest-extended": "~5.0.37",
57
+ "@xyo-network/archivist-indexeddb": "~5.1.24",
58
+ "@xyo-network/boundwitness-builder": "~5.1.24",
59
+ "@xyo-network/node-memory": "~5.1.24",
60
+ "@xyo-network/payload-builder": "~5.1.24",
58
61
  "fake-indexeddb": "~6.2.5",
59
62
  "typescript": "~5.9.3",
60
- "vitest": "~4.0.8"
63
+ "vitest": "~4.0.10"
61
64
  },
62
65
  "publishConfig": {
63
66
  "access": "public"
package/src/Diviner.ts CHANGED
@@ -138,7 +138,7 @@ export class IndexedDbBoundWitnessDiviner<
138
138
 
139
139
  protected override async startHandler() {
140
140
  await super.startHandler()
141
- // NOTE: Do not eager initialize the DB here. It will cause the
141
+ // Do not eager initialize the DB here. It will cause the
142
142
  // DB to be created by this process and then the DB will be
143
143
  // in a bad state for other processes that need to create the DB.
144
144
  }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=Diviner.Error.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Diviner.Error.spec.d.ts","sourceRoot":"","sources":["../../../src/spec/Diviner.Error.spec.ts"],"names":[],"mappings":""}
@@ -1,2 +0,0 @@
1
- import '@xylabs/vitest-extended';
2
- //# sourceMappingURL=Diviner.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Diviner.spec.d.ts","sourceRoot":"","sources":["../../../src/spec/Diviner.spec.ts"],"names":[],"mappings":"AAAA,OAAO,yBAAyB,CAAA"}
@@ -1,118 +0,0 @@
1
- import { IndexedDbArchivist } from '@xyo-network/archivist-indexeddb'
2
- import { BoundWitnessBuilder } from '@xyo-network/boundwitness-builder'
3
- import type { BoundWitness } from '@xyo-network/boundwitness-model'
4
- import { BoundWitnessDivinerQuerySchema } from '@xyo-network/diviner-boundwitness-model'
5
- import { MemoryNode } from '@xyo-network/node-memory'
6
- import { PayloadBuilder } from '@xyo-network/payload-builder'
7
- import {
8
- IDBCursor,
9
- IDBCursorWithValue,
10
- IDBDatabase,
11
- IDBFactory,
12
- IDBIndex,
13
- IDBKeyRange,
14
- IDBObjectStore,
15
- IDBOpenDBRequest,
16
- IDBRequest,
17
- IDBTransaction,
18
- IDBVersionChangeEvent,
19
- indexedDB,
20
- } from 'fake-indexeddb'
21
- import {
22
- beforeAll, describe, expect, it,
23
- } from 'vitest'
24
-
25
- import { IndexedDbBoundWitnessDiviner } from '../Diviner.ts'
26
-
27
- // Augment window with prototypes to ensure instance of comparisons work
28
- globalThis.IDBCursor = IDBCursor
29
- globalThis.IDBCursorWithValue = IDBCursorWithValue
30
- globalThis.IDBDatabase = IDBDatabase
31
- globalThis.IDBFactory = IDBFactory
32
- globalThis.IDBIndex = IDBIndex
33
- globalThis.IDBKeyRange = IDBKeyRange
34
- globalThis.IDBObjectStore = IDBObjectStore
35
- globalThis.IDBOpenDBRequest = IDBOpenDBRequest
36
- globalThis.IDBRequest = IDBRequest
37
- globalThis.IDBTransaction = IDBTransaction
38
- globalThis.IDBVersionChangeEvent = IDBVersionChangeEvent
39
- globalThis.indexedDB = indexedDB
40
-
41
- /**
42
- * @group module
43
- * @group diviner
44
- */
45
- describe('IndexedDbBoundWitnessDiviner.Errors', () => {
46
- const dbName = 'testDb'
47
- const storeName = 'testStore'
48
- const values: BoundWitness[] = []
49
- let archivist: IndexedDbArchivist
50
- describe('divine', () => {
51
- const createTestNode = async (testDbName = 'INCORRECT-DB-NAME', testStoreName = 'INCORRECT-STORE-NAME') => {
52
- const sut = await IndexedDbBoundWitnessDiviner.create({
53
- account: 'random',
54
- config: {
55
- archivist: archivist.address,
56
- dbName: testDbName,
57
- schema: IndexedDbBoundWitnessDiviner.defaultConfigSchema,
58
- storeName: testStoreName,
59
- },
60
- })
61
- const node = await MemoryNode.create({
62
- account: 'random',
63
- config: { schema: MemoryNode.defaultConfigSchema },
64
- })
65
- const modules = [archivist, sut]
66
- await node.start()
67
- await Promise.all(
68
- modules.map(async (mod) => {
69
- await node.register(mod)
70
- await node.attach(mod.address, true)
71
- }),
72
- )
73
- return sut
74
- }
75
- beforeAll(async () => {
76
- archivist = await IndexedDbArchivist.create({
77
- account: 'random',
78
- config: {
79
- dbName, schema: IndexedDbArchivist.defaultConfigSchema, storeName,
80
- },
81
- })
82
- const [bw] = await new BoundWitnessBuilder().build()
83
- values.push(bw)
84
- await archivist.insert(values)
85
- })
86
- describe('when DB and store do not exist', () => {
87
- let sut: IndexedDbBoundWitnessDiviner
88
- beforeAll(async () => {
89
- sut = await createTestNode('INCORRECT-DB-NAME', 'INCORRECT-STORE-NAME')
90
- })
91
- it('returns empty array', async () => {
92
- const result = await sut.divine([{ schema: BoundWitnessDivinerQuerySchema }])
93
- expect(result).toEqual([])
94
- })
95
- })
96
- describe('when DB exists but store does not exist', () => {
97
- let sut: IndexedDbBoundWitnessDiviner
98
- beforeAll(async () => {
99
- sut = await createTestNode(dbName, 'INCORRECT-STORE-NAME')
100
- })
101
- it('returns empty array', async () => {
102
- const result = await sut.divine([{ schema: BoundWitnessDivinerQuerySchema }])
103
- expect(result).toEqual([])
104
- })
105
- })
106
- describe('when DB and store exist', () => {
107
- let sut: IndexedDbBoundWitnessDiviner
108
- beforeAll(async () => {
109
- sut = await createTestNode(dbName, storeName)
110
- })
111
- it('returns values', async () => {
112
- const result = await sut.divine([{ schema: BoundWitnessDivinerQuerySchema }])
113
- const filtered = PayloadBuilder.omitStorageMeta(result)
114
- expect(filtered).toEqual(values)
115
- })
116
- })
117
- })
118
- })
@@ -1,213 +0,0 @@
1
- import '@xylabs/vitest-extended'
2
-
3
- import { filterAs } from '@xylabs/array'
4
- import { delay } from '@xylabs/delay'
5
- import { IndexedDbArchivist } from '@xyo-network/archivist-indexeddb'
6
- import { BoundWitnessBuilder } from '@xyo-network/boundwitness-builder'
7
- import type { BoundWitness } from '@xyo-network/boundwitness-model'
8
- import { asOptionalBoundWitnessWithStorageMeta, isBoundWitness } from '@xyo-network/boundwitness-model'
9
- import type { BoundWitnessDivinerQueryPayload } from '@xyo-network/diviner-boundwitness-model'
10
- import { BoundWitnessDivinerQuerySchema } from '@xyo-network/diviner-boundwitness-model'
11
- import { MemoryNode } from '@xyo-network/node-memory'
12
- import { PayloadBuilder } from '@xyo-network/payload-builder'
13
- import type { WithStorageMeta } from '@xyo-network/payload-model'
14
- import {
15
- IDBCursor,
16
- IDBCursorWithValue,
17
- IDBDatabase,
18
- IDBFactory,
19
- IDBIndex,
20
- IDBKeyRange,
21
- IDBObjectStore,
22
- IDBOpenDBRequest,
23
- IDBRequest,
24
- IDBTransaction,
25
- IDBVersionChangeEvent,
26
- indexedDB,
27
- } from 'fake-indexeddb'
28
- import {
29
- beforeAll, describe, expect,
30
- it,
31
- } from 'vitest'
32
-
33
- import { IndexedDbBoundWitnessDiviner } from '../Diviner.ts'
34
-
35
- // Augment window with prototypes to ensure instance of comparisons work
36
- globalThis.IDBCursor = IDBCursor
37
- globalThis.IDBCursorWithValue = IDBCursorWithValue
38
- globalThis.IDBDatabase = IDBDatabase
39
- globalThis.IDBFactory = IDBFactory
40
- globalThis.IDBIndex = IDBIndex
41
- globalThis.IDBKeyRange = IDBKeyRange
42
- globalThis.IDBObjectStore = IDBObjectStore
43
- globalThis.IDBOpenDBRequest = IDBOpenDBRequest
44
- globalThis.IDBRequest = IDBRequest
45
- globalThis.IDBTransaction = IDBTransaction
46
- globalThis.IDBVersionChangeEvent = IDBVersionChangeEvent
47
- globalThis.indexedDB = indexedDB
48
-
49
- /**
50
- * @group module
51
- * @group diviner
52
- */
53
- describe('IndexedDbBoundWitnessDiviner', () => {
54
- const dbName = 'testDb'
55
- const storeName = 'testStore'
56
- let archivist: IndexedDbArchivist
57
- let sut: IndexedDbBoundWitnessDiviner
58
- let node: MemoryNode
59
- const payloadA = {
60
- schema: 'network.xyo.test',
61
- url: 'https://xyo.network',
62
- }
63
- const payloadB = {
64
- foo: ['bar', 'baz'],
65
- schema: 'network.xyo.debug',
66
- }
67
- const boundWitnesses: WithStorageMeta<BoundWitness>[] = []
68
- beforeAll(async () => {
69
- const [boundWitnessA] = await (new BoundWitnessBuilder().payloads([payloadA])).build()
70
- const [boundWitnessB] = await (new BoundWitnessBuilder().payloads([payloadB])).build()
71
- const [boundWitnessC] = await (new BoundWitnessBuilder().payloads([payloadA, payloadB])).build()
72
- archivist = await IndexedDbArchivist.create({
73
- account: 'random',
74
- config: {
75
- dbName, schema: IndexedDbArchivist.defaultConfigSchema, storeName,
76
- },
77
- })
78
- for (const [bw, payloads] of [
79
- [boundWitnessA, [payloadA]],
80
- [boundWitnessB, [payloadB]],
81
- [boundWitnessC, [payloadA, payloadB]],
82
- ] as const) {
83
- await delay(2)
84
- const inserted = await archivist.insert([bw, ...payloads])
85
- const bwWithStorageMeta = filterAs(inserted, asOptionalBoundWitnessWithStorageMeta)
86
- boundWitnesses.push(...bwWithStorageMeta)
87
- }
88
- sut = await IndexedDbBoundWitnessDiviner.create({
89
- account: 'random',
90
- config: {
91
- archivist: archivist.address,
92
- dbName,
93
- schema: IndexedDbBoundWitnessDiviner.defaultConfigSchema,
94
- storeName,
95
- },
96
- })
97
- node = await MemoryNode.create({
98
- account: 'random',
99
- config: { schema: MemoryNode.defaultConfigSchema },
100
- })
101
- const modules = [archivist, sut]
102
- await node.start()
103
- await Promise.all(
104
- modules.map(async (mod) => {
105
- await node.register(mod)
106
- await node.attach(mod.address, true)
107
- }),
108
- )
109
- })
110
- describe('with filter for', () => {
111
- describe('payload_schemas', () => {
112
- describe('single', () => {
113
- it.each(['network.xyo.test', 'network.xyo.debug'])(
114
- 'returns only bound witnesses with payload_schemas that contain the schema',
115
- async (schema) => {
116
- const payload_schemas = [schema]
117
- const query = new PayloadBuilder<BoundWitnessDivinerQueryPayload>({ schema: BoundWitnessDivinerQuerySchema })
118
- .fields({ payload_schemas })
119
- .build()
120
- const results = await sut.divine([query])
121
- expect(results.length).toBeGreaterThan(0)
122
- const bws = results.filter(isBoundWitness)
123
- expect(bws.length).toBeGreaterThan(0)
124
- for (const bw of bws) {
125
- expect(bw.payload_schemas).toIncludeAllMembers(payload_schemas)
126
- }
127
- },
128
- )
129
- })
130
- describe('multiple', () => {
131
- it.each([
132
- ['network.xyo.test', 'network.xyo.debug'],
133
- ['network.xyo.test', 'network.xyo.debug'],
134
- ])('returns only bound witnesses with payload_schemas that contain the all the schemas', async (...payload_schemas) => {
135
- const query = new PayloadBuilder<BoundWitnessDivinerQueryPayload>({ schema: BoundWitnessDivinerQuerySchema })
136
- .fields({ payload_schemas })
137
- .build()
138
- const results = await sut.divine([query])
139
- expect(results.length).toBeGreaterThan(0)
140
- const bws = results.filter(isBoundWitness)
141
- expect(bws.length).toBeGreaterThan(0)
142
- for (const bw of bws) {
143
- expect(bw.payload_schemas).toIncludeAllMembers(payload_schemas)
144
- }
145
- })
146
- })
147
- })
148
- })
149
- describe('with order', () => {
150
- describe('not set', () => {
151
- it('returns payloads in ascending order', async () => {
152
- const query = new PayloadBuilder<BoundWitnessDivinerQueryPayload>({ schema: BoundWitnessDivinerQuerySchema }).build()
153
- const results = await sut.divine([query])
154
- expect(results).toEqual(boundWitnesses)
155
- })
156
- })
157
- describe('asc', () => {
158
- it('returns payloads in ascending order', async () => {
159
- const query = new PayloadBuilder<BoundWitnessDivinerQueryPayload>({ schema: BoundWitnessDivinerQuerySchema })
160
- .fields({ order: 'asc' })
161
- .build()
162
- const results = await sut.divine([query])
163
- expect(results).toEqual(boundWitnesses)
164
- })
165
- })
166
- describe('desc', () => {
167
- it('returns payloads in descending order', async () => {
168
- const query = new PayloadBuilder<BoundWitnessDivinerQueryPayload>({ schema: BoundWitnessDivinerQuerySchema })
169
- .fields({ order: 'desc' })
170
- .build()
171
- const results = await sut.divine([query])
172
- expect(results).toEqual([...boundWitnesses].toReversed())
173
- })
174
- })
175
- })
176
- describe('with cursor', () => {
177
- describe('when ascending order', () => {
178
- it('returns payloads from the beginning', async () => {
179
- const iterator = boundWitnesses.entries()
180
- iterator.next()
181
- for (const [i, boundWitness] of iterator) {
182
- const query = new PayloadBuilder<BoundWitnessDivinerQueryPayload>({ schema: BoundWitnessDivinerQuerySchema })
183
- .fields({
184
- limit: 1, cursor: boundWitnesses[i - 1]._sequence, order: 'asc',
185
- })
186
- .build()
187
- const results = await sut.divine([query])
188
- expect(results).toBeArrayOfSize(1)
189
- const [result] = results
190
- expect(PayloadBuilder.omitMeta(result)).toEqual(PayloadBuilder.omitMeta(boundWitness))
191
- }
192
- })
193
- })
194
- describe('when descending order', () => {
195
- it('returns payloads from the end', async () => {
196
- const descendingBoundWitnesses = [...boundWitnesses].toReversed()
197
- const iterator = [...descendingBoundWitnesses.entries()][Symbol.iterator]()
198
- iterator.next()
199
- for (const [i, boundWitness] of iterator) {
200
- const query = new PayloadBuilder<BoundWitnessDivinerQueryPayload>({ schema: BoundWitnessDivinerQuerySchema })
201
- .fields({
202
- limit: 1, cursor: descendingBoundWitnesses[i - 1]._sequence, order: 'desc',
203
- })
204
- .build()
205
- const results = await sut.divine([query])
206
- expect(results).toBeArrayOfSize(1)
207
- const [result] = results
208
- expect(PayloadBuilder.omitMeta(result)).toEqual(PayloadBuilder.omitMeta(boundWitness))
209
- }
210
- })
211
- })
212
- })
213
- })