Rescript bindings to the easy-to-use Dexie wrapper of IndexedDB.
These bindings are not complete, but everything required for basic IndexedDB access should be working, including:
- Define fully typed table schemas
- Version and upgrade schemas
- Create, update, delete records (including bulk operations)
- Query by index
- Query using criteria
- Query using where clauses
- Perform operations on the resulting Collections
- Execute inside Transactions
- React live queries (optional, with
dexie-react-hooks
installed)
Some of the more complex pieces of Dexie are missing from these bindings:
- Translation of Dexie's JS error types into a Rescript-friendly paradigm
- Dexie Hooks API or DBCore Middleware
- Syncables
- Addons, including Dexie Cloud
A couple things I haven't tested yet:
- Not sure if things like compound primary keys are working
- Probably schema upgrades will get confused when dealing with 'before' and 'after' types
Start by defining a small module for each table in your database, that
describes the type of the id
field, the structure of each record, and
the name of the table:
module FriendSchema = {
type id = int
type t = {
id: option<int>,
name: string,
color: [#Blue | #Red | #Purple],
}
let tableName = "friends"
}
Use the MakeTable
functor to create a table for each schema:
module Friend = Dexie.Table.MakeTable(FriendSchema)
Construct a Dexie instance with the IndexedDB name:
let dexie = Dexie.Database.make(`hello dexie ${someNumber}`)
Describe the Dexie schema for
each of your tables using an array of (name, schema)
tuples:
let schema = [("friends", "++id,name,birthdate,color"), ...]
Create your initial version of the database and open it:
dexie
->Dexie.Database.version(1)
->Dexie.Version.stores(schema)
->ignore
dexie->Dexie.Database.opendb->ignore
Add and query your tables using the module you created with the
MakeTable
functor. Note that most functions return promises so you'll
want to use async and await syntax.
Some things you can do:
dexie->Friend.bulkPut([
{id: Some(1), name: "Chris", color: #Red},
{id: Some(2), name: "Leroy", color: #Blue},
{id: Some(3), name: "Jerome", color: #Purple},
{id: Some(4), name: "Betty", color: #Purple},
])
dexie->Friend.add(None, name: "Xiao", color: #Blue)
dexie->Friend.getById(3)->Promise.then(friendOption => ...)
dexie
->Friend.where("name")
->Dexie.Where.anyOfIgnoreCase(["Leroy", "Xiao"])
->Dexie.Collection.first
->Promise.then(friend=> ...)
React live query
hooks are also supported if you yarn add dexie-react-hooks
:
let teamBlue = Dexie.LiveQuery.use0(() => {
dexie->Friend.findByCriteria({color: #Blue})
})
There are hooks use0
through use7
that behave similarly to rescript-react's
useEffect
modelling.
I haven't documented this as thoroughly as I normally do in my projects. For the most part, follow Dexie's excellent documentation and assume the Rescript bindings are sane (or completely unavailable).
You can also refer to the unit tests to get a better idea of the things you can do with the bindings.
And there is a tiny React app in the examples/react folder.
PRs and issues are welcome!
I use my rescript-zora
library for testing. yarn test:watch
should be all you need.
This is for my reference:
- update the version in
bsconfig.json
- bump the version in
example/react
np