@fireproof/database
Advanced tools
Comparing version
{ | ||
"name": "@fireproof/database", | ||
"version": "0.10.10", | ||
"version": "0.10.11", | ||
"description": "Immutable embedded distributed database for the web", | ||
@@ -5,0 +5,0 @@ "main": "dist/fireproof.cjs", |
@@ -25,10 +25,6 @@ import { TransactionBlockstore, IndexBlockstore } from './transaction' | ||
}), | ||
this.indexBlocks.ready.then(async (header: IdxCarHeader) => { | ||
this.indexBlocks.ready.then((header: IdxCarHeader) => { | ||
if (header.indexes === undefined) return | ||
for (const [name, idx] of Object.entries(header.indexes)) { | ||
const idxM = idx as IdxMeta | ||
const ix = this.indexer_int(name, idxM.map) // todo eval | ||
ix.byId.cid = idxM.byId | ||
ix.byKey.cid = idxM.byKey | ||
ix.indexHead = idxM.head | ||
this.indexer(name, undefined, idx as IdxMeta) | ||
} | ||
@@ -58,3 +54,3 @@ }) | ||
async changes(since: ClockHead) { | ||
async changes(since: ClockHead = []) { | ||
await this.ready | ||
@@ -69,35 +65,19 @@ return await clockChangesSince(this.blocks, this._head, since) | ||
async indexer(name: string, mapFn?: MapFn | string): Promise<Indexer> { | ||
await this.ready | ||
return this.indexer_int(name, mapFn) | ||
} | ||
// async indexer(name: string, mapFn?: MapFn | string): Promise<Indexer> { | ||
// await this.ready | ||
// return this.indexer_int(name, mapFn) | ||
// } | ||
indexer_int(name: string, mapFn?: MapFn | string): Indexer { | ||
const idx = this.indexers.get(name) // maybe this should error if the mapfn is different | ||
if (idx) { | ||
if (!idx.mapFn && idx.mapFnString && mapFn) { | ||
if (mapFn.toString() !== idx.mapFnString) throw new Error('Indexer already registered with different map function') | ||
if (mapFn.constructor.name === 'Function') idx.mapFn = mapFn as MapFn | ||
} | ||
if (idx.mapFn && mapFn && idx.mapFn.toString() !== mapFn.toString()) throw new Error('Indexer already registered with different map function') | ||
return idx | ||
} | ||
const idx2 = new Indexer(this.indexBlocks, this, name, mapFn || name) | ||
this._registerIndexer(idx2) | ||
const indx = this.indexers.get(name) | ||
if (!indx) throw new Error('indexer not registered') | ||
return indx | ||
} | ||
_registerIndexer(indexer: Indexer) { | ||
if (!indexer.name) throw new Error('Indexer must have a name') | ||
if (this.indexers.has(indexer.name)) { | ||
const existing = this.indexers.get(indexer.name) | ||
if (existing?.mapFnString !== indexer.mapFnString) throw new Error(`Indexer ${indexer.name} already registered with different map function`) | ||
// the new indexer might have a car file, etc, so we need to merge them | ||
// throw new Error('todo merge indexers') | ||
indexer(name: string, mapFn?: MapFn, meta?: IdxMeta): Indexer { | ||
if (mapFn && meta) throw new Error('cannot provide both mapFn and meta') | ||
if (mapFn && mapFn.constructor.name !== 'Function') throw new Error('mapFn must be a function') | ||
if (this.indexers.has(name)) { | ||
const idx = this.indexers.get(name)! | ||
idx.applyMapFn(name, mapFn, meta) | ||
} else { | ||
this.indexers.set(indexer.name, indexer) | ||
const idx = new Indexer(this.indexBlocks, this, name, mapFn, meta) | ||
this.indexers.set(name, idx) | ||
} | ||
return this.indexers.get(name)! | ||
} | ||
} |
@@ -74,4 +74,4 @@ // @ts-ignore | ||
async index(name: string, mapFn?: MapFn) { | ||
return await this._crdt.indexer(name, mapFn) | ||
index(name: string, mapFn?: MapFn) { | ||
return this._crdt.indexer(name, mapFn) | ||
} | ||
@@ -78,0 +78,0 @@ |
@@ -159,15 +159,1 @@ import { Block } from 'multiformats' | ||
} | ||
export function makeName(mapFnString: string) { | ||
const regex = /\(([^,()]+,\s*[^,()]+|\[[^\]]+\],\s*[^,()]+)\)/g | ||
let matches: RegExpExecArray | null | string[] = Array.from(mapFnString.matchAll(regex), match => match[1].trim()) | ||
if (matches.length === 0) { | ||
matches = /=>\s*(.*)/.exec(mapFnString) | ||
} | ||
if (matches === null) { | ||
return mapFnString | ||
} else { | ||
// it's a consise arrow function, match everythign after the arrow | ||
return matches[1] | ||
} | ||
} |
import { ClockHead, DocUpdate, MapFn, IndexUpdate, QueryOpts, DocFragment, IdxMeta } from './types' | ||
import { IndexBlockstore } from './transaction' | ||
import { bulkIndex, indexEntriesForChanges, byIdOpts, byKeyOpts, IndexTree, applyQuery, encodeRange, encodeKey, makeName, loadIndex } from './indexer-helpers' | ||
import { bulkIndex, indexEntriesForChanges, byIdOpts, byKeyOpts, IndexTree, applyQuery, encodeRange, encodeKey, loadIndex } from './indexer-helpers' | ||
import { CRDT } from './crdt' | ||
function makeMapFnFromName(name: string): MapFn { | ||
return (doc) => { | ||
if (doc[name]) return doc[name] as DocFragment | ||
} | ||
} | ||
export class Indexer { | ||
@@ -14,28 +20,60 @@ blocks: IndexBlockstore | ||
byId = new IndexTree() | ||
indexHead: ClockHead = [] | ||
indexHead: ClockHead | undefined = undefined | ||
includeDocsDefault: boolean = false | ||
initError: Error | null = null | ||
constructor(blocks: IndexBlockstore, crdt: CRDT, name: string | null, mapFn: MapFn | string) { | ||
constructor(blocks: IndexBlockstore, crdt: CRDT, name: string, mapFn?: MapFn, meta?: IdxMeta) { | ||
this.blocks = blocks | ||
this.crdt = crdt | ||
this.applyMapFn(mapFn, name) | ||
this.applyMapFn(name, mapFn, meta) | ||
if (!(this.mapFnString || this.initError)) throw new Error('missing mapFnString') | ||
} | ||
applyMapFn(mapFn: MapFn | string, name: string | null) { | ||
if (typeof mapFn === 'string') { | ||
this.mapFnString = mapFn | ||
const regex = /^[a-zA-Z0-9 ]+$/ | ||
if (regex.test(mapFn)) { | ||
this.mapFn = (doc) => { | ||
if (doc[mapFn]) return doc[mapFn] as DocFragment | ||
applyMapFn(name: string, mapFn?: MapFn, meta?: IdxMeta) { | ||
if (mapFn && meta) throw new Error('cannot provide both mapFn and meta') | ||
if (this.name && this.name !== name) throw new Error('cannot change name') | ||
this.name = name | ||
try { | ||
if (meta) { | ||
// hydrating from header | ||
if (this.indexHead && | ||
this.indexHead.map(c => c.toString()).join() !== meta.head.map(c => c.toString()).join()) { | ||
throw new Error('cannot apply meta to existing index') | ||
} | ||
this.includeDocsDefault = true | ||
this.byId.cid = meta.byId | ||
this.byKey.cid = meta.byKey | ||
this.indexHead = meta.head | ||
if (this.mapFnString) { | ||
// we already initialized from application code | ||
if (this.mapFnString !== meta.map) throw new Error('cannot apply different mapFn meta') | ||
} else { | ||
// we are first | ||
this.mapFnString = meta.map | ||
} | ||
} else { | ||
if (this.mapFn) { | ||
// we already initialized from application code | ||
if (mapFn) { | ||
if (this.mapFn.toString() !== mapFn.toString()) throw new Error('cannot apply different mapFn app2') | ||
} | ||
} else { | ||
// application code is creating an index | ||
if (!mapFn) { | ||
mapFn = makeMapFnFromName(name) | ||
} | ||
if (this.mapFnString) { | ||
// we already loaded from a header | ||
if (this.mapFnString !== mapFn.toString()) throw new Error('cannot apply different mapFn app') | ||
} else { | ||
// we are first | ||
this.mapFnString = mapFn.toString() | ||
} | ||
this.mapFn = mapFn | ||
} | ||
} | ||
} else { | ||
this.mapFn = mapFn | ||
this.mapFnString = mapFn.toString() | ||
const matches = /=>\s*(.*)/.test(this.mapFnString) | ||
this.includeDocsDefault = matches | ||
} catch (e) { | ||
this.initError = e as Error | ||
} | ||
const matches = /=>\s*(.*)/.exec(this.mapFnString) | ||
this.includeDocsDefault = this.includeDocsDefault || !!(matches && matches.length > 0) | ||
this.name = name || makeName(this.mapFnString) | ||
} | ||
@@ -83,2 +121,3 @@ | ||
await this.crdt.ready | ||
if (this.initError) throw this.initError | ||
if (!this.mapFn) throw new Error('No map function defined') | ||
@@ -85,0 +124,0 @@ const { result, head } = await this.crdt.changes(this.indexHead) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
115570
0.01%10860504
0