Skip to content

Releases: tinyplex/tinybase

v6.4.0

10 Jul 21:40

Choose a tag to compare

This release includes the new persister-react-native-sqlite module, which allows you to persist data in a React Native SQLite database via the react-native-sqlite-storage library.

Usage should be as simple as this:

import {enablePromise, openDatabase} from 'react-native-sqlite-storage';
import {createStore} from 'tinybase';
import {createReactNativeSqlitePersister} from 'tinybase/persisters/persister-react-native-sqlite';

enablePromise(true);
const db = await openDatabase({name: 'my.db', location: 'default'});
const store = createStore().setTables({pets: {fido: {species: 'dog'}}});
const persister = createReactNativeSqlitePersister(store, db);

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

Please let us know how you get on with this new Persister, and if you have any feedback or suggestions.

v6.3.1

09 Jul 12:29

Choose a tag to compare

This release updates dependencies.

v6.3.0

20 Jun 22:40

Choose a tag to compare

This release includes the new persister-durable-object-sql-storage module, which allows you to persist data in a Cloudflare Durable Object's SQLite-based storage in conjunction with websocket-based synchronization (using the WsServerDurableObject class).

Huge thanks to Corey Jepperson, @acoreyj, for implementing the entirety of this functionality!

import {createMergeableStore} from 'tinybase';
import {createDurableObjectSqlStoragePersister} from 'tinybase/persisters/persister-durable-object-sql-storage';
import {WsServerDurableObject} from 'tinybase/synchronizers/synchronizer-ws-server-durable-object';

const config = {
  mode: 'fragmented',
  storagePrefix: 'my_app_',
};

export class MyDurableObject extends WsServerDurableObject {
  createPersister() {
    const store = createMergeableStore();
    const persister = createDurableObjectSqlStoragePersister(
      store,
      this.ctx.storage.sql,
      config,
    );
    return persister;
  }
}

Prior to this release, the only way to persist data in a Durable Object was to use the persister-durable-object-storage module, which uses CloudFlare's key-value storage backend behind the scenes.

However, Cloudflare's SQLite storage backend for Durable Objects offers significantly better pricing compared to the key-value storage backend. The SQLite storage backend is Cloudflare's recommended storage option for new Durable Object namespaces.

Note that, before using this persister, you must configure your Durable Object class to use SQLite storage by adding a migration to your wrangler.toml or wrangler.json configuration file. Use new_sqlite_classes in your migration configuration to enable SQLite storage for your Durable Object class. See the module documentation for more information.

This release also addresses a local-storage persistence issue, #257.

v6.2.1

05 Jun 23:16

Choose a tag to compare

This release updates dependencies.

v6.2.0

31 May 21:08

Choose a tag to compare

This release contains various packaging improvements and exposes some internal HLC functions that are useful for people building their own persisters or synchronizers.

New omni module

There is a new omni module that is an explicit superset of everything in the TinyBase ecosystem. It exports the features and functionality of every tinybase/* module, including every persister, every synchronizer, and every UI component. This is useful for applications that want to use multiple facets of the overall TinyBase ecosystem and also benefit from the fact they share a lot of code internally.

import {createStore, createSqliteBunPersister} from 'tinybase/omni';

However, it should go without saying that you should only use the omni module if you have an aggressive tree-shaking bundler that can remove all the persisters, synchronizers, and so on, that you do not use. Experiment with different bundler configurations to see what works best for your usage.

with-schema exports

This release changes the package.json exports slightly so that imports of both /with-schema and non-schema'd versions of the modules resolve to the same JavaScript file. This reduces bundle size for apps that use both schema and non-schema imports.

HLC & hash functions

The common module (and hence tinybase module) now export the getHlcFunctions function. This returns set of seven functions that can be used to create and manipulate HLC (Hybrid Logical Clock) timestamps.

import {getHlcFunctions} from 'tinybase';
const [getNextHlc, seenHlc, encodeHlc] = getHlcFunctions();

There are also several functions to help hash tabular and key-value data in a way that is compatible with the internal MergeableStore implementation. These include the getHash function and the getCellHash function, for example.

These are for pretty advanced use-cases! But you can use these in your own systems to ensure the timestamps and hashes are compatible with the ones generated in TinyBase MergeableStore objects.

Moved types

The rarely-used GetNow and Hash types have been moved from the mergeable-store module into the common module.

v6.1.2

25 May 01:40

Choose a tag to compare

This release updates dependencies and fixes minor documentation issues.

v6.2.0-beta.1

18 May 18:47

Choose a tag to compare

v6.2.0-beta.1 Pre-release
Pre-release

with-schema exports

This release changes the package.json exports slightly so that imports of both /with-schema and non-schema'd versions of the modules resolve to the same JavaScript file. This reduces bundle size for apps that use both schema and non-schema imports.

v6.1.0

16 May 01:54

Choose a tag to compare

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!

v6.0.5

07 May 01:00

Choose a tag to compare

This release updates dependencies.

v6.0.4

18 Apr 19:52

Choose a tag to compare

This release addresses multi-slice index sorting (#217) and updates the Yjs dependency.