Skip to content

v0.5.0

Latest

Choose a tag to compare

@D34DPlayer D34DPlayer released this 20 Feb 01:27

Documentation
NPM
Full Changelog

Features

Arbitrary indices

Closes #36, closes #37, closes #12 and closes #13

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 init if called multiple times

Others

  • Typing improvements
  • Migrated to Vite for bundling the library
  • Migrated to Vitest for library testing