Four variants of the same sync library (IndexedDB, NeDB, SQLite WASM, sql.js) plus a paste-bin demo app for testing multi-browser sync via shared folders. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
65 lines
2.3 KiB
TypeScript
65 lines
2.3 KiB
TypeScript
import type { CollectionApi, IndexDefinition, IndexRange, StoreOptions } from './types.js';
|
|
import type { SqlJsStore } from './sqljs-store.js';
|
|
import type { SyncEngine } from './sync-engine.js';
|
|
|
|
export class Collection<T extends { id: string }> implements CollectionApi<T> {
|
|
private readonly storeName: string;
|
|
private readonly indexes: IndexDefinition<T>[];
|
|
private indexesBuilt = false;
|
|
|
|
constructor(options: StoreOptions<T>, private store: SqlJsStore, private sync: SyncEngine) {
|
|
this.storeName = options.name;
|
|
this.indexes = options.indexes ?? [];
|
|
this.sync.registerIndexes(this.storeName, this.indexes as IndexDefinition[]);
|
|
}
|
|
|
|
private async ensureIndexes(): Promise<void> {
|
|
if (this.indexesBuilt || this.indexes.length === 0) return;
|
|
await this.store.rebuildIndexes(this.storeName, this.indexes as IndexDefinition[]);
|
|
this.indexesBuilt = true;
|
|
}
|
|
|
|
async get(id: string): Promise<T | undefined> {
|
|
const rec = await this.store.getDoc(this.storeName, id);
|
|
return rec ? (rec.data as T) : undefined;
|
|
}
|
|
|
|
async put(doc: T): Promise<void> {
|
|
await this.ensureIndexes();
|
|
const existing = await this.store.getRawDoc(this.storeName, doc.id);
|
|
await this.sync.writeDoc(this.storeName, doc.id, doc, Date.now(), (existing?.rev ?? 0) + 1);
|
|
}
|
|
|
|
async delete(id: string): Promise<void> {
|
|
await this.ensureIndexes();
|
|
const existing = await this.store.getRawDoc(this.storeName, id);
|
|
if (!existing || existing.deleted) return;
|
|
await this.sync.deleteDocEvent(this.storeName, id, Date.now(), existing.rev + 1);
|
|
}
|
|
|
|
async all(): Promise<T[]> {
|
|
return (await this.store.getAllDocs(this.storeName)).map((d) => d.data as T);
|
|
}
|
|
|
|
async findByIndex(indexName: string, value: unknown): Promise<T[]> {
|
|
await this.ensureIndexes();
|
|
const ids = await this.store.findByIndex(this.storeName, indexName, value);
|
|
return this.fetchByIds(ids);
|
|
}
|
|
|
|
async queryByIndex(indexName: string, range: IndexRange): Promise<T[]> {
|
|
await this.ensureIndexes();
|
|
const ids = await this.store.queryByIndex(this.storeName, indexName, range);
|
|
return this.fetchByIds(ids);
|
|
}
|
|
|
|
private async fetchByIds(ids: string[]): Promise<T[]> {
|
|
const results: T[] = [];
|
|
for (const id of ids) {
|
|
const doc = await this.store.getDoc(this.storeName, id);
|
|
if (doc) results.push(doc.data as T);
|
|
}
|
|
return results;
|
|
}
|
|
}
|