Declaring a database
A doxor database is a name and a set of collections. Each collection is an IndexedDB object store, declared with collection<T>(): the record type, an optional key property and the indexes you want to query by.
import { collection, createDB } from 'doxor.js'
type User = { id: number; name: string; email: string; age: number; tags: string[] }
type Note = { slug: string; userId: number; body: string }
type Setting = { value: string }
export const db = createDB({
name: 'app',
collections: {
// Auto-generated numeric keys: `id` is optional on insert.
users: collection<User>()
.key('id', { autoIncrement: true })
.index('email', { unique: true }) // rejects duplicates
.index('name')
.index('age')
.index('tags', { multiEntry: true }), // query arrays by element
// A key you provide yourself.
notes: collection<Note>().key('slug').index('userId'),
// No key property: pass the key separately (a key-value store).
settings: collection<Setting>(),
},
})Keys
| Declaration | The key is | On insert |
|---|---|---|
.key('id', { autoIncrement: true }) | The id property, generated by IndexedDB | id is optional |
.key('slug') | The slug property, provided by you | slug is required |
no .key() | Stored separately from the value | Pass it as the second argument |
Indexes
.index(property) makes a property queryable with where(). Two options change how it behaves:
unique: truerejects a write whose value already exists in the index, with the error codeConstraint.multiEntry: trueindexes each element of an array property, sowhere('tags').equals('admin')finds every record whosetagscontains'admin'.
Index names are checked by the compiler. db.users.where('agee') is a type error, not a runtime surprise.
When the database opens
createDB() does not touch IndexedDB. The database is opened on the first operation, or when you call await db.ready() to surface errors early. That makes it safe to create at module level, including in code that also runs on the server (see SSR, frameworks and tests).
Create one instance per database and share it. When you change the declaration later, doxor upgrades the database on the next load: see Schema changes and migrations.