- IndexedDB data layer: db.ts, items.ts, locations.ts, sightings.ts, labels.ts - Pure algorithms: confidence decay, custody state transitions - Barcode parser: HTTPS URI, haus:// scheme, raw ID parsing - 150 tests all passing Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
109 lines
2.6 KiB
TypeScript
109 lines
2.6 KiB
TypeScript
import { openDB, type IDBPDatabase, type DBSchema } from 'idb';
|
|
|
|
interface SolidHausDB extends DBSchema {
|
|
items: {
|
|
key: string;
|
|
value: import('$lib/types').Item;
|
|
indexes: {
|
|
'by-name': string;
|
|
'by-category': string;
|
|
'by-location': string;
|
|
'by-type': string;
|
|
'by-custody': string;
|
|
};
|
|
};
|
|
locations: {
|
|
key: string;
|
|
value: import('$lib/types').Location;
|
|
indexes: {
|
|
'by-parent': string;
|
|
'by-name': string;
|
|
};
|
|
};
|
|
sightings: {
|
|
key: string;
|
|
value: import('$lib/types').Sighting;
|
|
indexes: {
|
|
'by-item': string;
|
|
'by-location': string;
|
|
'by-timestamp': string;
|
|
};
|
|
};
|
|
photos: {
|
|
key: string;
|
|
value: import('$lib/types').Photo;
|
|
indexes: {
|
|
'by-item': string;
|
|
};
|
|
};
|
|
preGeneratedIds: {
|
|
key: string;
|
|
value: import('$lib/types').PreGeneratedId;
|
|
indexes: {
|
|
'by-batch': string;
|
|
'by-assigned': string;
|
|
};
|
|
};
|
|
settings: {
|
|
key: string;
|
|
value: {
|
|
key: string;
|
|
value: unknown;
|
|
};
|
|
};
|
|
}
|
|
|
|
export type { SolidHausDB };
|
|
|
|
const DB_NAME = 'solidhaus';
|
|
const DB_VERSION = 1;
|
|
|
|
let dbPromise: Promise<IDBPDatabase<SolidHausDB>> | null = null;
|
|
|
|
export function getDB(): Promise<IDBPDatabase<SolidHausDB>> {
|
|
if (!dbPromise) {
|
|
dbPromise = openDB<SolidHausDB>(DB_NAME, DB_VERSION, {
|
|
upgrade(db) {
|
|
// Items
|
|
const itemStore = db.createObjectStore('items', { keyPath: 'shortId' });
|
|
itemStore.createIndex('by-name', 'name');
|
|
itemStore.createIndex('by-category', 'category');
|
|
itemStore.createIndex('by-location', 'lastSeenAt');
|
|
itemStore.createIndex('by-type', 'itemType');
|
|
itemStore.createIndex('by-custody', 'custodyState');
|
|
|
|
// Locations
|
|
const locStore = db.createObjectStore('locations', { keyPath: 'id' });
|
|
locStore.createIndex('by-parent', 'parentId');
|
|
locStore.createIndex('by-name', 'name');
|
|
|
|
// Sightings
|
|
const sightStore = db.createObjectStore('sightings', { keyPath: 'id' });
|
|
sightStore.createIndex('by-item', 'itemId');
|
|
sightStore.createIndex('by-location', 'locationId');
|
|
sightStore.createIndex('by-timestamp', 'timestamp');
|
|
|
|
// Photos
|
|
const photoStore = db.createObjectStore('photos', { keyPath: 'id' });
|
|
photoStore.createIndex('by-item', 'itemId');
|
|
|
|
// Pre-generated IDs
|
|
const pregenStore = db.createObjectStore('preGeneratedIds', { keyPath: 'id' });
|
|
pregenStore.createIndex('by-batch', 'batchId');
|
|
pregenStore.createIndex('by-assigned', 'assignedTo');
|
|
|
|
// Settings
|
|
db.createObjectStore('settings', { keyPath: 'key' });
|
|
},
|
|
});
|
|
}
|
|
return dbPromise;
|
|
}
|
|
|
|
export async function resetDBPromise(): Promise<void> {
|
|
if (dbPromise) {
|
|
const db = await dbPromise;
|
|
db.close();
|
|
dbPromise = null;
|
|
}
|
|
}
|