Skip to content

v6.1.0

Choose a tag to compare

@jamesgpearce jamesgpearce released this 16 May 01:54
· 228 commits to main since this release

In Summary

And more!

Bun SQLite

This release includes a new Persister for the embedded SQLite database available in the Bun runtime.

You use it by passing a reference to a Bun Database object into the createSqliteBunPersister function:

import {Database} from 'bun:sqlite';
import {createStore} from 'tinybase';
import {createSqliteBunPersister} from 'tinybase/persisters/persister-sqlite-bun';

const db = new Database(':memory:');
const store = createStore().setTables({pets: {fido: {species: 'dog'}}});
const persister = createSqliteBunPersister(store, db, 'my_tinybase');

await persister.save();
// Store will be saved to the database.

console.log(db.query('SELECT * FROM my_tinybase;').all());
// -> [{_id: '_', store: '[{"pets":{"fido":{"species":"dog"}}},{}]'}]

db.query(
  'UPDATE my_tinybase SET store = ' +
    `'[{"pets":{"felix":{"species":"cat"}}},{}]' WHERE _id = '_';`,
).run();
await persister.load();
console.log(store.getTables());
// -> {pets: {felix: {species: 'cat'}}}

await persister.destroy();

There's more information the documentation for the new persister-sqlite-bun module.

Subset persistence

Persisters that load and save data to an underlying database can now be configured to only load a subset of the rows in a table into a Store.

This is useful for reducing the amount of data that is loaded into memory, or for working with a subset of data that is relevant to the current user, for example.

Do this by specifying a condition in the Persister configuration. This is a single string argument which is used as a SQL WHERE clause when reading and observing data in the table.

For example, the following code will only load rows from the pets database table where the sold column is set to 0:

const subsetPersister = createSqliteWasmPersister(store, sqlite3, db, {
  mode: 'tabular',
  tables: {
    load: {pets: {tableId: 'pets', condition: '$tableName.sold = 0'}},
    save: {pets: {tableName: 'pets', condition: '$tableName.sold = 0'}},
  },
});

See the 'Loading subsets of database tables' section of the Database Persistence guide for more details. And a huge thank you to Jakub Riedl (@jakubriedl) for landing this functionality!

Destructed object arguments for sorted Row Ids

The getSortedRowIds method on the Store interface has a number of optional parameters and it can be tiresome to fill in the defaults if you only want to change the last one, for example. So this release introduces an override such that you can pass an object with the parameters as properties.

So instead of:

store.getSortedRowIds('pets', undefined, undefined, undefined, 10);

You can now do:

store.getSortedRowIds({tableId: 'pets', limit: 10});

This pattern is also made available to the addSortedRowIdsListener method, the useSortedRowIds hook, and the useSortedRowIdsListener hook.

New startAutoPersisting method

The new startAutoPersisting method and stopAutoPersisting method on the Persister interface act as convenience methods for starting (and stopping) both the automatic loading and saving of data.

New createMergeableStore getNow parameter

The createMergeableStore function now takes an optional getNow argument that lets you override the clock used to generate HLC timestamps.

Asynchronous Persister & Synchronizer methods

Please note that some methods in the Persister and Synchronizer APIs are now asynchronous. Although most implementations of these methods are synchronous, some (particularly for Postgres-based databases) are no longer so and you are recommended to await them all.

The stopAutoLoad method, the stopAutoSave method, and the destroy method in the base Persister interface have been marked asynchronous and return Promises. The stopSync method in the Synchronizer interface and the destroy method in the Synchronizer server interfaces should also be considered asynchronous.

Thanks!

Enjoy the release and please provide feedback!