dexie-typed-query
v1.0.1
Published
A type-safe query interface for Dexie
Maintainers
Readme
Dexie Typed Query
Dexie is great, but its TypeScript support and query interface leave something to be desired.
This project aims to alleviate this by offering a lightweight, type-safe query wrapper.
Introduction
Example
With vanilla Dexie:
const query = await db.users.where('name')
.startsWith('T')
.and(u => u.createdAt < new Date())
.reverse()
.sortBy('createdAt')
const result = query.slice(10, 20)With dexie-typed-query:
const result = await typedQuery(db.users).where({
and: [{
name: { startsWith: 'T' },
}, {
createdAt: { below: new Date() },
}],
}, { offset: 10, limit: 10, orderBy: { createdAt: 'desc' } })Features
- Declarative query interface: Replace complex method chains with a single, readable query object.
- Simplified Pagination: Specify offsets and limits for your queries.
- Easy Adoption: Drop it into an existing Dexie project without refactoring your entire database layer.
- Deep Type Safety:
- Property-aware operators: Only see operators that make sense for your data type (e.g., no
startsWithon numbers/dates). - Validated condition values: The type system takes into account both the property type and the selected operator. For example, using
betweenon a date property will require a tuple of dates.
- Property-aware operators: Only see operators that make sense for your data type (e.g., no
- Lightweight: Zero dependencies (only a peer dependency on Dexie).
- Production Ready: 100% test coverage.
Caveats
This is not a complete replacement for Dexie. It should work for most everyday queries, but you may still need to use vanilla Dexie for more advanced queries.
Installation
Requirements: dexie@^4.0.0
npm install dexie-typed-queryUsage
Note: This assumes you are using TypeScript to define your Dexie table interfaces.
Basic Querying
import { typedQuery } from 'dexie-typed-query'
const query = typedQuery(db.someTable)
const result = await query.where({ someField: { equals: 'test' } })Note: The queried field must be an indexed field. If a non-indexed field is used, Dexie will throw an error.
Query Options
An optional QueryOptions object can be passed as the second argument to the where function to handle pagination (offset, limit) and sorting (orderBy, ascending or descending).
const result = await typedQuery(db.someTable).where({
someField: { equals: 'test' }
}, { offset: 5, limit 5, orderBy: { createdAt: 'desc' } })Retrieving All
Retreive all objects in a table by calling the all function.
await typedQuery(db.someTable).all()Also accepts an optional query options object, e.g.:
await typedQuery(db.someTable).all({ orderBy: { createdAt: 'desc' } })Note: The orderBy field must be an indexed field. If a non-indexed field is used, Dexie will throw an error.
ANDing
Multiple query objects can be ANDed together.
const result = await typedQuery(db.users).where({
and: [{
name: { startsWith: 'T' },
}, {
createdAt: { below: new Date() },
}],
})Note: The first query object must be for an indexed field. If a non-indexed field is used, Dexie will throw an error. Under the hood, all subsequent query objects will use Dexie's filter function.
ORing
Multiple query objects can be ORed together.
const result = await typedQuery(db.users).where({
or: [{
createdAt: { below: new Date('03/01/2026') },
}, {
name: { startsWith: 'Test' },
}],
})Note: Each query object must be for an indexed field. If a non-indexed field is used, Dexie will throw an error.
Available Operators
| Operator | Description | Supported Types |
| ------------ | --------------------------------------------------- | --------------- |
| above | Selects items where the field value is above the given lower bound | number, Date |
| aboveOrEqual | Selects items where the field value is above or equal to the given lower bound | number, Date |
| anyOf | Selects items where the field value contains any of the given values | string, number, Date, array of string/number/Date |
| anyOfIgnoreCase | Selects items where the field value contains any of the given values, ignoring case | string |
| below | Selects items where the field value is below the given upper bound | number, Date |
| belowOrEqual | Selects items where the field value is below or equal to the given upper bound | number, Date |
| between | Selects items where the field value is between the given lower and upper bounds, not including the lower and upper bounds | number, Date |
| betweenIncludeLower | Selects items where the field value is between the given lower and upper bounds, including the lower bound and excluding the upper bound | number, Date |
| betweenIncludeLowerAndUpper | Selects items where the field value is between the given lower and upper bounds, including the lower and upper bound | number, Date |
| betweenIncludeUpper | Selects items where the field value is between the given lower and upper bounds, including the upper bound and excluding the lower bound | number, Date |
| equals | Selects items where the field value is equal to the given value | string, number, Date, array of string/number/Date |
| equalsIgnoreCase | Selects items where the field value is equal to the given value, ignoring case | string |
| noneOf | Selects items where the field value is NOT equal to the given value | string, number, Date, array of string/number/Date |
| startsWith | Selects items where the field value starts with the given prefix | string |
| startsWithIgnoreCase | Selects items where the field value starts with the given prefix, ignoring case | string |
License
This project is licensed under the MIT License - see the LICENSE file for details
