TinyBase logoTinyBase

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 of Table objects.
  • Each Table contains a number of Row objects.
  • Each Row contains a number of Cell 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:

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.

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

Getter methods

This is the collection of getter methods within the Store interface. There are 29 getter methods in total.

Setter methods

This is the collection of setter methods within the Store interface. There are 17 setter methods in total.

Listener methods

This is the collection of listener methods within the Store interface. There are 27 listener methods in total.

Iterator methods

This is the collection of iterator methods within the Store interface. There are 5 iterator methods in total.

Transaction methods

This is the collection of transaction methods within the Store interface. There are only three transaction methods, finishTransaction, startTransaction, and transaction.

Deleter methods

This is the collection of deleter methods within the Store interface. There are 9 deleter methods in total.

Development methods

This is the collection of development methods within the Store interface. There is only one method, getListenerStats.