Store
A Store
is the main location for keeping both tabular data and keyed values.
Create a Store
easily with the createStore
function. From there, you can set and get data, add listeners for when the data changes, set schemas, and so on.
A Store
has two facets. It can contain keyed Values
, and independently, it can contain tabular Tables
data. These two facets have similar APIs but can be used entirely independently: you can use only tables, only keyed Values
, or both tables and keyed Values
- all in a single Store
.
Keyed values
The keyed value support is best thought of as a flat JavaScript object. The Store
contains a number of Value
objects, each with a unique ID, and which is a string, boolean, or number.
{ // Store
"value1": "one", // Value (string)
"value2": true, // Value (boolean)
"value3": 3, // Value (number)
...
}
In its default form, a Store
has no sense of a structured schema for the Values
. However, you can optionally specify a ValuesSchema
for a Store
, which then usefully constrains and defaults the Values
you can use.
Tabular data
The tabular data exists in a simple hierarchical structure:
- The
Store
contains a number ofTable
objects. - Each
Table
contains a number ofRow
objects. - Each
Row
contains a number ofCell
objects.
A Cell
is a string, boolean, or number value.
The members of each level of this hierarchy are identified with a unique Id
(which is a string). In other words you can naively think of a Store
as a three-level-deep JavaScript object, keyed with strings:
{ // Store
"table1": { // Table
"row1": { // Row
"cell1": "one", // Cell (string)
"cell2": true, // Cell (boolean)
"cell3": 3, // Cell (number)
...
},
...
},
...
}
Again, by default Store
has no sense of a structured schema. As long as they are unique within their own parent, the Id
keys can each be any string you want. However, as you can optionally specify a TablesSchema
for the tabular data in a Store
, which then usefully constrains the Table
and Cell
Ids
(and Cell
values) you can use.
Setting and getting data
Every part of the Store
can be accessed with getter methods. When you retrieve data from the Store
, you are receiving a copy - rather than a reference - of it. This means that manipulating the data in the Store
must be performed with the equivalent setter and deleter methods.
To benefit from the reactive behavior of the Store
, you can also subscribe to changes on any part of it with 'listeners'. Registering a listener returns a listener Id
(that you can use later to remove it with the delListener
method), and it will then be called every time there is a change within the part of the hierarchy you're listening to.
This table shows the main ways you can set, get, and listen to, different types of data in a Store
:
There are two extra methods to manipulate Row
objects. The addRow
method is like the setRow
method but automatically assigns it a new unique Id
. And the setPartialRow
method lets you update multiple Cell
values in a Row
without affecting the others. There is a similar setPartialValues
method to do the same for the Values
in a Store
.
You can listen to attempts to write invalid data to a Value
or Cell
with the addInvalidValueListener
method or addInvalidCellListener
method.
The transaction
method is used to wrap multiple changes to the Store
so that the relevant listeners only fire once.
The setJson
method and the getJson
method allow you to work with a JSON-encoded representation of the entire Store
, which is useful for persisting it.
Finally, the callListener
method provides a way for you to manually provoke a listener to be called, even if the underlying data hasn't changed. This is useful when you are using mutator listeners to guarantee that data conforms to programmatic conditions, and those conditions change such that you need to update the Store
in bulk.
Read more about setting and changing data in The Basics guides, and about listeners in the Listening to Stores guide.
Creating a schema
You can set a ValuesSchema
and a TablesSchema
with the setValuesSchema
method and setTablesSchema
method respectively. A TablesSchema
constrains the Table
Ids
the Store
can have, and the types of Cell
data in each Table
. Each Cell
requires its type to be specified, and can also take a default value for when it's not specified.
You can also get a serialization of the schemas out of the Store
with the getSchemaJson
method, and remove the schemas altogether with the delValuesSchema
method and delTablesSchema
method.
Read more about schemas in the Using Schemas guide.
Convenience methods
There are a few additional helper methods to make it easier to work with a Store
. There are methods for easily checking the existence of a Table
, Row
, or Cell
, and iterators that let you act on the children of a common parent:
Checking existence | Iterator | |
---|---|---|
Value | hasValue | forEachValue |
Table | hasTable | forEachTable |
Row | hasRow | forEachRow |
Cell | hasCell | forEachCell |
Since v4.3.23, you can add listeners for the change of existence of part of a Store
. For example, the addHasValueListener
method lets you listen for a Value
being added or removed.
Finally, the getListenerStats
method describes the current state of the Store
's listeners for debugging purposes.
Example
This example shows a very simple lifecycle of a Store
: from creation, to adding and getting some data, and then registering and removing a listener.
import {createStore} from 'tinybase';
const store = createStore().setTables({pets: {fido: {species: 'dog'}}});
console.log(store.getRow('pets', 'fido'));
// -> {species: 'dog'}
store.setCell('pets', 'fido', 'color', 'brown');
console.log(store.getCell('pets', 'fido', 'color'));
// -> 'brown'
const listenerId = store.addTableListener('pets', () => {
console.log('changed');
});
store.setCell('pets', 'fido', 'sold', false);
// -> 'changed'
store.delListener(listenerId);
See also
- The Basics guides
- Using Schemas guides
- Hello World demos
- Todo App demos
Since
v1.0.0
Methods
These are the methods within the Store
interface.
Properties
There is one property, isMergeable
, within the Store
interface.