Documentation
NPM
Full Changelog
Features
Arbitrary indices
Indexes are a feature of IndexedDB that allow for faster queries if used properly.
// 1st use case, multi-field ordering:
// An index can be created with multiple fields, when using that index the results will be ordered by the fields in the index.
@Table({
indexes: {
nameAge: {
fields: ['name', 'age'],
},
},
})
class Test extends Model {
id!: number
name!: string
age!: number
}
*
// The results will be ordered by name and then by age
await Test.withIndex('nameAge').all()
*
// 2nd use case, unique fields:
// An index can be created with the `unique` option, this will enforce that the field, or combination of fields is unique.
@Table({
indexes: {
uniqueName: { fields: ['firstName', 'lastName'], unique: true },
}
})
class Test2 extends Model {
id!: number
firstName!: string
lastName!: string
}
*
await Test2.create({ firstName: 'John', lastName: 'Doe', id: 1 })
// This will fail
await Test2.create({ firstName: 'John', lastName: 'Doe', id: 2 })
*
// 3rd use case, multi-field filtering:
// An index with multiple fields can also be used to speed up filtering.
@Table({
indexes: {
nameAge: {
fields: ['name', 'age'],
},
},
})
class Test3 extends Model {
id!: number
name!: string
age!: number
}
// Looking for people named John that are 30 years old
await Test3.withIndex('nameAge', Between(['John', 30], ['John', 30])).all()
// The alternative will only use the name index and check the age for each result
await Test3.filter({ name: 'John', age: 30 }).all()
// "Between" can also be used for ranges, eg. looking for people named John that are between 30 and 40 years old
await Test3.withIndex('nameAge', Between(['John', 30], ['John', 40])).all()
*
// 4th use case, filter + ordering:
// You can combine all this information and use the first field(s) for filtering and leaving the rest for ordering.
// Looking for people named John, ordered by age
await Test3.withIndex('nameAge', Between(['John', BetweenFilter.minKey], ['John', BetweenFilter.maxKey])).all()The Table decorator
As you may have noticed in the previous section, an extra decorator has been added to provide table metadata.
Currently this allows the following:
- Set the table name to something different than the class name
- Set wether a table is abstract or not (and override the auto-inferrence)
- Define extra indices
For non-decorator users, defineModel has been updated to allow for table metadata
defineModel<T extends Model>(
modelClass: Constructor<T>,
definition: TableDefinition,
options: TableOptions = {},
)BetweenFilter
Another feature paired with indices, they can be used to filter arbitrary indices, or used with the default single-field indices:
// Get all users with an age between 20 and 30
const query = User.filter({ age: new BetweenFilter(20, 30) })
// Get all users with an age between 20 and 30, excluding 20 and 30
const query = User.filter({ age: new BetweenFilter(20, 30, true, true) })Changes to Transaction
The signature of Transaction has changed from:
Transaction(IDBMode, callback)
To the new:
Transaction(IDBMode, Table[], callback)
This is to make explicit what tables are being targeted by the transaction, as those will be blocked until done.
Export/Import
W-ORM now comes with utility functions to export/import the data in the database:
exportTable(table: string): Promise<unknown[]>
importTable(
table: string,
entries: unknown[],
tx?: IDBTransaction,
): Promise<number>
exportDatabase(
blacklist: string[] = [],
): Promise<Record<string, unknown[]>>
importDatabase(
data: Record<string, unknown[]>,
): Promise<Record<string, number>>
exportDatabaseToBlob(blacklist?: string[]): Promise<Blob>LenientModel
To improve the DX and safety Model doesn't allow anymore extra fields, however since this is something IDB allows LenientModel was created with the exact same functionality and the extra typing to allow for extra fields.
Bug-fixes
- Auto-index shouldn't pick a field without an index
- Shortcut
initif called multiple times
Others
- Typing improvements
- Migrated to Vite for bundling the library
- Migrated to Vitest for library testing