tinybase 8.3.0-beta.3 → 8.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/@types/ui-react-dom/index.d.ts +10 -10
- package/@types/ui-react-dom/with-schemas/index.d.ts +10 -10
- package/@types/ui-react-inspector/index.d.ts +1 -1
- package/@types/ui-react-inspector/with-schemas/index.d.ts +1 -1
- package/@types/ui-svelte-dom/index.d.ts +10 -10
- package/@types/ui-svelte-dom/with-schemas/index.d.ts +10 -10
- package/@types/ui-svelte-inspector/index.d.ts +1 -1
- package/@types/ui-svelte-inspector/with-schemas/index.d.ts +1 -1
- package/package.json +2 -2
- package/readme.md +14 -14
- package/releases.md +80 -59
package/releases.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<link rel="preload" as="image" href="https://beta.tinybase.org/shots/sortedtableinhtmltable-svelte-demo.png"><link rel="preload" as="image" href="https://beta.tinybase.org/shots/inspector-svelte-demo.png"><link rel="preload" as="image" href="https://beta.tinybase.org/shots/editablevalueview-svelte-full-demo.png"><link rel="preload" as="image" href="https://beta.tinybase.org/shots/inspector-react-demo.png"><link rel="preload" as="image" href="https://beta.tinybase.org/partykit.gif"><link rel="preload" as="image" href="https://beta.tinybase.org/shots/sortedtableinhtmltable-react-demo.png"><link rel="preload" as="image" href="https://beta.tinybase.org/shots/car-analysis-demo.png"><link rel="preload" as="image" href="https://beta.tinybase.org/shots/movie-database-demo.png"><p>This is a reverse chronological list of the major TinyBase releases, with highlighted features.</p><hr><h1 id="v8-3">v8.3</h1><h2 id="solid-support">Solid Support</h2><p>This release adds the new
|
|
1
|
+
<link rel="preload" as="image" href="https://beta.tinybase.org/shots/sortedtableinhtmltable-svelte-demo.png"><link rel="preload" as="image" href="https://beta.tinybase.org/shots/inspector-svelte-demo.png"><link rel="preload" as="image" href="https://beta.tinybase.org/shots/editablevalueview-svelte-full-demo.png"><link rel="preload" as="image" href="https://beta.tinybase.org/shots/inspector-react-demo.png"><link rel="preload" as="image" href="https://beta.tinybase.org/partykit.gif"><link rel="preload" as="image" href="https://beta.tinybase.org/shots/sortedtableinhtmltable-react-demo.png"><link rel="preload" as="image" href="https://beta.tinybase.org/shots/car-analysis-demo.png"><link rel="preload" as="image" href="https://beta.tinybase.org/shots/movie-database-demo.png"><p>This is a reverse chronological list of the major TinyBase releases, with highlighted features.</p><hr><h1 id="v8-3">v8.3</h1><h2 id="solid-support">Solid Support</h2><p>This release adds the new ui-solid module, bringing TinyBase's reactive Store bindings to Solid apps. It provides Solid primitives that return Accessor functions, listener primitives that clean up with Solid's lifecycle, Provider context helpers, and view components for rendering Store data directly in a Solid component tree.</p><p>The primitives follow Solid's fine-grained reactivity model. They read TinyBase data immediately, then update the Accessor when the underlying Store data changes:</p>
|
|
2
2
|
|
|
3
3
|
```js
|
|
4
4
|
import {createRoot} from 'solid-js';
|
|
@@ -17,7 +17,7 @@ createRoot((dispose) => {
|
|
|
17
17
|
});
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
<p>The module also includes Solid view components and a
|
|
20
|
+
<p>The module also includes Solid view components and a Provider component, so you can assemble UI directly from TinyBase data while still taking advantage of Solid's selective updates:</p>
|
|
21
21
|
|
|
22
22
|
```jsx
|
|
23
23
|
import {render} from 'solid-js/web';
|
|
@@ -39,7 +39,32 @@ console.log(solidApp.textContent);
|
|
|
39
39
|
disposeSolid();
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
<p>Read more in the <a href="https://beta.tinybase.org/guides/building-uis-with-solid/">Building UIs With Solid</a> guides and the
|
|
42
|
+
<p>Read more in the <a href="https://beta.tinybase.org/guides/building-uis-with-solid/">Building UIs With Solid</a> guides and the ui-solid module documentation.</p><p>A huge thanks to <a href="">Daniel Grant</a> for designing and implementing this new Solid support! Please let us know how it works for you and if you have any feedback or suggestions.</p><h2 id="queries-from-queries">Queries From Queries</h2><p>Also in this release, <a href="https://beta.tinybase.org/guides/using-queries/tinyql/">TinyQL</a> queries can now use the result of another query as their source. This lets you build complex results in small, readable steps - for example, first finding all dogs, and then querying that result to find just the brown ones:</p>
|
|
43
|
+
|
|
44
|
+
```js
|
|
45
|
+
import {createQueries} from 'tinybase';
|
|
46
|
+
|
|
47
|
+
const queryStore = createStore().setTable('pets', {
|
|
48
|
+
fido: {species: 'dog', color: 'brown'},
|
|
49
|
+
felix: {species: 'cat', color: 'black'},
|
|
50
|
+
cujo: {species: 'dog', color: 'black'},
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const queryQueries = createQueries(queryStore)
|
|
54
|
+
.setQueryDefinition('dogs', 'pets', ({select, where}) => {
|
|
55
|
+
select('color');
|
|
56
|
+
where('species', 'dog');
|
|
57
|
+
})
|
|
58
|
+
.setQueryDefinition('brownDogs', true, 'dogs', ({select, where}) => {
|
|
59
|
+
select('color');
|
|
60
|
+
where('color', 'brown');
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
console.log(queryQueries.getResultTable('brownDogs'));
|
|
64
|
+
// -> {fido: {color: 'brown'}}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
<p>The <code>true</code> argument tells setQueryDefinition that <code>dogs</code> is another query result, not a Table in the underlying Store. This works in query clauses too, so you can select or join from query results as your <a href="https://beta.tinybase.org/guides/using-queries/tinyql/">TinyQL</a> definitions become more modular.</p><h2 id="schematizer-enums">Schematizer Enums</h2><p>This release addresses enum types in the schematizers. For example, Zod enums are now schematized as string types, rather than being rejected as invalid. This is also now documented accordingly.</p><p>There are no intended breaking changes in this release. If you try the new Solid bindings in particular, please let us know how they fit your expectations of building Solid apps - and good luck!</p><hr><h1 id="v8-2">v8.2</h1><h2 id="svelte-dom-components-and-inspector">Svelte DOM Components And Inspector</h2><p>This release completes TinyBase's Svelte support with two new additions: the ui-svelte-dom module and the ui-svelte-inspector module.</p><p>The ui-svelte-dom module provides browser-ready Svelte components for rendering and editing TinyBase data as HTML tables. They mirror the React DOM components, but use Svelte component composition and props throughout:</p><p><img src="https://beta.tinybase.org/shots/sortedtableinhtmltable-svelte-demo.png" alt="SortedTableInHtmlTable (Svelte)" title="SortedTableInHtmlTable (Svelte)"></p>
|
|
43
68
|
|
|
44
69
|
```svelte
|
|
45
70
|
<script>
|
|
@@ -55,7 +80,7 @@ disposeSolid();
|
|
|
55
80
|
<TableInHtmlTable tableId="pets" {store} editable />
|
|
56
81
|
```
|
|
57
82
|
|
|
58
|
-
<p>Alongside the table components, the new
|
|
83
|
+
<p>Alongside the table components, the new ui-svelte-inspector module brings the TinyBase development inspector to Svelte apps too, making it easy to inspect and edit Stores, Indexes, Relationships, and Queries during development:</p><p><img src="https://beta.tinybase.org/shots/inspector-svelte-demo.png" alt="Inspector (Svelte)" title="Inspector (Svelte)"></p>
|
|
59
84
|
|
|
60
85
|
```svelte
|
|
61
86
|
<script>
|
|
@@ -73,7 +98,7 @@ disposeSolid();
|
|
|
73
98
|
</Provider>
|
|
74
99
|
```
|
|
75
100
|
|
|
76
|
-
<p>Read more in the <a href="https://beta.tinybase.org/guides/building-uis-with-svelte/using-svelte-dom-components/">Using Svelte DOM Components</a> guide and the <a href="https://beta.tinybase.org/guides/inspecting-data/">Inspecting Data</a> guide.</p><h2 id="new-demos">New <a href="https://beta.tinybase.org/demos/">Demos</a></h2><p>This release also adds a complete set of Svelte UI component demos, plus an Inspector demo, so you can see the new modules working across Stores,
|
|
101
|
+
<p>Read more in the <a href="https://beta.tinybase.org/guides/building-uis-with-svelte/using-svelte-dom-components/">Using Svelte DOM Components</a> guide and the <a href="https://beta.tinybase.org/guides/inspecting-data/">Inspecting Data</a> guide.</p><h2 id="new-demos">New <a href="https://beta.tinybase.org/demos/">Demos</a></h2><p>This release also adds a complete set of Svelte UI component demos, plus an Inspector demo, so you can see the new modules working across Stores, Indexes, Relationships, Queries, and editable views.</p><p><img src="https://beta.tinybase.org/shots/editablevalueview-svelte-full-demo.png" alt="EditableValueView (Svelte)" title="EditableValueView (Svelte)"></p><p>These demos intentionally mirror the React set where possible, making it easier to compare implementation patterns across frameworks.</p><p>There are no intended breaking changes in this release. If you spot any issues with the new Svelte DOM components or the Svelte inspector, please let us know!</p><hr><h1 id="v8-1">v8.1</h1><h2 id="svelte-support">Svelte Support</h2><p>This highly-anticipated release introduces the new ui-svelte module, bringing native Svelte 5 runes-based reactive bindings to TinyBase. The module provides reactive functions and view components for building reactive UIs without any additional state management.</p><p>Reactive functions return a reactive object backed by Svelte's reactivity. Any component that reads <code>current</code> from it will automatically re-render when the underlying TinyBase data changes:</p>
|
|
77
102
|
|
|
78
103
|
```svelte
|
|
79
104
|
<script>
|
|
@@ -87,7 +112,7 @@ disposeSolid();
|
|
|
87
112
|
<p>Color: {color.current}</p>
|
|
88
113
|
```
|
|
89
114
|
|
|
90
|
-
<p>The
|
|
115
|
+
<p>The getCell function and the getValue function provide a writable <code>current</code> property that pairs naturally with Svelte's <code>bind:</code> directive for two-way data binding:</p>
|
|
91
116
|
|
|
92
117
|
```svelte
|
|
93
118
|
<script>
|
|
@@ -99,7 +124,7 @@ disposeSolid();
|
|
|
99
124
|
<input bind:value={color.current} />
|
|
100
125
|
```
|
|
101
126
|
|
|
102
|
-
<p>All reactive functions accept reactive getter functions as parameters — the
|
|
127
|
+
<p>All reactive functions accept reactive getter functions as parameters — the MaybeGetter type (<code>T | (() => T)</code>) — so passing <code>() => rowId</code> from a <code>$state</code> variable causes the function to reactively track which row it reads, without unmounting and remounting.</p><p>The module further includes a provider component and context helpers for sharing TinyBase objects across a component tree, and many built-in view components for assembling UIs directly from Store data.</p><p>Read more in the ui-svelte module documentation and the <a href="https://beta.tinybase.org/guides/building-uis-with-svelte/">Building UIs With Svelte</a> guide.</p><h2 id="new-demos">New <a href="https://beta.tinybase.org/demos/">Demos</a></h2><p>To showcase the new Svelte support, we have created two new Svelte-specific demos: a <a href="https://beta.tinybase.org/demos/hello-world/hello-world-svelte/">Hello World (Svelte)</a> demo and a <a href="https://beta.tinybase.org/demos/countries/countries-svelte/">Countries (Svelte)</a> demo. Check them out to see the new module in action.</p><p>The <code>create-tinybase</code> CLI tool also now includes an option to create a Svelte demo project, so you can easily get started with Svelte and TinyBase in exactly the same way you can with React:</p>
|
|
103
128
|
|
|
104
129
|
```bash
|
|
105
130
|
> npm create tinybase@latest
|
|
@@ -107,7 +132,7 @@ disposeSolid();
|
|
|
107
132
|
📦 Creating your project...
|
|
108
133
|
```
|
|
109
134
|
|
|
110
|
-
<h2 id="breaking-changes">Breaking
|
|
135
|
+
<h2 id="breaking-changes">Breaking Changes</h2><p>If you tried the ui-svelte module in earlier beta releases, there are some intentional breaking changes made to ensure the API is more idiomatic for Svelte. What was <code>useX</code> is now a reactive <code>getX</code> or <code>hasX</code> function, so for example <code>useCell</code> has become the getCell function and <code>useHasCell</code> has become the hasCell function. Context lookups also use <code>getX</code>, as with the getMetrics function, but those return TinyBase objects directly from Provider context rather than reactive <code>current</code>-based wrappers. Listener functions now use <code>onX</code>; so for example <code>useCellListener</code> has become the onCell function. The old <code>useBindableCell</code> and <code>useBindableValue</code> beta names have also gone away because the getCell function and getValue function expose the writable scalar accessors directly.</p><p>This release also contains a minor breaking change since v8.0. The <code>tinybase/omni</code> module no longer includes the ui-react module, ui-react-dom module, or ui-react-inspector module. Since the ui-svelte module exports many of the same names, including both in a single flat namespace would cause silent name collisions.</p><p>If you were importing React UI helpers from <code>tinybase/omni</code>, update your imports:</p>
|
|
111
136
|
|
|
112
137
|
```js ignore
|
|
113
138
|
// Before
|
|
@@ -118,11 +143,9 @@ import {createStore} from 'tinybase/omni';
|
|
|
118
143
|
import {useCell, Provider} from 'tinybase/ui-react';
|
|
119
144
|
```
|
|
120
145
|
|
|
121
|
-
<p>(Sorry about that!)</p><h2 id="we-need-your-help">We need your help</h2><p>We hope you enjoy exploring this early new Svelte support. But we really need feedback on how it works and whether or not you find it easy and idiomatic to work with! Please let us know in the issues, discussions, or on social media. Thanks and good luck!</p><hr><h1 id="v8-0">v8.0</h1><h2 id="object-and-array-types">Object And Array Types</h2><p>This release extends the range of types that a
|
|
146
|
+
<p>(Sorry about that!)</p><h2 id="we-need-your-help">We need your help</h2><p>We hope you enjoy exploring this early new Svelte support. But we really need feedback on how it works and whether or not you find it easy and idiomatic to work with! Please let us know in the issues, discussions, or on social media. Thanks and good luck!</p><hr><h1 id="v8-0">v8.0</h1><h2 id="object-and-array-types">Object And Array Types</h2><p>This release extends the range of types that a Cell or Value can hold. Previously, TinyBase supported <code>string</code>, <code>number</code>, <code>boolean</code>, and (since v7.0) <code>null</code>. Now you can also store plain JavaScript <strong>objects</strong> and <strong>arrays</strong> directly in a Store.</p>
|
|
122
147
|
|
|
123
148
|
```js
|
|
124
|
-
import {createStore} from 'tinybase';
|
|
125
|
-
|
|
126
149
|
const store = createStore().setRow('pets', 'fido', {
|
|
127
150
|
species: 'dog',
|
|
128
151
|
traits: {friendly: true, energetic: true},
|
|
@@ -136,7 +159,7 @@ console.log(store.getCell('pets', 'fido', 'vaccinations'));
|
|
|
136
159
|
// -> ['rabies', 'distemper', 'parvovirus']
|
|
137
160
|
```
|
|
138
161
|
|
|
139
|
-
<p>Internally, objects and arrays are stored as JSON-encoded strings with a special prefix character, so they round-trip transparently through persistence layers. But in and out of your application code, the
|
|
162
|
+
<p>Internally, objects and arrays are stored as JSON-encoded strings with a special prefix character, so they round-trip transparently through persistence layers. But in and out of your application code, the Store API always expects or returns them as native JavaScript values.</p><p><a href="https://beta.tinybase.org/guides/schemas/">Schemas</a> also gain <code>object</code> and <code>array</code> as valid types:</p>
|
|
140
163
|
|
|
141
164
|
```js
|
|
142
165
|
store.setTablesSchema({
|
|
@@ -154,7 +177,7 @@ console.log(store.getRow('pets', 'fido'));
|
|
|
154
177
|
store.delSchema();
|
|
155
178
|
```
|
|
156
179
|
|
|
157
|
-
<p>Note that TinyBase does not deeply validate the contents of objects or arrays when a schema is applied - it simply checks that the value is of the right top-level type. For deeper validation, consider combining with a <a href="https://beta.tinybase.org/guides/the-basics/using-middleware/">Middleware</a> callback. On which note...</p><h2 id="introducing-middleware">Introducing
|
|
180
|
+
<p>Note that TinyBase does not deeply validate the contents of objects or arrays when a schema is applied - it simply checks that the value is of the right top-level type. For deeper validation, consider combining with a <a href="https://beta.tinybase.org/guides/the-basics/using-middleware/">Middleware</a> callback. On which note...</p><h2 id="introducing-middleware">Introducing Middleware</h2><p>This release introduces a powerful new system for intercepting and transforming data as it flows into your TinyBase Store. Middleware callbacks can be registered to fire before data is written to the Store, allowing you to modify, validate, or even reject changes before they take effect.</p>
|
|
158
181
|
|
|
159
182
|
```jsx
|
|
160
183
|
import {createMiddleware} from 'tinybase';
|
|
@@ -170,7 +193,7 @@ middleware.addWillSetCellCallback((tableId, rowId, cellId, cell) => {
|
|
|
170
193
|
});
|
|
171
194
|
```
|
|
172
195
|
|
|
173
|
-
<p>Read more in our new comprehensive <a href="https://beta.tinybase.org/guides/using-middleware/">Using Middleware</a> guide, which includes examples of using
|
|
196
|
+
<p>Read more in our new comprehensive <a href="https://beta.tinybase.org/guides/using-middleware/">Using Middleware</a> guide, which includes examples of using Middleware for data validation, transformation, and more.</p><p>Middleware complements listeners but is distinct in that it runs before changes are applied to the Store, whereas listeners run after. Middleware can modify the data that listeners see, and can prevent changes from being applied at all by returning <code>undefined</code>. In conjunction with schemas, Middleware provides a powerful way to enforce data integrity and implement complex data transformations - and it should work in synchronization environments too.</p><p>Many, many thanks to <a href="https://github.com/bitmage">Brandon Mason</a> for designing and implementing this concept. Despite the major version number, we trust there are no breaking changes in this release. But please let us know if you find any!</p><hr><h1 id="v7-3">v7.3</h1><h2 id="introducing-state-hooks">Introducing State Hooks</h2><p>This release introduces a new family of convenience hooks that follow React's <code>useState</code> pattern, making it even easier to read and write TinyBase data in your React components.</p><p>Each state hook returns a tuple containing both the current value and a setter function, eliminating the need to use separate getter and setter hooks.</p><p>State hooks combine the functionality of getter hooks (like the useRow hook) and setter callback hooks (like the useSetRowCallback hook) into a single, convenient API that feels just like React's <code>useState</code>:</p>
|
|
174
197
|
|
|
175
198
|
```jsx
|
|
176
199
|
import {useCellState} from 'tinybase/ui-react';
|
|
@@ -192,11 +215,9 @@ const PetEditor = () => {
|
|
|
192
215
|
};
|
|
193
216
|
```
|
|
194
217
|
|
|
195
|
-
<h2 id="available-state-hooks">Available State Hooks</h2><p>This release includes eight new state hooks covering the most common data access patterns:</p><ul><li>The
|
|
218
|
+
<h2 id="available-state-hooks">Available State Hooks</h2><p>This release includes eight new state hooks covering the most common data access patterns:</p><ul><li>The useTablesState hook for reading and writing all Tables</li><li>The useTableState hook for reading and writing a single Table</li><li>The useRowState hook for reading and writing a single Row</li><li>The useCellState hook for reading and writing a single Cell</li><li>The useValuesState hook for reading and writing all Values</li><li>The useValueState hook for reading and writing a single Value</li><li>The useParamValuesState hook for reading and writing all query ParamValues</li><li>The useParamValueState hook for reading and writing a single query ParamValue</li></ul><p>These hopefully mean less boilerplate, are particularly useful when building forms, editors, or any interactive UI that needs bidirectional data binding.</p><h2 id="demo-updates">Demo Updates</h2><p>We've updated a few of the demos to showcase these new state hooks:</p><ul><li>The <a href="https://beta.tinybase.org/demos/countries/">Countries</a> demo now uses the useCellState hook for the star/unstar toggle functionality.</li><li>The <a href="https://beta.tinybase.org/demos/todo-app/">Todo App</a> demo uses the useCellState hook to simplify todo completion toggling, and the useValueState hook for managing the selected type filter.</li><li>The <a href="https://beta.tinybase.org/demos/car-analysis/">Car Analysis</a> demo uses the useParamValueState hook to manage query parameters for dimensions, measures, and aggregates. Much more elegant!</li></ul><p>Check out these demos to see the state hooks in action.</p><hr><h1 id="v7-2">v7.2</h1><h2 id="introducing-parameterized-queries">Introducing Parameterized Queries!</h2><p>This release introduces parameterized queries to <a href="https://beta.tinybase.org/guides/using-queries/tinyql/">TinyQL</a> - finally!</p><p>These allow you to define queries using named 'params' that you can then easily update to change the query's results - without redefining the whole query each time.</p><p>Let's take a look with a simple example:</p>
|
|
196
219
|
|
|
197
220
|
```js
|
|
198
|
-
import {createQueries} from 'tinybase';
|
|
199
|
-
|
|
200
221
|
store.setTable('pets', {
|
|
201
222
|
fido: {age: 2, species: 'dog'},
|
|
202
223
|
felix: {age: 1, species: 'cat'},
|
|
@@ -222,7 +243,7 @@ console.log(queries.getResultTable('petsBySpecies'));
|
|
|
222
243
|
// -> {felix: {age: 1}}
|
|
223
244
|
```
|
|
224
245
|
|
|
225
|
-
<p>You can of course have multiple params in a query definition, and use them in any part of the query definition that you would like. Listeners also work as expected - if you are listening to a query's results, and you change a param that affects those results, your listener will be called accordingly.</p><p>This is TinyBase so you should not be too surprised... but params themselves are reactive! You can get and listen to their values with the
|
|
246
|
+
<p>You can of course have multiple params in a query definition, and use them in any part of the query definition that you would like. Listeners also work as expected - if you are listening to a query's results, and you change a param that affects those results, your listener will be called accordingly.</p><p>This is TinyBase so you should not be too surprised... but params themselves are reactive! You can get and listen to their values with the getParamValue method and addParamValueListener method, for example.</p><p>For React users, we also shipped a bunch of new hooks that cover params in exactly the way you would expect, including the useSetParamValueCallback hook and the useSetParamValuesCallback hook, which let you easily update param values from, say, an event handler in your application.</p><p>We know this has been a long-awaited feature, so we hope you enjoy it! See the <a href="https://beta.tinybase.org/guides/using-queries/tinyql/">TinyQL</a> guide for more details, and please let us know how it goes!</p><h2 id="demos"><a href="https://beta.tinybase.org/demos/">Demos</a></h2><p>We have updated the <a href="https://beta.tinybase.org/demos/movie-database/">Movie Database</a> demo to use parameterized queries, and as a result is more efficient and easier to (we think) understand. See the <code>yearGenreMovies</code>, <code>directedMovies</code>, and <code>appearedMovies</code> queries to see params in action.</p><p>We have also updated the <a href="https://beta.tinybase.org/demos/car-analysis/">Car Analysis</a> demo to use just one single parameterized query for the whole app!</p><h2 id="full-api-additions">Full API additions</h2><p>This release includes the following new Queries interface methods:</p><ul><li>getParamValues method</li><li>getParamValue method</li><li>setParamValues method</li><li>setParamValue method</li><li>addParamValuesListener method</li><li>addParamValueListener method</li></ul><p>It also includes the following new React hooks:</p><ul><li>useParamValues hook</li><li>useParamValue hook</li><li>useSetParamValuesCallback hook</li><li>useSetParamValueCallback hook</li><li>useParamValuesListener hook</li><li>useParamValueListener hook</li></ul><p>Check out the API docs for each. They should seem very familiar.</p><p>Please check out this new release and let us know what you think!</p><hr><h1 id="v7-1">v7.1</h1><p>This release introduces <strong>Schematizers</strong>, a new system for converting schemas from popular validation libraries into TinyBase's schema format.</p><h2 id="schematizers">Schematizers</h2><p>Schematizers provide a bridge between external schema validation libraries (like Zod, TypeBox, and Valibot) and TinyBase's TablesSchema and ValuesSchema formats. Instead of manually writing TinyBase schemas, you can now convert existing schemas at runtime:</p>
|
|
226
247
|
|
|
227
248
|
```js
|
|
228
249
|
import {createZodSchematizer} from 'tinybase/schematizers/schematizer-zod';
|
|
@@ -247,7 +268,7 @@ console.log(schematizedStore.getRow('pets', 'fido'));
|
|
|
247
268
|
// -> {species: 'dog', age: 3, sold: false}
|
|
248
269
|
```
|
|
249
270
|
|
|
250
|
-
<p>Schematizers perform best-effort conversions, extracting basic type information (string, number, boolean), defaults, and nullable settings from your schemas.</p><p>This release includes support for:</p><ul><li><strong>Zod</strong> via the
|
|
271
|
+
<p>Schematizers perform best-effort conversions, extracting basic type information (string, number, boolean), defaults, and nullable settings from your schemas.</p><p>This release includes support for:</p><ul><li><strong>Zod</strong> via the createZodSchematizer function</li><li><strong>TypeBox</strong> via the createTypeBoxSchematizer function</li><li><strong>Valibot</strong> via the createValibotSchematizer function</li><li><strong>ArkType</strong> via the createArkTypeSchematizer function</li><li><strong>Yup</strong> via the createYupSchematizer function</li><li><strong>Effect Schema</strong> via the createEffectSchematizer function</li></ul><p>For more information, see the <a href="https://beta.tinybase.org/guides/schemas/using-schematizers/">Using Schematizers</a> guide.</p><hr><h1 id="v7-0">v7.0</h1><p>This important (and slightly breaking!) release adds support for <code>null</code> as a valid Cell and Value type, alongside <code>string</code>, <code>number</code>, and <code>boolean</code>.</p><h2 id="null-type-support">Null Type Support</h2><p>You can now set Cells and Values to <code>null</code>:</p>
|
|
251
272
|
|
|
252
273
|
```js
|
|
253
274
|
store.setCell('pets', 'fido', 'species', 'dog');
|
|
@@ -279,7 +300,7 @@ store.setCell('pets', 'fido', 'species', null);
|
|
|
279
300
|
store.delSchema();
|
|
280
301
|
```
|
|
281
302
|
|
|
282
|
-
<h2 id="important-distinction-null-vs-undefined">Important Distinction: <code>null</code> vs <code>undefined</code></h2><p>It's crucial to understand the difference between <code>null</code> and <code>undefined</code> in TinyBase:</p><ul><li><code>null</code> is an explicit value. A
|
|
303
|
+
<h2 id="important-distinction-null-vs-undefined">Important Distinction: <code>null</code> vs <code>undefined</code></h2><p>It's crucial to understand the difference between <code>null</code> and <code>undefined</code> in TinyBase:</p><ul><li><code>null</code> is an explicit value. A Cell set to <code>null</code> exists in the Store.</li><li><code>undefined</code> means the Cell does not exist in the Store.</li></ul><p>This means that the hasCell method will return <code>true</code> for a Cell with a <code>null</code> value:</p>
|
|
283
304
|
|
|
284
305
|
```js
|
|
285
306
|
store.setCell('pets', 'fido', 'color', null);
|
|
@@ -293,7 +314,7 @@ console.log(store.hasCell('pets', 'fido', 'color'));
|
|
|
293
314
|
store.delTables();
|
|
294
315
|
```
|
|
295
316
|
|
|
296
|
-
<h2 id="breaking-change-database-persistence">Breaking Change: <a href="https://beta.tinybase.org/guides/persistence/database-persistence/">Database Persistence</a></h2><p><strong>Important:</strong> This release includes a breaking change for applications using database persisters (the
|
|
317
|
+
<h2 id="breaking-change-database-persistence">Breaking Change: <a href="https://beta.tinybase.org/guides/persistence/database-persistence/">Database Persistence</a></h2><p><strong>Important:</strong> This release includes a breaking change for applications using database persisters (the Sqlite3Persister, PostgresPersister, or PglitePersister interfaces, for example).</p><p>SQL <code>NULL</code> values are now loaded as TinyBase <code>null</code> values. Previously, SQL <code>NULL</code> would result in Cells being absent from the Store. Now, SQL <code>NULL</code> maps directly to TinyBase <code>null</code>, which means:</p><ul><li>Tables loaded from SQL databases will be <strong>dense</strong> rather than <strong>sparse</strong></li><li>Every Row will have every Cell Id present in the table schema</li><li>Cells that were SQL <code>NULL</code> will have the value <code>null</code></li></ul><p>Example of the roundtrip transformation via a SQLite database:</p>
|
|
297
318
|
|
|
298
319
|
```js
|
|
299
320
|
import sqlite3InitModule from '@sqlite.org/sqlite-wasm';
|
|
@@ -324,7 +345,7 @@ console.log(store.getRow('pets', 'fido'));
|
|
|
324
345
|
// -> {species: 'dog', color: null}
|
|
325
346
|
```
|
|
326
347
|
|
|
327
|
-
<p>This is the correct semantic mapping since SQL databases have fixed schemas where every row must account for every column. See the <a href="https://beta.tinybase.org/guides/persistence/database-persistence/">Database Persistence</a> guide for more details.</p><h2 id="migration-guide">Migration Guide</h2><p>If you are using database persisters, you should:</p><ol><li><p><strong>Review your data access patterns</strong>: If you were checking <code>hasCell(...) === false</code> to detect missing data, you now need to check <code>getCell(...) === null</code> for null values.</p></li><li><p><strong>Update your schemas</strong>: Add <code>allowNull: true</code> to
|
|
348
|
+
<p>This is the correct semantic mapping since SQL databases have fixed schemas where every row must account for every column. See the <a href="https://beta.tinybase.org/guides/persistence/database-persistence/">Database Persistence</a> guide for more details.</p><h2 id="migration-guide">Migration Guide</h2><p>If you are using database persisters, you should:</p><ol><li><p><strong>Review your data access patterns</strong>: If you were checking <code>hasCell(...) === false</code> to detect missing data, you now need to check <code>getCell(...) === null</code> for null values.</p></li><li><p><strong>Update your schemas</strong>: Add <code>allowNull: true</code> to Cell definitions that should permit null values:</p></li></ol>
|
|
328
349
|
|
|
329
350
|
```js ignore
|
|
330
351
|
store.setTablesSchema({
|
|
@@ -336,7 +357,7 @@ store.setTablesSchema({
|
|
|
336
357
|
});
|
|
337
358
|
```
|
|
338
359
|
|
|
339
|
-
<ol start="3"><li><strong>Consider memory implications</strong>: Dense tables consume more memory than sparse tables. If you have large tables with many optional Cells, this could be significant.</li></ol><hr><h1 id="v6-7">v6.7</h1><p>This release includes support for the Origin Private File System (OPFS) in a browser. The
|
|
360
|
+
<ol start="3"><li><strong>Consider memory implications</strong>: Dense tables consume more memory than sparse tables. If you have large tables with many optional Cells, this could be significant.</li></ol><hr><h1 id="v6-7">v6.7</h1><p>This release includes support for the Origin Private File System (OPFS) in a browser. The createOpfsPersister function is the main entry point, and is available in the existing persister-browser module:</p>
|
|
340
361
|
|
|
341
362
|
```js
|
|
342
363
|
import {createOpfsPersister} from 'tinybase/persisters/persister-browser';
|
|
@@ -356,7 +377,7 @@ await opfsPersister.load();
|
|
|
356
377
|
await opfsPersister.destroy();
|
|
357
378
|
```
|
|
358
379
|
|
|
359
|
-
<p>That's it! If you've used other TinyBase persisters, this
|
|
380
|
+
<p>That's it! If you've used other TinyBase persisters, this API should be easy and familiar to use.</p><p>One caveat: observability in OPFS is not yet standardized in browsers. This means that the auto-load functionality of the persister may not work as expected, although a best effort is made using the experimental FileSystemObserverAPI, so please let us know how that works!</p><hr><h1 id="v6-6">v6.6</h1><p>This release improves the Inspector tool, making it easier to debug, inspect, and mutate your TinyBase stores.</p><p><img src="https://beta.tinybase.org/shots/inspector-react-demo.png" alt="Inspector" title="Inspector"></p><p>As well as a modernized UI, new in this release is the ability to create, duplicate, or delete tables, rows, values and cells directly within the Inspector. Press the 'pencil' icon to start editing items, and then hover over the new icons to see how to manipulate the data.</p><p>See the <a href="https://beta.tinybase.org/guides/inspecting-data/">Inspecting Data</a> guide for more information about how to use the Inspector in your application during development.</p><h1 id="v6-5">v6.5</h1><p>This release includes the new persister-react-native-mmkv module, which allows you to persist data in a React Native MMKV store via the <a href="https://github.com/mrousavy/react-native-mmkv">react-native-mmkv</a> library.</p><p>Usage should be as simple as this:</p>
|
|
360
381
|
|
|
361
382
|
```js ignore
|
|
362
383
|
import {createMMKV} from 'react-native-mmkv';
|
|
@@ -370,7 +391,7 @@ await persister.save();
|
|
|
370
391
|
// Store will be saved to the MMKV store.
|
|
371
392
|
```
|
|
372
393
|
|
|
373
|
-
<p>A huge shout out to <a href="https://github.com/JeremyBarbet">Jérémy Barbet</a> for this new persister!</p><hr><h1 id="v6-4">v6.4</h1><p>This release includes the new
|
|
394
|
+
<p>A huge shout out to <a href="https://github.com/JeremyBarbet">Jérémy Barbet</a> for this new persister!</p><hr><h1 id="v6-4">v6.4</h1><p>This release includes the new persister-react-native-sqlite module, which allows you to persist data in a React Native SQLite database via the <a href="https://github.com/andpor/react-native-sqlite-storage">react-native-sqlite-storage</a> library.</p><p>Usage should be as simple as this:</p>
|
|
374
395
|
|
|
375
396
|
```js ignore
|
|
376
397
|
import {enablePromise, openDatabase} from 'react-native-sqlite-storage';
|
|
@@ -386,7 +407,7 @@ await persister.save();
|
|
|
386
407
|
// Store will be saved to the database.
|
|
387
408
|
```
|
|
388
409
|
|
|
389
|
-
<p>Please let us know how you get on with this new
|
|
410
|
+
<p>Please let us know how you get on with this new Persister, and if you have any feedback or suggestions.</p><hr><h1 id="v6-3">v6.3</h1><p>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).</p><p>Huge thanks to <a href="https://github.com/acoreyj">Corey Jepperson</a> for implementing the entirety of this functionality!</p>
|
|
390
411
|
|
|
391
412
|
```js ignore
|
|
392
413
|
import {createMergeableStore} from 'tinybase';
|
|
@@ -411,20 +432,20 @@ export class MyDurableObject extends WsServerDurableObject {
|
|
|
411
432
|
}
|
|
412
433
|
```
|
|
413
434
|
|
|
414
|
-
<p>Prior to this release, the only way to persist data in a Durable Object was to use the
|
|
435
|
+
<p>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.</p><p>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.</p><p>Note that, before using this persister, you must configure your Durable Object class to use SQLite storage by adding a migration to your <code>wrangler.toml</code> or <code>wrangler.json</code> configuration file. Use <code>new_sqlite_classes</code> in your migration configuration to enable SQLite storage for your Durable Object class. See the module documentation for more information.</p><p>This release also addresses a local-storage persistence issue, #<a href="https://github.com/tinyplex/tinybase/issues/257">257</a>.</p><hr><h1 id="v6-2">v6.2</h1><p>This release contains various packaging improvements and exposes some internal HLC functions that are useful for people building their own persisters or synchronizers.</p><h2 id="new-omni-module">New <code>omni</code> module</h2><p>There is a new <code>omni</code> module that is an explicit superset of everything in the TinyBase ecosystem. It exports the features and functionality of every <code>tinybase/*</code> 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.</p>
|
|
415
436
|
|
|
416
437
|
```js ignore
|
|
417
438
|
import {createStore, createSqliteBunPersister} from 'tinybase/omni';
|
|
418
439
|
```
|
|
419
440
|
|
|
420
|
-
<p>However, it should go without saying that you should only use the <code>omni</code> module if you have an aggressive tree-shaking bundler that can remove all the persisters, synchronizers, and so on, that you do <em>not</em> use. Experiment with different bundler configurations to see what works best for your usage.</p><h2 id="with-schema-exports">with-schema exports</h2><p>This release changes the <code>package.json</code> exports slightly so that imports of both <code>/with-schema</code> 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.</p><h2 id="hlc-hash-functions">HLC & hash functions</h2><p>The
|
|
441
|
+
<p>However, it should go without saying that you should only use the <code>omni</code> module if you have an aggressive tree-shaking bundler that can remove all the persisters, synchronizers, and so on, that you do <em>not</em> use. Experiment with different bundler configurations to see what works best for your usage.</p><h2 id="with-schema-exports">with-schema exports</h2><p>This release changes the <code>package.json</code> exports slightly so that imports of both <code>/with-schema</code> 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.</p><h2 id="hlc-hash-functions">HLC & hash functions</h2><p>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.</p>
|
|
421
442
|
|
|
422
443
|
```js
|
|
423
444
|
import {getHlcFunctions} from 'tinybase';
|
|
424
445
|
const [getNextHlc, seenHlc, encodeHlc] = getHlcFunctions();
|
|
425
446
|
```
|
|
426
447
|
|
|
427
|
-
<p>There are also several functions to help hash tabular and key-value data in a way that is compatible with the internal
|
|
448
|
+
<p>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.</p><p>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.</p><h2 id="moved-types">Moved types</h2><p>The rarely-used GetNow and Hash types have been moved from the mergeable-store module into the common module.</p><hr><h1 id="v6-1">v6.1</h1><h2 id="in-summary">In Summary</h2><ul><li><a href="#bun-sqlite">A new Persister for Bun</a>'s embedded SQLite database.</li><li><a href="#subset-persistence">Subset persistence</a> to load subsets of tables into a Store.</li><li><a href="#destructured-object-arguments-for-sorted-row-ids">Destructured object arguments</a> for sorted Row Id methods and hooks.</li><li><a href="#new-startautopersisting-method">A new startAutoPersisting method</a>.</li></ul><p>And more!</p><h2 id="bun-sqlite">Bun SQLite</h2><p>This release includes a new Persister for the <a href="https://bun.sh/docs/api/sqlite">embedded SQLite database</a> available in the Bun runtime.</p><p>You use it by passing a reference to a Bun Database object into the createSqliteBunPersister function:</p>
|
|
428
449
|
|
|
429
450
|
```js bun
|
|
430
451
|
import {Database} from 'bun:sqlite';
|
|
@@ -452,7 +473,7 @@ console.log(store.getTables());
|
|
|
452
473
|
await persister.destroy();
|
|
453
474
|
```
|
|
454
475
|
|
|
455
|
-
<p>There's more information the documentation for the new
|
|
476
|
+
<p>There's more information the documentation for the new persister-sqlite-bun module.</p><h2 id="subset-persistence">Subset persistence</h2><p>Persisters that load and save data to an underlying database can now be configured to only load a <em>subset</em> of the rows in a table into a Store.</p><p>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.</p><p>Do this by specifying a <code>condition</code> in the Persister configuration. This is a single string argument which is used as a SQL <code>WHERE</code> clause when reading and observing data in the table.</p><p>For example, the following code will only load rows from the <code>pets</code> database table where the <code>sold</code> column is set to <code>0</code>:</p>
|
|
456
477
|
|
|
457
478
|
```js ignore
|
|
458
479
|
const subsetPersister = createSqliteWasmPersister(store, sqlite3, db, {
|
|
@@ -464,7 +485,7 @@ const subsetPersister = createSqliteWasmPersister(store, sqlite3, db, {
|
|
|
464
485
|
});
|
|
465
486
|
```
|
|
466
487
|
|
|
467
|
-
<p>See the '<a href="https://beta.tinybase.org/guides/persistence/database-persistence/#loading-subsets-of-database-tables">Loading subsets of database tables</a>' section of the <a href="https://beta.tinybase.org/guides/persistence/database-persistence/">Database Persistence</a> guide for more details. And a huge thank you to Jakub Riedl (<a href="https://github.com/jakubriedl">@jakubriedl</a>) for landing this functionality!</p><h2 id="destructured-object-arguments-for-sorted-row-ids">Destructured object arguments for sorted
|
|
488
|
+
<p>See the '<a href="https://beta.tinybase.org/guides/persistence/database-persistence/#loading-subsets-of-database-tables">Loading subsets of database tables</a>' section of the <a href="https://beta.tinybase.org/guides/persistence/database-persistence/">Database Persistence</a> guide for more details. And a huge thank you to Jakub Riedl (<a href="https://github.com/jakubriedl">@jakubriedl</a>) for landing this functionality!</p><h2 id="destructured-object-arguments-for-sorted-row-ids">Destructured object arguments for sorted Row Ids</h2><p>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.</p><p>So instead of:</p>
|
|
468
489
|
|
|
469
490
|
```js ignore
|
|
470
491
|
store.getSortedRowIds('pets', undefined, undefined, undefined, 10);
|
|
@@ -476,7 +497,7 @@ store.getSortedRowIds('pets', undefined, undefined, undefined, 10);
|
|
|
476
497
|
store.getSortedRowIds({tableId: 'pets', limit: 10});
|
|
477
498
|
```
|
|
478
499
|
|
|
479
|
-
<p>This pattern is also made available to the
|
|
500
|
+
<p>This pattern is also made available to the addSortedRowIdsListener method, the useSortedRowIds hook, and the useSortedRowIdsListener hook.</p><h2 id="new-startautopersisting-method">New startAutoPersisting method</h2><p>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.</p><h2 id="new-createmergeablestore-getnow-parameter">New createMergeableStore getNow parameter</h2><p>The createMergeableStore function now takes an optional <code>getNow</code> argument that lets you override the clock used to generate HLC timestamps.</p><h2 id="asynchronous-persister-synchronizer-methods">Asynchronous Persister & Synchronizer methods</h2><p>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.</p><p>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.</p><hr><h1 id="v6-0">v6.0</h1><p>This major release is about updating dependencies and infrastructure rather than adding new features.</p><p>The most notable changes for users are:</p><ul><li>The package distribution only includes modern ESM packages (both minified and non-minified).</li><li>React 19 is now compatible as an optional peer dependency.</li><li>The tools module and TinyBase CLI have been removed.</li></ul><p>If you have been using CJS or UMD packages, you will need to update your bundling strategy for TinyBase (in the same way that you will have had to have done for React 19, for example) but this change should be compatible with most packaging tools. If you had been using the library directly a browser, you should consider the <a href="https://esm.sh/">esm.sh</a> CDN, as we have for our demos.</p><p>As a result of these changes, there have been some additional knock-on effects to the project and developer infrastructure as a whole. For example:</p><ul><li>The test suite has been updated to use <code>react-testing-library</code> instead of <code>react-test-renderer</code>.</li><li>The React <code>jsx-runtime</code> is used for JSX transformations.</li><li><a href="https://beta.tinybase.org/demos/">Demos</a> (and CodePen examples) have been updated to use an <code>importmap</code> mapping the modules to the <a href="https://esm.sh/">esm.sh</a> CDN.</li><li>ESLint has finally been upgraded to v9.</li></ul><p>Note that TinyBase v6.0 adds no new functionality, so you can afford to stay on v5.4.x for a while if these changes are somehow incompatible for you. However, all future functionality changes and bug fixes <em>will</em> take effect as v6.x releases (and probably won't be back-ported to v5.4.x), so you should endeavor to upgrade as soon as you can.</p><p>Please let us know how these changes find you, and please file an issue on GitHub if you need help adapting to any of them.</p><hr><h1 id="v5-4">v5.4</h1><h2 id="durable-objects-synchronization">Durable Objects synchronization</h2><p>This release contains a new WebSocket synchronization server that runs on Cloudflare as a Durable Object.</p><p><embed src="https://beta.tinybase.org/durable.svg" title="Durable Objects"></p><p>It's in the new synchronizer-ws-server-durable-object module, and you use it by extending the WsServerDurableObject class. Use the getWsServerDurableObjectFetch function for conveniently binding your Cloudflare Worker to your Durable Object:</p>
|
|
480
501
|
|
|
481
502
|
```js ignore
|
|
482
503
|
import {
|
|
@@ -497,7 +518,7 @@ name = "MyDurableObjects"
|
|
|
497
518
|
class_name = "MyDurableObject"
|
|
498
519
|
```
|
|
499
520
|
|
|
500
|
-
<p>With this you can now easily connect and synchronize clients that are using the
|
|
521
|
+
<p>With this you can now easily connect and synchronize clients that are using the WsSynchronizer synchronizer.</p><h2 id="durable-objects-persistence">Durable Objects <a href="https://beta.tinybase.org/guides/persistence/">Persistence</a></h2><p>But wait! There's more. Durable Objects also provide a storage mechanism, and sometimes you want TinyBase data to also be stored on the server (in case all the current clients disconnect and a new one joins, for example). So this release of TinyBase also includes a dedicated persister, the DurableObjectStoragePersister, that also synchronizes the data to the Durable Object storage layer.</p><p>You create it with the createDurableObjectStoragePersister function, and hook it into the Durable Object by returning it from the createPersister method of your WsServerDurableObject:</p>
|
|
501
522
|
|
|
502
523
|
```js ignore
|
|
503
524
|
export class MyDurableObject extends WsServerDurableObject {
|
|
@@ -510,7 +531,7 @@ export class MyDurableObject extends WsServerDurableObject {
|
|
|
510
531
|
}
|
|
511
532
|
```
|
|
512
533
|
|
|
513
|
-
<p>You can get started quickly with this architecture using the Durable Objects option in the <a href="https://github.com/tinyplex/create-tinybase"><code>create-tinybase</code> tool</a>.</p><h2 id="server-reference-implementation">Server Reference Implementation</h2><p>Unrelated to Durable Objects, this release also includes the new <a href="https://beta.tinybase.org/api/synchronizer-ws-server-simple/"><code>synchronizer-ws-server-simple</code></a> module that contains a simple server implementation called <a href="https://beta.tinybase.org/api/synchronizer-ws-server-simple/interfaces/server/wsserversimple/"><code>WsServerSimple</code></a>. Without the complications of listeners, persistence, or statistics, this is more suitable to be used as a reference implementation for other server environments.</p><h2 id="architectural-guide">Architectural Guide</h2><p>To go with this release, we have added new documentation on ways in which you can use TinyBase in an app architecture. Check it out in the new <a href="https://beta.tinybase.org/guides/the-basics/architectural-options/">Architectural Options</a> guide.</p><p>We've also started a new section of documentation for describing integrations, of which the <a href="https://beta.tinybase.org/guides/integrations/cloudflare-durable-objects/">Cloudflare Durable Objects</a> guide, of course, is the first new entry!</p><hr><h1 id="v5-3">v5.3</h1><p>This release is focussed on a few <a href="https://beta.tinybase.org/api/">API</a> improvements and quality-of-life changes. These include:</p><h2 id="react-ssr-support">React SSR support</h2><p>Thanks to contributor <a href="https://github.com/muhajirdev">Muhammad Muhajir</a> for ensuring that TinyBase runs in server-side rendering environments!</p><h2 id="in-the-persisters-module">In the <a href="https://beta.tinybase.org/api/persisters/"><code>persisters</code></a> module...</h2><p>All <a href="https://beta.tinybase.org/api/the-essentials/persisting-stores/persister/"><code>Persister</code></a> objects now expose information about whether they are loading or saving. To access this <a href="https://beta.tinybase.org/api/persisters/enumerations/lifecycle/status/"><code>Status</code></a>, use:</p><ul><li>The <a href="https://beta.tinybase.org/api/persisters/interfaces/persister/persister/methods/lifecycle/getstatus/"><code>getStatus</code></a> method, which will return 0 when it is idle, 1 when it is loading, and 2 when it is saving.</li><li>The <a href="https://beta.tinybase.org/api/persisters/interfaces/persister/persister/methods/listener/addstatuslistener/"><code>addStatusListener</code></a> method, which lets you add a <a href="https://beta.tinybase.org/api/persisters/type-aliases/listener/statuslistener/"><code>StatusListener</code></a> function and which is called whenever the status changes.</li></ul><p>These make it possible to track background load and save activities, so that, for example, you can show a status-bar spinner of asynchronous persistence activity.</p><h2 id="in-the-synchronizers-module">In the <a href="https://beta.tinybase.org/api/synchronizers/"><code>synchronizers</code></a> module...</h2><p>Synchronizers are a sub-class of <a href="https://beta.tinybase.org/api/the-essentials/persisting-stores/persister/"><code>Persister</code></a>, so all <a href="https://beta.tinybase.org/api/the-essentials/synchronizing-stores/synchronizer/"><code>Synchronizer</code></a> objects now also have:</p><ul><li>The <a href="https://beta.tinybase.org/api/persisters/interfaces/persister/persister/methods/lifecycle/getstatus/"><code>getStatus</code></a> method, which will return 0 when it is idle, 1 when it is 'loading' (ie inbound syncing), and 2 when it is 'saving' (ie outbound syncing).</li><li>The <a href="https://beta.tinybase.org/api/persisters/interfaces/persister/persister/methods/listener/addstatuslistener/"><code>addStatusListener</code></a> method, which lets you add a <a href="https://beta.tinybase.org/api/persisters/type-aliases/listener/statuslistener/"><code>StatusListener</code></a> function and which is called whenever the status changes.</li></ul><h2 id="in-the-ui-react-module">In the <a href="https://beta.tinybase.org/api/ui-react/"><code>ui-react</code></a> module...</h2><p>There are corresponding hooks so that you can build these status changes into a React UI easily:</p><ul><li>The <a href="https://beta.tinybase.org/api/ui-react/functions/persister-hooks/usepersisterstatus/"><code>usePersisterStatus</code></a> hook, which will return the status for an explicitly provided, or context-derived <a href="https://beta.tinybase.org/api/the-essentials/persisting-stores/persister/"><code>Persister</code></a>.</li><li>The <a href="https://beta.tinybase.org/api/ui-react/functions/persister-hooks/usepersisterstatuslistener/"><code>usePersisterStatusListener</code></a> hook, which lets you add your own <a href="https://beta.tinybase.org/api/persisters/type-aliases/listener/statuslistener/"><code>StatusListener</code></a> function to a <a href="https://beta.tinybase.org/api/the-essentials/persisting-stores/persister/"><code>Persister</code></a>.</li><li>The <a href="https://beta.tinybase.org/api/ui-react/functions/persister-hooks/usepersister/"><code>usePersister</code></a> hook, which lets you get direct access to a <a href="https://beta.tinybase.org/api/the-essentials/persisting-stores/persister/"><code>Persister</code></a> from within your UI.</li></ul><p>And correspondingly for Synchronizers:</p><ul><li>The <a href="https://beta.tinybase.org/api/ui-react/functions/synchronizer-hooks/usesynchronizerstatus/"><code>useSynchronizerStatus</code></a> hook, which will return the status for an explicitly provided, or context-derived <a href="https://beta.tinybase.org/api/the-essentials/synchronizing-stores/synchronizer/"><code>Synchronizer</code></a>.</li><li>The <a href="https://beta.tinybase.org/api/ui-react/functions/synchronizer-hooks/usesynchronizerstatuslistener/"><code>useSynchronizerStatusListener</code></a> hook, which lets you add your own <a href="https://beta.tinybase.org/api/persisters/type-aliases/listener/statuslistener/"><code>StatusListener</code></a> function to a <a href="https://beta.tinybase.org/api/the-essentials/synchronizing-stores/synchronizer/"><code>Synchronizer</code></a>.</li><li>The <a href="https://beta.tinybase.org/api/ui-react/functions/synchronizer-hooks/usesynchronizer/"><code>useSynchronizer</code></a> hook, which lets you get direct access to a <a href="https://beta.tinybase.org/api/the-essentials/synchronizing-stores/synchronizer/"><code>Synchronizer</code></a> from within your UI.</li></ul><p>In addition, this module also now includes hooks for injecting objects into the Provider context scope imperatively, much like the existing <a href="https://beta.tinybase.org/api/ui-react/functions/store-hooks/useprovidestore/"><code>useProvideStore</code></a> hook:</p><ul><li>The <a href="https://beta.tinybase.org/api/ui-react/functions/metrics-hooks/useprovidemetrics/"><code>useProvideMetrics</code></a> hook, which lets you imperatively register <a href="https://beta.tinybase.org/api/metrics/interfaces/metrics/metrics/"><code>Metrics</code></a> objects.</li><li>The <a href="https://beta.tinybase.org/api/ui-react/functions/indexes-hooks/useprovideindexes/"><code>useProvideIndexes</code></a> hook, which lets you register <a href="https://beta.tinybase.org/api/indexes/interfaces/indexes/indexes/"><code>Indexes</code></a> objects.</li><li>The <a href="https://beta.tinybase.org/api/ui-react/functions/relationships-hooks/useproviderelationships/"><code>useProvideRelationships</code></a> hook, which lets you register <a href="https://beta.tinybase.org/api/relationships/interfaces/relationships/relationships/"><code>Relationships</code></a> objects.</li><li>The <a href="https://beta.tinybase.org/api/ui-react/functions/queries-hooks/useprovidequeries/"><code>useProvideQueries</code></a> hook, which lets you register <a href="https://beta.tinybase.org/api/queries/interfaces/queries/queries/"><code>Queries</code></a> objects.</li><li>The <a href="https://beta.tinybase.org/api/ui-react/functions/checkpoints-hooks/useprovidecheckpoints/"><code>useProvideCheckpoints</code></a> hook, which lets you register <a href="https://beta.tinybase.org/api/checkpoints/interfaces/checkpoints/checkpoints/"><code>Checkpoints</code></a> objects.</li><li>The <a href="https://beta.tinybase.org/api/ui-react/functions/persister-hooks/useprovidepersister/"><code>useProvidePersister</code></a> hook, which lets you register <a href="https://beta.tinybase.org/api/the-essentials/persisting-stores/persister/"><code>Persister</code></a> objects.</li><li>The <a href="https://beta.tinybase.org/api/ui-react/functions/synchronizer-hooks/useprovidesynchronizer/"><code>useProvideSynchronizer</code></a> hook, which lets you register <a href="https://beta.tinybase.org/api/the-essentials/synchronizing-stores/synchronizer/"><code>Synchronizer</code></a> objects.</li></ul><p>All of these new methods have extensive documentation, each with examples to show how to use them.</p><p>Please provide feedback on this new release on GitHub!</p><hr><h1 id="v5-2">v5.2</h1><p>This release introduces new Persisters for... PostgreSQL! TinyBase now has two new <a href="https://beta.tinybase.org/api/the-essentials/persisting-stores/persister/"><code>Persister</code></a> modules:</p><ul><li>The <a href="https://beta.tinybase.org/api/persister-postgres/"><code>persister-postgres</code></a> module provides the <a href="https://beta.tinybase.org/api/persister-postgres/interfaces/persister/postgrespersister/"><code>PostgresPersister</code></a>, which uses the excellent <a href="https://github.com/porsager/postgres"><code>postgres</code></a> module to bind to regular PostgreSQL databases, generally on a server.</li><li>The <a href="https://beta.tinybase.org/api/persister-pglite/"><code>persister-pglite</code></a> module provides the <a href="https://beta.tinybase.org/api/persister-pglite/interfaces/persister/pglitepersister/"><code>PglitePersister</code></a>, which uses the new and exciting <a href="https://github.com/electric-sql/pglite"><code>pglite</code></a> module for running PostgreSQL... in a browser!</li></ul><p>Conceptually, things behave in the same way as they do for the various SQLite persisters. Simply use the <a href="https://beta.tinybase.org/api/persister-postgres/functions/creation/createpostgrespersister/"><code>createPostgresPersister</code></a> function (or the similar <a href="https://beta.tinybase.org/api/the-essentials/persisting-stores/createpglitepersister/"><code>createPglitePersister</code></a> function) to persist your TinyBase data:</p>
|
|
534
|
+
<p>You can get started quickly with this architecture using the Durable Objects option in the <a href="https://github.com/tinyplex/create-tinybase"><code>create-tinybase</code> tool</a>.</p><h2 id="server-reference-implementation">Server Reference Implementation</h2><p>Unrelated to Durable Objects, this release also includes the new synchronizer-ws-server-simple module that contains a simple server implementation called WsServerSimple. Without the complications of listeners, persistence, or statistics, this is more suitable to be used as a reference implementation for other server environments.</p><h2 id="architectural-guide">Architectural Guide</h2><p>To go with this release, we have added new documentation on ways in which you can use TinyBase in an app architecture. Check it out in the new <a href="https://beta.tinybase.org/guides/the-basics/architectural-options/">Architectural Options</a> guide.</p><p>We've also started a new section of documentation for describing integrations, of which the <a href="https://beta.tinybase.org/guides/integrations/cloudflare-durable-objects/">Cloudflare Durable Objects</a> guide, of course, is the first new entry!</p><hr><h1 id="v5-3">v5.3</h1><p>This release is focussed on a few API improvements and quality-of-life changes. These include:</p><h2 id="react-ssr-support">React SSR support</h2><p>Thanks to contributor <a href="https://github.com/muhajirdev">Muhammad Muhajir</a> for ensuring that TinyBase runs in server-side rendering environments!</p><h2 id="in-the-persisters-module">In the persisters module...</h2><p>All Persister objects now expose information about whether they are loading or saving. To access this Status, use:</p><ul><li>The getStatus method, which will return 0 when it is idle, 1 when it is loading, and 2 when it is saving.</li><li>The addStatusListener method, which lets you add a StatusListener function and which is called whenever the status changes.</li></ul><p>These make it possible to track background load and save activities, so that, for example, you can show a status-bar spinner of asynchronous persistence activity.</p><h2 id="in-the-synchronizers-module">In the synchronizers module...</h2><p>Synchronizers are a sub-class of Persister, so all Synchronizer objects now also have:</p><ul><li>The getStatus method, which will return 0 when it is idle, 1 when it is 'loading' (ie inbound syncing), and 2 when it is 'saving' (ie outbound syncing).</li><li>The addStatusListener method, which lets you add a StatusListener function and which is called whenever the status changes.</li></ul><h2 id="in-the-ui-react-module">In the ui-react module...</h2><p>There are corresponding hooks so that you can build these status changes into a React UI easily:</p><ul><li>The usePersisterStatus hook, which will return the status for an explicitly provided, or context-derived Persister.</li><li>The usePersisterStatusListener hook, which lets you add your own StatusListener function to a Persister.</li><li>The usePersister hook, which lets you get direct access to a Persister from within your UI.</li></ul><p>And correspondingly for Synchronizers:</p><ul><li>The useSynchronizerStatus hook, which will return the status for an explicitly provided, or context-derived Synchronizer.</li><li>The useSynchronizerStatusListener hook, which lets you add your own StatusListener function to a Synchronizer.</li><li>The useSynchronizer hook, which lets you get direct access to a Synchronizer from within your UI.</li></ul><p>In addition, this module also now includes hooks for injecting objects into the Provider context scope imperatively, much like the existing useProvideStore hook:</p><ul><li>The useProvideMetrics hook, which lets you imperatively register Metrics objects.</li><li>The useProvideIndexes hook, which lets you register Indexes objects.</li><li>The useProvideRelationships hook, which lets you register Relationships objects.</li><li>The useProvideQueries hook, which lets you register Queries objects.</li><li>The useProvideCheckpoints hook, which lets you register Checkpoints objects.</li><li>The useProvidePersister hook, which lets you register Persister objects.</li><li>The useProvideSynchronizer hook, which lets you register Synchronizer objects.</li></ul><p>All of these new methods have extensive documentation, each with examples to show how to use them.</p><p>Please provide feedback on this new release on GitHub!</p><hr><h1 id="v5-2">v5.2</h1><p>This release introduces new Persisters for... PostgreSQL! TinyBase now has two new Persister modules:</p><ul><li>The persister-postgres module provides the PostgresPersister, which uses the excellent <a href="https://github.com/porsager/postgres"><code>postgres</code></a> module to bind to regular PostgreSQL databases, generally on a server.</li><li>The persister-pglite module provides the PglitePersister, which uses the new and exciting <a href="https://github.com/electric-sql/pglite"><code>pglite</code></a> module for running PostgreSQL... in a browser!</li></ul><p>Conceptually, things behave in the same way as they do for the various SQLite persisters. Simply use the createPostgresPersister function (or the similar createPglitePersister function) to persist your TinyBase data:</p>
|
|
514
535
|
|
|
515
536
|
```js
|
|
516
537
|
import postgres from 'postgres';
|
|
@@ -547,7 +568,7 @@ await pgPersister.destroy();
|
|
|
547
568
|
await sql.end();
|
|
548
569
|
```
|
|
549
570
|
|
|
550
|
-
<p>Note that these two
|
|
571
|
+
<p>Note that these two Persister objects support both the <code>json</code> and <code>tabular</code> modes for saving TinyBase data into the database. See the DatabasePersisterConfig type for more details. (Note however that, like the SQLite Persisters, only the <code>json</code> mode is supported for MergeableStore instances, due to their additional CRDT metadata.)</p><p>This release also exposes the new createCustomSqlitePersister function and createCustomPostgreSqlPersister function at the top level of the persister module. These can be used to build Persister objects against SQLite and PostgreSQL SDKs (or forks) that are not already included with TinyBase.</p><h2 id="minor-breaking-change">Minor breaking change</h2><p>It's very unlikely to affect most apps, but also be aware that the persisters module and synchronizers module are no longer bundled in the 'master' tinybase module. If you are using them (most likely because you have built a custom Persister or Synchronizer), you will need to update your imports accordingly to the standalone <code>tinybase/persisters</code> and <code>tinybase/synchronizers</code> versions of them. Apologies.</p><hr><h1 id="v5-1">v5.1</h1><p>This release lets you persist data on a server using the createWsServer function. This makes it possible for all clients to disconnect from a path, but, when they reconnect, for the data to still be present for them to sync with.</p><p>This is done by passing in a second argument to the createWsServer function that creates a Persister instance (for which also need to create or provide a MergeableStore) for a given path:</p>
|
|
551
572
|
|
|
552
573
|
```js
|
|
553
574
|
import {createMergeableStore} from 'tinybase';
|
|
@@ -567,7 +588,7 @@ const persistingServer = createWsServer(
|
|
|
567
588
|
await persistingServer.destroy();
|
|
568
589
|
```
|
|
569
590
|
|
|
570
|
-
<p>This is a very crude (and not production-safe!) example, but demonstrates a server that will create a file, based on any path that clients connect to, and persist data to it. See the
|
|
591
|
+
<p>This is a very crude (and not production-safe!) example, but demonstrates a server that will create a file, based on any path that clients connect to, and persist data to it. See the createWsServer function documentation for more details.</p><p>This implementation is still experimental so please kick the tires!</p><p>There is one small breaking change in this release: the functions for creating Synchronizer objects can now take optional onSend and onReceive callbacks that will fire whenever messages pass through the Synchronizer. See, for example, the createWsSynchronizer function. These are suitable for debugging synchronization issues in a development environment.</p><hr><h1 id="v5-0">v5.0</h1><p>We're excited to announce this major release for TinyBase! It includes important data synchronization functionality and a range of other improvements.</p><h1 id="in-summary">In Summary</h1><ul><li><a href="#the-new-mergeableStore-type">The new MergeableStore type</a> wraps your data as a Conflict-Free Replicated Data Type (CRDT).</li><li><a href="#the-new-synchronizer-framework">The new Synchronizer framework</a> keeps multiple instances of data in sync across different media.</li><li>An <a href="#improved-module-folder-structure">improved module folder structure</a> removes common packaging and bundling issues.</li><li>The TinyBase Inspector is now in its own standalone ui-react-inspector module.</li><li>TinyBase now supports only Expo SQLite v14 (<a href="https://expo.dev/changelog/2024/05-07-sdk-51">SDK 51</a>) and above.</li></ul><p>There are also some small <a href="#breaking-changes-in-v50">breaking changes</a> that may affect you (but which should easy to fix if they do).</p><p>Let's look at the major functionality in more detail!</p><h2 id="the-new-mergeablestore-type">The New MergeableStore Type</h2><p>A key part of TinyBase v5.0 is the new mergeable-store module, which contains a subtype of Store - called MergeableStore - that can be merged with another with deterministic results. The implementation uses an encoded hybrid logical clock (HLC) to timestamp the changes made so that they can be cleanly merged.</p><p>The getMergeableContent method on a MergeableStore is used to get the state of a store that can be merged into another. The applyMergeableChanges method will let you apply that to (another) store. The merge method is a convenience function to bidirectionally merge two stores together:</p>
|
|
571
592
|
|
|
572
593
|
```js
|
|
573
594
|
const localStore1 = createMergeableStore();
|
|
@@ -585,7 +606,7 @@ console.log(localStore2.getContent());
|
|
|
585
606
|
// -> [{pets: {felix: {species: 'cat'}, fido: {species: 'dog'}}}, {}]
|
|
586
607
|
```
|
|
587
608
|
|
|
588
|
-
<p>Please read the new <a href="https://beta.tinybase.org/guides/synchronization/using-a-mergeablestore/">Using A MergeableStore</a> guide for more details of how to use this important new
|
|
609
|
+
<p>Please read the new <a href="https://beta.tinybase.org/guides/synchronization/using-a-mergeablestore/">Using A MergeableStore</a> guide for more details of how to use this important new API.</p><p>A MergeableStore can be persisted locally, just like a regular Store into file, local and session storage, and simple SQLite environments such as Expo and SQLite3. These allow you to save the state of a MergeableStore locally before it has had the chance to be synchronized online, for example.</p><p>Which leads us onto the next important feature in v5.0, allowing you to synchronize stores between systems...</p><h2 id="the-new-synchronizer-framework">The New Synchronizer Framework</h2><p>The v5.0 release also introduces the new concept of synchronization. Synchronizer objects implement a negotiation protocol that allows multiple MergeableStore objects to be merged together. This can be across a network, using WebSockets, for example:</p>
|
|
589
610
|
|
|
590
611
|
```js
|
|
591
612
|
import {createWsSynchronizer} from 'tinybase/synchronizers/synchronizer-ws-client';
|
|
@@ -623,7 +644,7 @@ await synchronizer2.destroy();
|
|
|
623
644
|
await server.destroy();
|
|
624
645
|
```
|
|
625
646
|
|
|
626
|
-
<p>This release includes three types of <a href="https://beta.tinybase.org/api/the-essentials/synchronizing-stores/synchronizer/"><code>Synchronizer</code></a>:</p><ul><li>The <a href="https://beta.tinybase.org/api/synchronizer-ws-client/interfaces/synchronizer/wssynchronizer/"><code>WsSynchronizer</code></a> uses WebSockets to communicate between different systems as shown above.</li><li>The <a href="https://beta.tinybase.org/api/synchronizer-broadcast-channel/interfaces/synchronizer/broadcastchannelsynchronizer/"><code>BroadcastChannelSynchronizer</code></a> uses the browser's BroadcastChannel <a href="https://beta.tinybase.org/api/">API</a> to communicate between different tabs and workers.</li><li>The <a href="https://beta.tinybase.org/api/synchronizer-local/interfaces/synchronizer/localsynchronizer/"><code>LocalSynchronizer</code></a> demonstrates synchronization in memory on a single local system.</li></ul><p>Notice that the <a href="https://beta.tinybase.org/api/synchronizer-ws-client/interfaces/synchronizer/wssynchronizer/"><code>WsSynchronizer</code></a> assumes that there exists a server that can forward requests to other <a href="https://beta.tinybase.org/api/synchronizer-ws-client/interfaces/synchronizer/wssynchronizer/"><code>WsSynchronizer</code></a> systems. This can be created using the <a href="https://beta.tinybase.org/api/synchronizer-ws-server/functions/creation/createwsserver/"><code>createWsServer</code></a> function that takes a WebSocketServer as also shown above.</p><p>Please read the new <a href="https://beta.tinybase.org/guides/synchronization/using-a-synchronizer/">Using A Synchronizer</a> guide for more details of how to synchronize your data.</p><h2 id="improved-module-folder-structure">Improved Module Folder Structure</h2><p>We have previously found issues with legacy bundlers and other tools that didn't fully support the new <code>exports</code> field in the module's package.</p><p>To mitigate that, the TinyBase distribution now has a top-level folder structure that fully echoes the import paths, including signifiers for JavaScript versions, schema support, minification and so on.</p><p>Please read the comprehensive <a href="https://beta.tinybase.org/guides/the-basics/importing-tinybase/">Importing TinyBase</a> guide for more details of how to construct the correct import paths in v5.0.</p><h2 id="breaking-changes-in-v5-0">Breaking <a href="https://beta.tinybase.org/api/store/type-aliases/transaction/changes/"><code>Changes</code></a> in v5.0</h2><h3 id="module-file-structure">Module File Structure</h3><p>If you previously had <code>/lib/</code> in your import paths, you should remove it. You also do not have to explicitly specify whether you need the <code>cjs</code> version of TinyBase - if you are using a <code>require</code> rather than an <code>import</code>, you will get it automatically.</p><p>The non-minified version of the code is now default and you need to be explicit when you <em>want</em> minified code. Previously you would add <code>/debug</code> to the import path to get non-minified code, but now you add <code>/min</code> to the import path to get <em>minified</em> code.</p><h3 id="expo-sqlite-persister">Expo SQLite <a href="https://beta.tinybase.org/api/the-essentials/persisting-stores/persister/"><code>Persister</code></a></h3><p>Previously the <a href="https://beta.tinybase.org/api/persister-expo-sqlite/"><code>persister-expo-sqlite</code></a> module supported expo-sqlite v13 and the persister-expo-sqlite-next module supported their modern 'next' package. In v5.0, the <a href="https://beta.tinybase.org/api/persister-expo-sqlite/"><code>persister-expo-sqlite</code></a> module only supports v14 and later, and the persister-expo-sqlite-next module has been removed.</p><h3 id="the-tinybase-inspector">The TinyBase Inspector</h3><p>Previously, the React-based inspector (then known as <code>StoreInspector</code>) resided in the debug version of the <a href="https://beta.tinybase.org/api/ui-react-dom/"><code>ui-react-dom</code></a> module. It now lives in its own <a href="https://beta.tinybase.org/api/ui-react-inspector/"><code>ui-react-inspector</code></a> module (so that it can be used against non-debug code) and has been renamed to Inspector.</p><p>Please update your imports and rename the component when used, accordingly. See the <a href="https://beta.tinybase.org/api/">API</a> documentation for details, or the <a href="https://beta.tinybase.org/demos/ui-components-react/inspector-react/"><inspector>(React)</inspector></a>demo, for example.</p><h3 id="api-changes"><a href="https://beta.tinybase.org/api/">API</a> <a href="https://beta.tinybase.org/api/store/type-aliases/transaction/changes/"><code>Changes</code></a></h3><p>The following changes have been made to the existing TinyBase <a href="https://beta.tinybase.org/api/">API</a> for consistency. These are less common parts of the <a href="https://beta.tinybase.org/api/">API</a> but should straightforward to correct if you are using them.</p><p>In the type definitions:</p><ul><li>The GetTransactionChanges and GetTransactionLog types have been removed.</li><li>The TransactionChanges type has been renamed as the <a href="https://beta.tinybase.org/api/store/type-aliases/transaction/changes/"><code>Changes</code></a> type.</li><li>The <a href="https://beta.tinybase.org/api/store/type-aliases/transaction/changes/"><code>Changes</code></a> type now uses <code>undefined</code> instead of <code>null</code> to indicate a <a href="https://beta.tinybase.org/api/store/type-aliases/store/cell/"><code>Cell</code></a> or <a href="https://beta.tinybase.org/api/store/type-aliases/store/value/"><code>Value</code></a> that has been deleted or that was not present.</li><li>The <a href="https://beta.tinybase.org/api/store/type-aliases/transaction/transactionlog/"><code>TransactionLog</code></a> type is now an array instead of a JavaScript object.</li></ul><p>In the <a href="https://beta.tinybase.org/api/the-essentials/creating-stores/store/"><code>Store</code></a> interface:</p><ul><li>There is a new <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/transaction/gettransactionchanges/"><code>getTransactionChanges</code></a> method and a new getTransactionLog method.</li><li>The setTransactionChanges method is renamed as the <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/setter/applychanges/"><code>applyChanges</code></a> method.</li><li>A <a href="https://beta.tinybase.org/api/store/type-aliases/callback/dorollback/"><code>DoRollback</code></a> function no longer gets passed arguments. You can use the <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/transaction/gettransactionchanges/"><code>getTransactionChanges</code></a> method and <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/transaction/gettransactionlog/"><code>getTransactionLog</code></a> method directly instead.</li><li>Similarly, a <a href="https://beta.tinybase.org/api/store/type-aliases/listener/transactionlistener/"><code>TransactionListener</code></a> function no longer gets passed arguments.</li></ul><p>In the <a href="https://beta.tinybase.org/api/persisters/"><code>persisters</code></a> module:</p><ul><li>The <a href="https://beta.tinybase.org/api/persisters/functions/creation/createcustompersister/"><code>createCustomPersister</code></a> function now takes a final optional boolean (<code>supportsMergeableStore</code>) to indicate that the <a href="https://beta.tinybase.org/api/the-essentials/persisting-stores/persister/"><code>Persister</code></a> can support <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/"><code>MergeableStore</code></a> as well as <a href="https://beta.tinybase.org/api/the-essentials/creating-stores/store/"><code>Store</code></a> objects.</li><li>A <a href="https://beta.tinybase.org/api/the-essentials/persisting-stores/persister/"><code>Persister</code></a>'s <a href="https://beta.tinybase.org/api/persisters/interfaces/persister/persister/methods/load/load/"><code>load</code></a> method and <a href="https://beta.tinybase.org/api/persisters/interfaces/persister/persister/methods/load/startautoload/"><code>startAutoLoad</code></a> method now take a <a href="https://beta.tinybase.org/api/store/type-aliases/store/content/"><code>Content</code></a> object as one parameter, rather than <a href="https://beta.tinybase.org/api/store/type-aliases/store/tables/"><code>Tables</code></a> and <a href="https://beta.tinybase.org/api/store/type-aliases/store/values/"><code>Values</code></a> as two.</li><li>If you create a custom <a href="https://beta.tinybase.org/api/the-essentials/persisting-stores/persister/"><code>Persister</code></a>, the setPersisted method now receives changes made to a <a href="https://beta.tinybase.org/api/the-essentials/creating-stores/store/"><code>Store</code></a> directly by reference, rather than via a callback. Similarly, the <a href="https://beta.tinybase.org/api/persisters/type-aliases/creation/persisterlistener/"><code>PersisterListener</code></a> you register in your addPersisterListener implementation now takes <a href="https://beta.tinybase.org/api/store/type-aliases/store/content/"><code>Content</code></a> and <a href="https://beta.tinybase.org/api/store/type-aliases/transaction/changes/"><code>Changes</code></a> objects directly rather than via a callback.</li><li>The broadcastTransactionChanges method in the <a href="https://beta.tinybase.org/api/persister-partykit-server/"><code>persister-partykit-server</code></a> module has been renamed to the broadcastChanges method.</li></ul><hr><h1 id="v4-8">v4.8</h1><p>This release includes the new <a href="https://beta.tinybase.org/api/persister-powersync/"><code>persister-powersync</code></a> module, which provides a <a href="https://beta.tinybase.org/api/the-essentials/persisting-stores/persister/"><code>Persister</code></a> for <a href="https://www.powersync.com/">PowerSync's SQLite</a> database.</p><p>Much like the other SQLite persisters, use it by passing in a PowerSync instance to the <a href="https://beta.tinybase.org/api/persister-powersync/functions/creation/createpowersyncpersister/"><code>createPowerSyncPersister</code></a> function; something like:</p>
|
|
647
|
+
<p>This release includes three types of Synchronizer:</p><ul><li>The WsSynchronizer uses WebSockets to communicate between different systems as shown above.</li><li>The BroadcastChannelSynchronizer uses the browser's BroadcastChannel API to communicate between different tabs and workers.</li><li>The LocalSynchronizer demonstrates synchronization in memory on a single local system.</li></ul><p>Notice that the WsSynchronizer assumes that there exists a server that can forward requests to other WsSynchronizer systems. This can be created using the createWsServer function that takes a WebSocketServer as also shown above.</p><p>Please read the new <a href="https://beta.tinybase.org/guides/synchronization/using-a-synchronizer/">Using A Synchronizer</a> guide for more details of how to synchronize your data.</p><h2 id="improved-module-folder-structure">Improved Module Folder Structure</h2><p>We have previously found issues with legacy bundlers and other tools that didn't fully support the new <code>exports</code> field in the module's package.</p><p>To mitigate that, the TinyBase distribution now has a top-level folder structure that fully echoes the import paths, including signifiers for JavaScript versions, schema support, minification and so on.</p><p>Please read the comprehensive <a href="https://beta.tinybase.org/guides/the-basics/importing-tinybase/">Importing TinyBase</a> guide for more details of how to construct the correct import paths in v5.0.</p><h2 id="breaking-changes-in-v5-0">Breaking Changes in v5.0</h2><h3 id="module-file-structure">Module File Structure</h3><p>If you previously had <code>/lib/</code> in your import paths, you should remove it. You also do not have to explicitly specify whether you need the <code>cjs</code> version of TinyBase - if you are using a <code>require</code> rather than an <code>import</code>, you will get it automatically.</p><p>The non-minified version of the code is now default and you need to be explicit when you <em>want</em> minified code. Previously you would add <code>/debug</code> to the import path to get non-minified code, but now you add <code>/min</code> to the import path to get <em>minified</em> code.</p><h3 id="expo-sqlite-persister">Expo SQLite Persister</h3><p>Previously the persister-expo-sqlite module supported expo-sqlite v13 and the persister-expo-sqlite-next module supported their modern 'next' package. In v5.0, the persister-expo-sqlite module only supports v14 and later, and the persister-expo-sqlite-next module has been removed.</p><h3 id="the-tinybase-inspector">The TinyBase Inspector</h3><p>Previously, the React-based inspector (then known as <code>StoreInspector</code>) resided in the debug version of the ui-react-dom module. It now lives in its own ui-react-inspector module (so that it can be used against non-debug code) and has been renamed to Inspector.</p><p>Please update your imports and rename the component when used, accordingly. See the API documentation for details, or the <a href="https://beta.tinybase.org/demos/ui-components-react/inspector-react/"><inspector>(React)</inspector></a>demo, for example.</p><h3 id="api-changes">API Changes</h3><p>The following changes have been made to the existing TinyBase API for consistency. These are less common parts of the API but should straightforward to correct if you are using them.</p><p>In the type definitions:</p><ul><li>The GetTransactionChanges and GetTransactionLog types have been removed.</li><li>The TransactionChanges type has been renamed as the Changes type.</li><li>The Changes type now uses <code>undefined</code> instead of <code>null</code> to indicate a Cell or Value that has been deleted or that was not present.</li><li>The TransactionLog type is now an array instead of a JavaScript object.</li></ul><p>In the Store interface:</p><ul><li>There is a new getTransactionChanges method and a new getTransactionLog method.</li><li>The setTransactionChanges method is renamed as the applyChanges method.</li><li>A DoRollback function no longer gets passed arguments. You can use the getTransactionChanges method and getTransactionLog method directly instead.</li><li>Similarly, a TransactionListener function no longer gets passed arguments.</li></ul><p>In the persisters module:</p><ul><li>The createCustomPersister function now takes a final optional boolean (<code>supportsMergeableStore</code>) to indicate that the Persister can support MergeableStore as well as Store objects.</li><li>A Persister's load method and startAutoLoad method now take a Content object as one parameter, rather than Tables and Values as two.</li><li>If you create a custom Persister, the setPersisted method now receives changes made to a Store directly by reference, rather than via a callback. Similarly, the PersisterListener you register in your addPersisterListener implementation now takes Content and Changes objects directly rather than via a callback.</li><li>The broadcastTransactionChanges method in the persister-partykit-server module has been renamed to the broadcastChanges method.</li></ul><hr><h1 id="v4-8">v4.8</h1><p>This release includes the new persister-powersync module, which provides a Persister for <a href="https://www.powersync.com/">PowerSync's SQLite</a> database.</p><p>Much like the other SQLite persisters, use it by passing in a PowerSync instance to the createPowerSyncPersister function; something like:</p>
|
|
627
648
|
|
|
628
649
|
```js ignore
|
|
629
650
|
const powerSync = usePowerSync();
|
|
@@ -637,7 +658,7 @@ const persister = createPowerSyncPersister(store, powerSync, {
|
|
|
637
658
|
});
|
|
638
659
|
```
|
|
639
660
|
|
|
640
|
-
<p>A huge thank you to <a href="https://bndkt.com/">Benedikt Mueller</a> (<a href="https://github.com/bndkt">@bndkt</a>) for building out this functionality! And please provide feedback on how this new
|
|
661
|
+
<p>A huge thank you to <a href="https://bndkt.com/">Benedikt Mueller</a> (<a href="https://github.com/bndkt">@bndkt</a>) for building out this functionality! And please provide feedback on how this new Persister works for you.</p><hr><h1 id="v4-7">v4.7</h1><p>This release includes the new persister-libsql module, which provides a Persister for <a href="https://turso.tech/libsql">Turso's LibSQL</a> database.</p><p>Use the Persister by passing in a reference to the LibSQL client to the createLibSQLPersister function; something like:</p>
|
|
641
662
|
|
|
642
663
|
```js ignore
|
|
643
664
|
const client = createClient({url: 'file:my.db'});
|
|
@@ -651,7 +672,7 @@ const persister = createLibSqlPersister(store, client, {
|
|
|
651
672
|
});
|
|
652
673
|
```
|
|
653
674
|
|
|
654
|
-
<p>This is the first version of this functionality, so please provide feedback on how it works for you!</p><hr><h1 id="v4-6">v4.6</h1><p>This release includes the new
|
|
675
|
+
<p>This is the first version of this functionality, so please provide feedback on how it works for you!</p><hr><h1 id="v4-6">v4.6</h1><p>This release includes the new persister-electric-sql module, which provides a Persister for <a href="https://electric-sql.com/">ElectricSQL</a> client databases.</p><p>Use the Persister by passing in a reference to the Electric client to the createElectricSqlPersister function; something like:</p>
|
|
655
676
|
|
|
656
677
|
```js ignore
|
|
657
678
|
const electric = await electrify(connection, schema, config);
|
|
@@ -665,7 +686,7 @@ const persister = createElectricSqlPersister(store, electric, {
|
|
|
665
686
|
});
|
|
666
687
|
```
|
|
667
688
|
|
|
668
|
-
<p>This release is accompanied by a <a href="https://github.com/tinyplex/tinybase-ts-react-electricsql">template project</a> to get started quickly with this integration. Enjoy!</p><hr><h1 id="v4-5">v4.5</h1><p>This release includes the new persister-expo-sqlite-next module, which provides a
|
|
689
|
+
<p>This release is accompanied by a <a href="https://github.com/tinyplex/tinybase-ts-react-electricsql">template project</a> to get started quickly with this integration. Enjoy!</p><hr><h1 id="v4-5">v4.5</h1><p>This release includes the new persister-expo-sqlite-next module, which provides a Persister for the modern version of Expo's <a href="https://docs.expo.dev/versions/latest/sdk/sqlite">SQLite</a> library, designated 'next' as of November 2023. This API should be used if you are installing the <code>expo-sqlite/next</code> module.</p><p>Note that TinyBase support for the legacy version of Expo-SQLite (<code>expo-sqlite</code>) is still available in the persister-expo-sqlite module.</p><p>NB as of TinyBase v5.0, this is now the default and legacy support has been removed.</p><p>Thank you to Expo for providing this functionality!</p><hr><h1 id="v4-4">v4.4</h1><p>This relatively straightforward release adds a selection of new listeners to the Store object, and their respective hooks. These are for listening to changes in the 'existence' of entities rather than to their value. For example, the addHasTableListener method will let you listen for the presence (or not) of a specific table.</p><p>The full set of new existence-listening methods and hooks to work with this is as follows:</p><div class="table"><table><thead><tr><th>Existence of:</th><th>Add Listener</th><th>Hook</th><th>Add Listener Hook</th></tr></thead><tbody><tr><td>Tables</td><td>addHasTablesListener</td><td>useHasTables</td><td>useHasTablesListener</td></tr><tr><td>A Table</td><td>addHasTableListener</td><td>useHasTable</td><td>useHasTableListener</td></tr><tr><td>A Table Cell</td><td>addHasTableCellListener</td><td>useHasTableCell</td><td>useHasTableCellListener</td></tr><tr><td>A Row</td><td>addHasRowListener</td><td>useHasRow</td><td>useHasRowListener</td></tr><tr><td>A Cell</td><td>addHasCellListener</td><td>useHasCell</td><td>useHasCellListener</td></tr><tr><td>Values</td><td>addHasValuesListener</td><td>useHasValues</td><td>useHasValuesListener</td></tr><tr><td>A Value</td><td>addHasValueListener</td><td>useHasValue</td><td>useHasValueListener</td></tr></tbody></table></div><p>These methods may become particularly important in future versions of TinyBase that support <code>null</code> as valid Cells and Values.</p><hr><h1 id="v4-3">v4.3</h1><p>We're excited to announce TinyBase 4.3, which provides an integration with <a href="https://www.partykit.io/">PartyKit</a>, a cloud-based collaboration provider.</p><p>This allows you to enjoy the benefits of both a "local-first" architecture and a "sharing-first" platform. You can have structured data on the client with fast, reactive user experiences, but also benefit from cloud-based persistence and room-based collaboration.</p><p><img src="https://beta.tinybase.org/partykit.gif" alt="PartyKit" title="PartyKit"></p><p>This release includes two new modules:</p><ul><li>The persister-partykit-server module provides a server class for coordinating clients and persisting Store data to the PartyKit cloud.</li><li>The persister-partykit-client module provides the API to create connections to the server and a binding to your Store.</li></ul><p>A TinyBase server implementation on PartyKit can be as simple as this:</p>
|
|
669
690
|
|
|
670
691
|
```js ignore
|
|
671
692
|
import {TinyBasePartyKitServer} from 'tinybase/persisters/persister-partykit-server';
|
|
@@ -673,7 +694,7 @@ import {TinyBasePartyKitServer} from 'tinybase/persisters/persister-partykit-ser
|
|
|
673
694
|
export default class extends TinyBasePartyKitServer {}
|
|
674
695
|
```
|
|
675
696
|
|
|
676
|
-
<p>On the client, use the familiar
|
|
697
|
+
<p>On the client, use the familiar Persister API, passing in a reference to a PartyKit socket object that's been configured to connect to your server deployment and named room:</p>
|
|
677
698
|
|
|
678
699
|
```js ignore
|
|
679
700
|
import {createPartyKitPersister} from 'tinybase/persisters/persister-partykit-client';
|
|
@@ -689,7 +710,7 @@ await persister.startAutoSave();
|
|
|
689
710
|
await persister.startAutoLoad();
|
|
690
711
|
```
|
|
691
712
|
|
|
692
|
-
<p>The
|
|
713
|
+
<p>The load method and (gracefully failing) save method on this Persister use HTTPS to get or set full copies of the Store to the cloud. However, the auto-save and auto-load modes use a websocket to transmit subsequent incremental changes in either direction, making for performant sharing of state between clients.</p><p>See and try out this new collaboration functionality in the <a href="https://beta.tinybase.org/demos/todo-app/todo-app-v6-collaboration/">Todo App v6 (collaboration)</a> demo. This also emphasizes the few changes that need to be made to an existing app to make it instantly collaborative.</p><p>Also try out the <a href="https://github.com/tinyplex/tinybase-ts-react-partykit">tinybase-ts-react-partykit</a> template that gets you up and running with a PartyKit-enabled TinyBase app extremely quickly.</p><p>PartyKit supports retries for clients that go offline, and so the disconnected user experience is solid, out of the box. Learn more about configuring this behavior <a href="https://docs.partykit.io/reference/partysocket-api/#options">here</a>.</p><p>Note, however, that this release is not yet a full CRDT implementation: there is no clock synchronization and it is more 'every write wins' than 'last write wins'. However, since the transmitted updates are at single cell (or value) granularity, conflicts are minimized. More resilient replication is planned as this integration matures.</p><hr><h1 id="v4-2">v4.2</h1><p>This release adds support for persisting TinyBase to a browser's IndexedDB storage. You'll need to import the new persister-indexed-db module, and call the createIndexedDbPersister function to create the IndexedDB Persister.</p><p>The API is the same as for all the other Persister APIs:</p>
|
|
693
714
|
|
|
694
715
|
```js
|
|
695
716
|
import {createIndexedDbPersister} from 'tinybase/persisters/persister-indexed-db';
|
|
@@ -718,12 +739,12 @@ await indexedDbPersister.save();
|
|
|
718
739
|
await indexedDbPersister.destroy();
|
|
719
740
|
```
|
|
720
741
|
|
|
721
|
-
<p>Note that it is not possible to reactively detect changes to a browser's IndexedDB storage. A polling technique is used to load underlying changes if you choose to 'autoLoad' your data into TinyBase.</p><p>This release also upgrades Prettier to v3.0 which has a peer-dependency impact on the tools module. Please report any issues!</p><hr><h1 id="v4-1">v4.1</h1><p>This release introduces the new
|
|
722
|
-
TinyBase DOM Component"></p><h2 id="new-dom-components">New DOM Components</h2><p>The following is the list of all the components released in v4.1:</p><div class="table"><table><thead><tr><th>Component</th><th>Purpose</th><th></th></tr></thead><tbody><tr><td
|
|
742
|
+
<p>Note that it is not possible to reactively detect changes to a browser's IndexedDB storage. A polling technique is used to load underlying changes if you choose to 'autoLoad' your data into TinyBase.</p><p>This release also upgrades Prettier to v3.0 which has a peer-dependency impact on the tools module. Please report any issues!</p><hr><h1 id="v4-1">v4.1</h1><p>This release introduces the new ui-react-dom module. This provides pre-built components for tabular display of your data in a web application.</p><p><img src="https://beta.tinybase.org/shots/sortedtableinhtmltable-react-demo.png" alt="A TinyBase DOM Component" title="A
|
|
743
|
+
TinyBase DOM Component"></p><h2 id="new-dom-components">New DOM Components</h2><p>The following is the list of all the components released in v4.1:</p><div class="table"><table><thead><tr><th>Component</th><th>Purpose</th><th></th></tr></thead><tbody><tr><td>ValuesInHtmlTable</td><td>Renders Values.</td><td><a href="https://beta.tinybase.org/demos/ui-components-react/valuesinhtmltable-react">demo</a></td></tr><tr><td>TableInHtmlTable</td><td>Renders a Table.</td><td><a href="https://beta.tinybase.org/demos/ui-components-react/tableinhtmltable-react">demo</a></td></tr><tr><td>SortedTableInHtmlTable</td><td>Renders a sorted Table, with optional interactivity.</td><td><a href="https://beta.tinybase.org/demos/ui-components-react/sortedtableinhtmltable-react">demo</a></td></tr><tr><td>SliceInHtmlTable</td><td>Renders a Slice from an Index.</td><td><a href="https://beta.tinybase.org/demos/ui-components-react/sliceinhtmltable-react">demo</a></td></tr><tr><td>RelationshipInHtmlTable</td><td>Renders the local and remote Tables of a relationship</td><td><a href="https://beta.tinybase.org/demos/ui-components-react/relationshipinhtmltable-react">demo</a></td></tr><tr><td>ResultTableInHtmlTable</td><td>Renders a ResultTable.</td><td><a href="https://beta.tinybase.org/demos/ui-components-react/resulttableinhtmltable-react">demo</a></td></tr><tr><td>ResultSortedTableInHtmlTable</td><td>Renders a sorted ResultTable, with optional interactivity.</td><td><a href="https://beta.tinybase.org/demos/ui-components-react/resultsortedtableinhtmltable-react">demo</a></td></tr><tr><td>EditableCellView</td><td>Renders a Cell and lets you change its type and value.</td><td><a href="https://beta.tinybase.org/demos/ui-components-react/editablecellview-react">demo</a></td></tr><tr><td>EditableValueView</td><td>Renders a Value and lets you change its type and value.</td><td><a href="https://beta.tinybase.org/demos/ui-components-react/editablevalueview-react">demo</a></td></tr></tbody></table></div><p>These pre-built components are showcased in the <a href="https://beta.tinybase.org/demos/ui-components-react/">UI Components (React)</a> demos. Using them should be very familiar if you have used the more abstract ui-react module:</p>
|
|
723
744
|
|
|
724
745
|
```jsx
|
|
725
746
|
import React from 'react';
|
|
726
|
-
import {createRoot} from 'react-dom/client';
|
|
747
|
+
import {createRoot as createReactRoot} from 'react-dom/client';
|
|
727
748
|
import {SortedTableInHtmlTable} from 'tinybase/ui-react-dom';
|
|
728
749
|
|
|
729
750
|
const App = ({store}) => (
|
|
@@ -737,7 +758,7 @@ store.setTables({
|
|
|
737
758
|
},
|
|
738
759
|
});
|
|
739
760
|
const app = document.createElement('div');
|
|
740
|
-
const root =
|
|
761
|
+
const root = createReactRoot(app);
|
|
741
762
|
root.render(<App store={store} />);
|
|
742
763
|
|
|
743
764
|
console.log(app.innerHTML);
|
|
@@ -757,7 +778,7 @@ console.log(app.innerHTML);
|
|
|
757
778
|
root.unmount();
|
|
758
779
|
```
|
|
759
780
|
|
|
760
|
-
<p>The
|
|
781
|
+
<p>The EditableCellView component and EditableValueView component are interactive input controls for updating Cell and Value content respectively. You can generally use them across your table views by adding the <code>editable</code> prop to your table component.</p><h2 id="the-new-inspector">The new Inspector</h2><p><img src="https://beta.tinybase.org/shots/inspector-react-demo.png" alt="Inspector" title="Inspector"></p><p>The new Inspector component allows you to view, understand, and edit the content of a Store in a debug web environment. Try it out in most of the demos on the site, including the <a href="https://beta.tinybase.org/demos/movie-database/">Movie Database</a> demo, pictured. This requires a debug build of the new ui-react-dom module, which is now also included in the UMD distribution.</p><p>Also in this release, the getResultTableCellIds method and addResultTableCellIdsListener method have been added to the Queries object. The equivalent useResultTableCellIds hook and useResultTableCellIdsListener hook have also been added to ui-react module. A number of other minor React hooks have been added to support the components above.</p><p><a href="https://beta.tinybase.org/demos/">Demos</a> have been updated to demonstrate the ui-react-dom module and the Inspector component where appropriate.</p><p>(NB: Previous to v5.0, this component was called <code>StoreInspector</code>.)</p><hr><h1 id="v4-0">v4.0</h1><p>This major release provides Persister modules that connect TinyBase to SQLite databases (in both browser and server contexts), and CRDT frameworks that can provide synchronization and local-first reconciliation:</p><div class="table"><table><thead><tr><th>Module</th><th>Function</th><th>Storage</th></tr></thead><tbody><tr><td>persister-sqlite3</td><td>createSqlite3Persister</td><td>SQLite in Node, via <a href="https://github.com/TryGhost/node-sqlite3">sqlite3</a></td></tr><tr><td>persister-sqlite-wasm</td><td>createSqliteWasmPersister</td><td>SQLite in a browser, via <a href="https://github.com/tomayac/sqlite-wasm">sqlite-wasm</a></td></tr><tr><td>persister-cr-sqlite-wasm</td><td>createCrSqliteWasmPersister</td><td>SQLite CRDTs, via <a href="https://github.com/vlcn-io/cr-sqlite">cr-sqlite-wasm</a></td></tr><tr><td>persister-yjs</td><td>createYjsPersister</td><td>Yjs CRDTs, via <a href="https://github.com/yjs/yjs">yjs</a></td></tr><tr><td>persister-automerge</td><td>createSqliteWasmPersister</td><td>Automerge CRDTs, via <a href="https://github.com/automerge/automerge-repo">automerge-repo</a></td></tr></tbody></table></div><p>See the <a href="https://beta.tinybase.org/guides/persistence/database-persistence/">Database Persistence</a> guide for details on how to work with SQLite databases, and the <a href="https://beta.tinybase.org/guides/schemas-and-persistence/synchronizing-data/">Synchronizing Data</a> guide for more complex synchronization with the CRDT frameworks.</p><h2 id="sqlite-databases">SQLite databases</h2><p>You can persist Store data to a database with either a JSON serialization or tabular mapping. (See the DatabasePersisterConfig documentation for more details).</p><p>For example, this creates a Persister object and saves and loads the Store to and from a local SQLite database. It uses an explicit tabular one-to-one mapping for the 'pets' table:</p>
|
|
761
782
|
|
|
762
783
|
```js
|
|
763
784
|
store.setTables({pets: {fido: {species: 'dog'}}});
|
|
@@ -780,7 +801,7 @@ console.log(store.getTables());
|
|
|
780
801
|
await sqlitePersister.destroy();
|
|
781
802
|
```
|
|
782
803
|
|
|
783
|
-
<h2 id="crdt-frameworks">CRDT Frameworks</h2><p>CRDTs allow complex reconciliation and synchronization between clients. Yjs and Automerge are two popular examples. The
|
|
804
|
+
<h2 id="crdt-frameworks">CRDT Frameworks</h2><p>CRDTs allow complex reconciliation and synchronization between clients. Yjs and Automerge are two popular examples. The API should be familiar! The following will persist a TinyBase Store to a Yjs document:</p>
|
|
784
805
|
|
|
785
806
|
```js
|
|
786
807
|
import {createYjsPersister} from 'tinybase/persisters/persister-yjs';
|
|
@@ -819,7 +840,7 @@ await automergePersister.destroy();
|
|
|
819
840
|
store.delTables();
|
|
820
841
|
```
|
|
821
842
|
|
|
822
|
-
<h2 id="new-methods">New methods</h2><p>There are three new methods on the
|
|
843
|
+
<h2 id="new-methods">New methods</h2><p>There are three new methods on the Store object. The getContent method lets you get the Store's Tables and Values in one call. The corresponding setContent method lets you set them simultaneously.</p><p>The new setTransactionChanges method lets you replay TransactionChanges (received at the end of a transaction via listeners) into a Store, allowing you to take changes from one Store and apply them to another.</p><p>Persisters now provide a schedule method that lets you queue up asynchronous tasks, such as when persisting data that requires complex sequences of actions.</p><h2 id="breaking-changes">Breaking changes</h2><p>The way that data is provided to the DoRollback and TransactionListener callbacks at the end of a transaction has changed. Although previously they directly received content about changed Cell and Value content, they now receive functions that they can choose to call to receive that same data. This has a performance improvement, and your callback or listener can choose between concise TransactionChanges or more verbose TransactionLog structures for that data.</p><p>If you have build a custom persister, you will need to update your implementation. Most notably, the <code>setPersisted</code> function parameter is provided with a <code>getContent</code> function to get the content from the Store itself, rather than being passed pre-serialized JSON. It also receives information about the changes made during a transaction. The <code>getPersisted</code> function must return the content (or nothing) rather than JSON. <code>startListeningToPersisted</code> has been renamed <code>addPersisterListener</code>, and <code>stopListeningToPersisted</code> has been renamed <code>delPersisterListener</code>.</p><hr><h1 id="v3-3">v3.3</h1><p>This release allows you to track the Cell Ids used across a whole Table, regardless of which Row they are in.</p><p>In a Table (particularly in a Store without a TablesSchema), different Rows can use different Cells. Consider this Store, where each pet has a different set of Cell Ids:</p>
|
|
823
844
|
|
|
824
845
|
```js
|
|
825
846
|
store.setTable('pets', {
|
|
@@ -829,7 +850,7 @@ store.setTable('pets', {
|
|
|
829
850
|
});
|
|
830
851
|
```
|
|
831
852
|
|
|
832
|
-
<p>Prior to v3.3, you could only get the
|
|
853
|
+
<p>Prior to v3.3, you could only get the Cell Ids used in each Row at a time (with the getCellIds method). But you can now use the getTableCellIds method to get the union of all the Cell Ids used across the Table:</p>
|
|
833
854
|
|
|
834
855
|
```js
|
|
835
856
|
console.log(store.getCellIds('pets', 'fido')); // previously available
|
|
@@ -839,7 +860,7 @@ console.log(store.getTableCellIds('pets')); // new in v3.3
|
|
|
839
860
|
// -> ['species', 'friendly', 'legs']
|
|
840
861
|
```
|
|
841
862
|
|
|
842
|
-
<p>You can register a listener to track the
|
|
863
|
+
<p>You can register a listener to track the Cell Ids used across a Table with the new addTableCellIdsListener method. Use cases for this might include knowing which headers to render when displaying a sparse Table in a user interface, or synchronizing data with relational or column-oriented database system.</p><p>There is also a corresponding useTableCellIds hook in the optional ui-react module for accessing these Ids reactively, and a useTableCellIdsListener hook for more advanced purposes.</p><p>Note that the bookkeeping behind these new accessors and listeners is efficient and should not be slowed by the number of Rows in the Table.</p><p>This release also passes a getIdChanges function to every Id-related listener that, when called, returns information about the Id changes, both additions and removals, during a transaction. See the TableIdsListener type, for example.</p>
|
|
843
864
|
|
|
844
865
|
```js
|
|
845
866
|
let listenerId = store.addRowIdsListener(
|
|
@@ -858,7 +879,7 @@ store.delRow('pets', 'felix');
|
|
|
858
879
|
store.delListener(listenerId).delTables();
|
|
859
880
|
```
|
|
860
881
|
|
|
861
|
-
<hr><h1 id="v3-2">v3.2</h1><p>This release lets you add a listener to the start of a transaction, and detect that a set of changes are about to be made to a
|
|
882
|
+
<hr><h1 id="v3-2">v3.2</h1><p>This release lets you add a listener to the start of a transaction, and detect that a set of changes are about to be made to a Store.</p><p>To use this, call the addStartTransactionListener method on your Store. The listener you add can itself mutate the data in the Store.</p><p>From this release onwards, listeners added with the existing addWillFinishTransactionListener method are also able to mutate data. <a href="https://beta.tinybase.org/guides/the-basics/transactions/">Transactions</a> added with the existing addDidFinishTransactionListener method <em>cannot</em> mutate data.</p>
|
|
862
883
|
|
|
863
884
|
```js
|
|
864
885
|
const startListenerId = store.addStartTransactionListener(() => {
|
|
@@ -895,7 +916,7 @@ store
|
|
|
895
916
|
store.delTables();
|
|
896
917
|
```
|
|
897
918
|
|
|
898
|
-
<p>This release also fixes a bug where using the explicit
|
|
919
|
+
<p>This release also fixes a bug where using the explicit startTransaction method <em>inside</em> another listener could create infinite recursion.</p><hr><h1 id="v3-1">v3.1</h1><p>This new release adds a powerful schema-based type system to TinyBase.</p><p>If you define the shape and structure of your data with a TablesSchema or ValuesSchema, you can benefit from an enhanced developer experience when operating on it. For example:</p>
|
|
899
920
|
|
|
900
921
|
```ts ignore
|
|
901
922
|
// Import the 'with-schemas' definition:
|
|
@@ -913,7 +934,7 @@ store.setValues({employees: true}); // TypeScript error
|
|
|
913
934
|
store.setValues({employees: 3, website: 'pets.com'}); // TypeScript error
|
|
914
935
|
```
|
|
915
936
|
|
|
916
|
-
<p>The schema-based typing is used comprehensively throughout every module - from the core
|
|
937
|
+
<p>The schema-based typing is used comprehensively throughout every module - from the core Store interface all the way through to the ui-react module. See the new <a href="https://beta.tinybase.org/guides/schemas/schema-based-typing/">Schema-Based Typing</a> guide for instructions on how to use it.</p><p>This now means that there are <em>three</em> progressive ways to use TypeScript with TinyBase:</p><ul><li>Basic Type Support (since v1.0)</li><li>Schema-based Typing (since v3.1)</li><li>ORM-like type definitions (since v2.2)</li></ul><p>These are each described in the new <a href="https://beta.tinybase.org/guides/the-basics/tinybase-and-typescript/">TinyBase And TypeScript</a> guide.</p><p>Also in v3.1, the ORM-like type definition generation in the tools module has been extended to emit ui-react module definitions.</p><p>Finally, v3.1.1 adds a <code>reuseRowIds</code> parameter to the addRow method and the useAddRowCallback hook. It defaults to <code>true</code>, for backwards compatibility, but if set to <code>false</code>, new Row Ids will not be reused unless the whole Table is deleted.</p><hr><h1 id="v3-0">v3.0</h1><p>This major new release adds key/value store functionality to TinyBase. Alongside existing tabular data, it allows you to get, set, and listen to, individual Value items, each with a unique Id.</p>
|
|
917
938
|
|
|
918
939
|
```js
|
|
919
940
|
store.setValues({employees: 3, open: true});
|
|
@@ -933,7 +954,7 @@ store.setValue('employees', 4);
|
|
|
933
954
|
store.delListener(listenerId).delValues();
|
|
934
955
|
```
|
|
935
956
|
|
|
936
|
-
<p><a href="https://beta.tinybase.org/guides/">Guides</a> and documentation have been fully updated, and certain demos - such as the <a href="https://beta.tinybase.org/demos/todo-app/todo-app-v2-indexes/">Todo App v2 (indexes)</a> demo, and the <a href="https://beta.tinybase.org/demos/countries/">Countries</a> demo - have been updated to use this new functionality.</p><p>If you use the optional <a href="https://beta.tinybase.org/api/ui-react/"><code>ui-react</code></a> module with TinyBase, v3.0 now uses and expects React v18.</p><p>In terms of core <a href="https://beta.tinybase.org/api/">API</a> changes in v3.0, there are some minor breaking changes (see below), but the majority of the alterations are additions.</p><p>The <a href="https://beta.tinybase.org/api/the-essentials/creating-stores/store/"><code>Store</code></a> object gains the following:</p><ul><li>The <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/setter/setvalues/"><code>setValues</code></a> method, <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/setter/setpartialvalues/"><code>setPartialValues</code></a> method, and <a href="https://beta.tinybase.org/api/the-essentials/setting-data/setvalue/"><code>setValue</code></a> method, to set keyed value data into the <a href="https://beta.tinybase.org/api/the-essentials/creating-stores/store/"><code>Store</code></a>.</li><li>The <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/getter/getvalues/"><code>getValues</code></a> method, <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/getter/getvalueids/"><code>getValueIds</code></a> method, and <a href="https://beta.tinybase.org/api/the-essentials/getting-data/getvalue/"><code>getValue</code></a> method, to get keyed value data out of the <a href="https://beta.tinybase.org/api/the-essentials/creating-stores/store/"><code>Store</code></a>.</li><li>The <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/deleter/delvalues/"><code>delValues</code></a> method and <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/deleter/delvalue/"><code>delValue</code></a> method for removing keyed value data.</li><li>The <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/listener/addvalueslistener/"><code>addValuesListener</code></a> method, <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/listener/addvalueidslistener/"><code>addValueIdsListener</code></a> method, addValueListener method, and <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/listener/addinvalidvaluelistener/"><code>addInvalidValueListener</code></a> method, for listening to changes to keyed value data.</li><li>The <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/getter/hasvalues/"><code>hasValues</code></a> method, <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/getter/hasvalue/"><code>hasValue</code></a> method, and <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/iterator/foreachvalue/"><code>forEachValue</code></a> method, for existence and enumeration purposes.</li><li>The <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/getter/gettablesjson/"><code>getTablesJson</code></a> method, <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/getter/getvaluesjson/"><code>getValuesJson</code></a> method, <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/setter/settablesjson/"><code>setTablesJson</code></a> method, and <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/setter/setvaluesjson/"><code>setValuesJson</code></a> method, for reading and writing tabular and keyed value data to and from a JSON string. Also see below.</li><li>The <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/getter/gettablesschemajson/"><code>getTablesSchemaJson</code></a> method, <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/getter/getvaluesschemajson/"><code>getValuesSchemaJson</code></a> method, setTablesSchema method, <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/setter/setvaluesschema/"><code>setValuesSchema</code></a> method, <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/deleter/deltablesschema/"><code>delTablesSchema</code></a> method, and delValuesSchema method, for reading and writing tabular and keyed value schemas for the <a href="https://beta.tinybase.org/api/the-essentials/creating-stores/store/"><code>Store</code></a>. Also see below.</li></ul><p>The following types have been added to the <a href="https://beta.tinybase.org/api/store/"><code>store</code></a> module:</p><ul><li><a href="https://beta.tinybase.org/api/store/type-aliases/store/values/"><code>Values</code></a>, <a href="https://beta.tinybase.org/api/store/type-aliases/store/value/"><code>Value</code></a>, and <a href="https://beta.tinybase.org/api/store/type-aliases/store/valueorundefined/"><code>ValueOrUndefined</code></a>, representing keyed value data in a <a href="https://beta.tinybase.org/api/the-essentials/creating-stores/store/"><code>Store</code></a>.</li><li><a href="https://beta.tinybase.org/api/store/type-aliases/listener/valuelistener/"><code>ValueListener</code></a> and <a href="https://beta.tinybase.org/api/store/type-aliases/listener/invalidvaluelistener/"><code>InvalidValueListener</code></a>, to describe functions used to listen to (valid or invalid) changes to a <a href="https://beta.tinybase.org/api/store/type-aliases/store/value/"><code>Value</code></a>.</li><li><a href="https://beta.tinybase.org/api/store/type-aliases/schema/valuesschema/"><code>ValuesSchema</code></a> and <a href="https://beta.tinybase.org/api/store/type-aliases/schema/valueschema/"><code>ValueSchema</code></a>, to describe the keyed <a href="https://beta.tinybase.org/api/store/type-aliases/store/values/"><code>Values</code></a> that can be set in a <a href="https://beta.tinybase.org/api/the-essentials/creating-stores/store/"><code>Store</code></a> and their types.</li><li><a href="https://beta.tinybase.org/api/store/type-aliases/callback/valuecallback/"><code>ValueCallback</code></a>, <a href="https://beta.tinybase.org/api/store/type-aliases/callback/mapvalue/"><code>MapValue</code></a>, <a href="https://beta.tinybase.org/api/store/type-aliases/transaction/changedvalues/"><code>ChangedValues</code></a>, and <a href="https://beta.tinybase.org/api/store/type-aliases/transaction/invalidvalues/"><code>InvalidValues</code></a>, which also correspond to their '<a href="https://beta.tinybase.org/api/store/type-aliases/store/cell/"><code>Cell</code></a>' equivalents.</li></ul><p>Additionally:</p><ul><li>The persisters' <a href="https://beta.tinybase.org/api/persisters/interfaces/persister/persister/methods/load/load/"><code>load</code></a> method and <a href="https://beta.tinybase.org/api/persisters/interfaces/persister/persister/methods/load/startautoload/"><code>startAutoLoad</code></a> method take an optional <code>initialValues</code> parameter for setting <a href="https://beta.tinybase.org/api/store/type-aliases/store/values/"><code>Values</code></a> when a persisted <a href="https://beta.tinybase.org/api/the-essentials/creating-stores/store/"><code>Store</code></a> is bootstrapped.</li><li>The <a href="https://beta.tinybase.org/api/checkpoints/interfaces/checkpoints/checkpoints/"><code>Checkpoints</code></a> module will undo and redo changes to keyed values in the same way they do for tabular data.</li><li>The tools module provides a getStoreValuesSchema method for inferring value-based schemas. The getStoreApi method and getPrettyStoreApi method now also provides an ORM-like code-generated <a href="https://beta.tinybase.org/api/">API</a> for schematized key values.</li></ul><p>All attempts have been made to provide backwards compatibility and/or easy upgrade paths.</p><p>In previous versions, <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/getter/getjson/"><code>getJson</code></a> method would get a JSON serialization of the <a href="https://beta.tinybase.org/api/the-essentials/creating-stores/store/"><code>Store</code></a>'s tabular data. That functionality is now provided by the <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/getter/gettablesjson/"><code>getTablesJson</code></a> method, and the <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/getter/getjson/"><code>getJson</code></a> method instead now returns a two-part array containing the tabular data and the keyed value data.</p><p>Similarly, the <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/getter/getschemajson/"><code>getSchemaJson</code></a> method used to return the tabular schema, now provided by the <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/getter/gettablesschemajson/"><code>getTablesSchemaJson</code></a> method. The <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/getter/getschemajson/"><code>getSchemaJson</code></a> method instead now returns a two-part array of tabular schema and the keyed value schema.</p><p>The <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/setter/setjson/"><code>setJson</code></a> method used to take a serialization of just the tabular data object. That's now provided by the <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/setter/settablesjson/"><code>setTablesJson</code></a> method, and the <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/setter/setjson/"><code>setJson</code></a> method instead expects a two-part array containing the tabular data and the keyed value data (as emitted by the <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/getter/getjson/"><code>getJson</code></a> method). However, for backwards compatibility, if the <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/setter/setjson/"><code>setJson</code></a> method is passed an object, it <em>will</em> set the tabular data, as it did prior to v3.0.</p><p>Along similar lines, the <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/setter/setschema/"><code>setSchema</code></a> method's previous behavior is now provided by the <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/setter/settablesschema/"><code>setTablesSchema</code></a> method. The <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/setter/setschema/"><code>setSchema</code></a> method now takes two arguments, the second of which is optional, also aiding backward compatibility. The <a href="https://beta.tinybase.org/api/mergeable-store/interfaces/mergeable/mergeablestore/methods/deleter/delschema/"><code>delSchema</code></a> method removes both types of schema.</p><hr><h1 id="v2-2">v2.2</h1><p>Note: The tools module has been removed in TinyBase v6.0.</p><p>This release includes a new tools module. These tools are not intended for production use, but are instead to be used as part of your engineering workflow to perform tasks like generating APIs from schemas, or schemas from data. For example:</p>
|
|
957
|
+
<p><a href="https://beta.tinybase.org/guides/">Guides</a> and documentation have been fully updated, and certain demos - such as the <a href="https://beta.tinybase.org/demos/todo-app/todo-app-v2-indexes/">Todo App v2 (indexes)</a> demo, and the <a href="https://beta.tinybase.org/demos/countries/">Countries</a> demo - have been updated to use this new functionality.</p><p>If you use the optional ui-react module with TinyBase, v3.0 now uses and expects React v18.</p><p>In terms of core API changes in v3.0, there are some minor breaking changes (see below), but the majority of the alterations are additions.</p><p>The Store object gains the following:</p><ul><li>The setValues method, setPartialValues method, and setValue method, to set keyed value data into the Store.</li><li>The getValues method, getValueIds method, and getValue method, to get keyed value data out of the Store.</li><li>The delValues method and delValue method for removing keyed value data.</li><li>The addValuesListener method, addValueIdsListener method, addValueListener method, and addInvalidValueListener method, for listening to changes to keyed value data.</li><li>The hasValues method, hasValue method, and forEachValue method, for existence and enumeration purposes.</li><li>The getTablesJson method, getValuesJson method, setTablesJson method, and setValuesJson method, for reading and writing tabular and keyed value data to and from a JSON string. Also see below.</li><li>The getTablesSchemaJson method, getValuesSchemaJson method, setTablesSchema method, setValuesSchema method, delTablesSchema method, and delValuesSchema method, for reading and writing tabular and keyed value schemas for the Store. Also see below.</li></ul><p>The following types have been added to the store module:</p><ul><li>Values, Value, and ValueOrUndefined, representing keyed value data in a Store.</li><li>ValueListener and InvalidValueListener, to describe functions used to listen to (valid or invalid) changes to a Value.</li><li>ValuesSchema and ValueSchema, to describe the keyed Values that can be set in a Store and their types.</li><li>ValueCallback, MapValue, ChangedValues, and InvalidValues, which also correspond to their 'Cell' equivalents.</li></ul><p>Additionally:</p><ul><li>The persisters' load method and startAutoLoad method take an optional <code>initialValues</code> parameter for setting Values when a persisted Store is bootstrapped.</li><li>The Checkpoints module will undo and redo changes to keyed values in the same way they do for tabular data.</li><li>The tools module provides a getStoreValuesSchema method for inferring value-based schemas. The getStoreApi method and getPrettyStoreApi method now also provides an ORM-like code-generated API for schematized key values.</li></ul><p>All attempts have been made to provide backwards compatibility and/or easy upgrade paths.</p><p>In previous versions, getJson method would get a JSON serialization of the Store's tabular data. That functionality is now provided by the getTablesJson method, and the getJson method instead now returns a two-part array containing the tabular data and the keyed value data.</p><p>Similarly, the getSchemaJson method used to return the tabular schema, now provided by the getTablesSchemaJson method. The getSchemaJson method instead now returns a two-part array of tabular schema and the keyed value schema.</p><p>The setJson method used to take a serialization of just the tabular data object. That's now provided by the setTablesJson method, and the setJson method instead expects a two-part array containing the tabular data and the keyed value data (as emitted by the getJson method). However, for backwards compatibility, if the setJson method is passed an object, it <em>will</em> set the tabular data, as it did prior to v3.0.</p><p>Along similar lines, the setSchema method's previous behavior is now provided by the setTablesSchema method. The setSchema method now takes two arguments, the second of which is optional, also aiding backward compatibility. The delSchema method removes both types of schema.</p><hr><h1 id="v2-2">v2.2</h1><p>Note: The tools module has been removed in TinyBase v6.0.</p><p>This release includes a new tools module. These tools are not intended for production use, but are instead to be used as part of your engineering workflow to perform tasks like generating APIs from schemas, or schemas from data. For example:</p>
|
|
937
958
|
|
|
938
959
|
```js ignore
|
|
939
960
|
import {createTools} from 'tinybase/tools';
|
|
@@ -973,7 +994,7 @@ npx tinybase getStoreApi schema.json shop api
|
|
|
973
994
|
Implementation: [...]/api/shop.ts
|
|
974
995
|
```
|
|
975
996
|
|
|
976
|
-
<p>Finally, the tools module also provides ways to track the overall size and structure of a
|
|
997
|
+
<p>Finally, the tools module also provides ways to track the overall size and structure of a Store for use while debugging.</p><hr><h1 id="v2-1">v2.1</h1><p>This release allows you to create indexes where a single Row Id can exist in multiple slices. You can utilize this to build simple keyword searches, for example.</p><p>Simply provide a custom getSliceIdOrIds function in the setIndexDefinition method that returns an array of Slice Ids, rather than a single Id:</p>
|
|
977
998
|
|
|
978
999
|
```js
|
|
979
1000
|
import {createIndexes} from 'tinybase';
|
|
@@ -997,7 +1018,7 @@ console.log(indexes.getSliceRowIds('containsLetter', 'x'));
|
|
|
997
1018
|
// -> ['felix', 'rex']
|
|
998
1019
|
```
|
|
999
1020
|
|
|
1000
|
-
<p>This functionality is showcased in the <a href="https://beta.tinybase.org/demos/word-frequencies/">Word Frequencies</a> demo if you would like to see it in action.</p><hr><h1 id="v2-0">v2.0</h1><p><strong>Announcing the next major version of TinyBase 2.0!</strong> This is an exciting release that evolves TinyBase towards becoming a reactive, relational data store, complete with querying, sorting, and pagination. Here are a few of the highlights...</p><h2 id="query-engine">Query Engine</h2><p>The <a href="https://beta.tinybase.org/guides/making-queries/using-queries/">flagship feature</a> of this release is the new
|
|
1021
|
+
<p>This functionality is showcased in the <a href="https://beta.tinybase.org/demos/word-frequencies/">Word Frequencies</a> demo if you would like to see it in action.</p><hr><h1 id="v2-0">v2.0</h1><p><strong>Announcing the next major version of TinyBase 2.0!</strong> This is an exciting release that evolves TinyBase towards becoming a reactive, relational data store, complete with querying, sorting, and pagination. Here are a few of the highlights...</p><h2 id="query-engine">Query Engine</h2><p>The <a href="https://beta.tinybase.org/guides/making-queries/using-queries/">flagship feature</a> of this release is the new queries module. This allows you to build expressive queries against your data with a SQL-adjacent API that we've cheekily called <a href="https://beta.tinybase.org/guides/making-queries/tinyql/">TinyQL</a>. The query engine lets you select, join, filter, group, sort and paginate data. And of course, it's all reactive!</p><p>The best way to see the power of this new engine is with the two new demos we've included this release:</p><p><img src="https://beta.tinybase.org/shots/car-analysis-demo.png" alt="Car Analysis demo screenshot"></p><p>The <a href="https://beta.tinybase.org/demos/car-analysis/">Car Analysis</a> demo showcases the analytical query capabilities of TinyBase v2.0, grouping and sorting dimensional data for lightweight analytical usage, graphing, and tabular display. <em><a href="https://beta.tinybase.org/demos/car-analysis/">Try this demo here</a>.</em></p><p><img src="https://beta.tinybase.org/shots/movie-database-demo.png" alt="Movie Database demo screenshot"></p><p>The <a href="https://beta.tinybase.org/demos/movie-database/">Movie Database</a> demo showcases the relational query capabilities of TinyBase v2.0, joining together information about movies, directors, and actors from across multiple source tables. <em><a href="https://beta.tinybase.org/demos/movie-database/">Try this demo here</a>.</em></p><h2 id="sorting-and-pagination">Sorting and Pagination</h2><p>To complement the query engine, you can now sort and paginate Row Ids. This makes it very easy to build grid-like user interfaces (also shown in the demos above). To achieve this, the Store now includes the getSortedRowIds method (and the addSortedRowIdsListener method for reactivity), and the Queries object includes the equivalent getResultSortedRowIds method and addResultSortedRowIdsListener method.</p><p>These are also exposed in the optional ui-react module via the useSortedRowIds hook, the useResultSortedRowIds hook, the SortedTableView component and the ResultSortedTableView component, and so on.</p><h2 id="queries-in-the-ui-react-module">Queries in the ui-react module</h2><p>The v2.0 query functionality is fully supported by the ui-react module (to match support for Store, Metrics, Indexes, and Relationship objects). The useCreateQueries hook memoizes the creation of app- or component-wide Query objects; and the useResultTable hook, useResultRow hook, useResultCell hook (and so on) let you bind you component to the results of a query.</p><p>This is, of course, supplemented with higher-level components: the ResultTableView component, the ResultRowView component, the ResultCellView component, and so on. See the <a href="https://beta.tinybase.org/guides/using-queries/building-a-ui-with-queries/">Building A UI With Queries</a> guide for more details.</p><h2 id="it-s-a-big-release">It's a big release!</h2><p>Thank you for all your support as we brought this important new release to life, and we hope you enjoy using it as much as we did building it. Please provide feedback via <a href="https://github.com/tinyplex/tinybase">GitHub</a>, <a href="https://bsky.app/profile/tinybase.bsky.social">Bluesky</a>, and <a href="https://x.com/tinybasejs">X</a>!</p><hr><h1 id="v1-3">v1.3</h1><p>Adds support for explicit transaction start and finish methods, as well as listeners for transactions finishing.</p><p>The startTransaction method and finishTransaction method allow you to explicitly enclose a transaction that will make multiple mutations to the Store, buffering all calls to the relevant listeners until it completes when you call the finishTransaction method.</p><p>Unlike the transaction method, this approach is useful when you have a more 'open-ended' transaction, such as one containing mutations triggered from other events that are asynchronous or not occurring inline to your code. You must remember to also call the finishTransaction method explicitly when the transaction is started with the startTransaction method, of course.</p>
|
|
1001
1022
|
|
|
1002
1023
|
```js
|
|
1003
1024
|
store.setTables({pets: {fido: {species: 'dog'}}});
|
|
@@ -1010,4 +1031,4 @@ store.finishTransaction();
|
|
|
1010
1031
|
// -> 'Fido changed'
|
|
1011
1032
|
```
|
|
1012
1033
|
|
|
1013
|
-
<p>In addition, see the
|
|
1034
|
+
<p>In addition, see the addWillFinishTransactionListener method and the addDidFinishTransactionListener method for details around listening to transactions completing.</p><p>Together, this release allows stores to couple their transaction life-cycles together, which we need for the query engine.</p><p>Note: this API was updated to be more comprehensive in v4.0.</p><hr><h1 id="v1-2">v1.2</h1><p>This adds a way to revert transactions if they have not met certain conditions.</p><p>When using the transaction method, you can provide an optional <code>doRollback</code> callback which should return true if you want to revert the whole transaction at its conclusion.</p><p>The callback is provided with two objects, <code>changedCells</code> and <code>invalidCells</code>, which list all the net changes and invalid attempts at changes that were made during the transaction. You will most likely use the contents of those objects to decide whether the transaction should be rolled back.</p><p>Note: this API was updated to be more comprehensive in v4.0.</p><hr><h1 id="v1-1">v1.1</h1><p>This release allows you to listen to invalid data being added to a Store, allowing you to gracefully handle errors, rather than them failing silently.</p><p>There is a new listener type InvalidCellListener and a addInvalidCellListener method in the Store interface.</p><p>These allow you to keep track of failed attempts to update the Store with invalid Cell data. These listeners can also be mutators, allowing you to address any failed writes programmatically.</p><p>For more information, please see the addInvalidCellListener method documentation. In particular, this explains how this listener behaves for a Store with a TablesSchema.</p>
|