tinybase
Version:
A reactive data store and sync engine.
1,140 lines (1,106 loc) • 37 kB
TypeScript
/**
* The mergeable-store module contains the types, interfaces, and functions to
* work with MergeableStore objects, which provide merge and synchronization
* functionality.
*
* The main entry point to this module is the createMergeableStore function,
* which returns a new MergeableStore, a subtype of Store that can be merged
* with another with deterministic results.
*
* Please be aware that a lot of the types and methods exposed by this module
* are used internally within TinyBase itself (in particular the Synchronizer
* framework). They're documented here, but mostly for interest, and it is
* generally assumed that they won't be called directly by applications.
*
* As an application developer, it's more likely that you will continue to use
* the main Store methods for reading, writing, and listening to data, and rely
* on Synchronizer instances to keep the data in step with other places.
* @packageDocumentation
* @module mergeable-store
* @since v5.0.0
*/
import type {Id} from '../common/index.d.ts';
import type {
CellOrUndefined,
Content,
Store,
ValueOrUndefined,
} from '../store/index.d.ts';
/**
* The Hash type is used within the mergeable-store module to quickly compare
* the content of two objects.
*
* This is simply an alias for a JavaScript `number`.
*
* This type is mostly utilized internally within TinyBase itself and is
* generally assumed to be opaque to applications that use it.
* @category Stamps
* @since v5.0.0
*/
export type Hash = number;
/**
* The Time type is used within the mergeable-store module to store the value of
* a hybrid logical clock (HLC).
*
* It is simply an alias for a JavaScript `string`, but it comprises three HLC
* parts: a logical timestamp, a sequence counter, and a client Id. It is
* designed to be string-sortable and unique across all of the systems involved
* in synchronizing a MergeableStore.
*
* This type is mostly utilized internally within TinyBase itself and is
* generally assumed to be opaque to applications that use it.
* @category Stamps
* @since v5.0.0
*/
export type Time = string;
/**
* The Stamp type is used as metadata to decide how to merge two different
* MergeableStore objects together.
*
* It describes a combination of a value (or object), a Time, and optionally a
* Hash, all in an array.
*
* This type is mostly utilized internally within TinyBase itself and is
* generally assumed to be opaque to applications that use it.
* @category Stamps
* @since v5.0.0
*/
export type Stamp<Thing, Hashed extends boolean = false> = Hashed extends true
? [thing: Thing, time: Time, hash: Hash]
: [thing: Thing, time?: Time];
/**
* The ContentHashes type is used to quickly compare the content of two
* MergeableStore objects.
*
* It is simply an array of two Hash types, one for the MergeableStore's Tables
* and one for its Values.
*
* This type is mostly utilized internally within TinyBase itself and is
* generally assumed to be opaque to applications that use it.
* @category Syncing
* @since v5.0.0
*/
export type ContentHashes = [tablesHash: Hash, valuesHash: Hash];
/**
* The TablesStamp type is used as metadata to decide how to merge two different
* sets of Tables together.
*
* This type is mostly utilized internally within TinyBase itself and is
* generally assumed to be opaque to applications that use it.
* @category Stamps
* @since v5.0.0
*/
export type TablesStamp<Hashed extends boolean = false> = Stamp<
{[tableId: Id]: TableStamp<Hashed>},
Hashed
>;
/**
* The TableHashes type is used to quickly compare the content of two sets of
* Table objects.
*
* It is simply an object of Hash types, one for each Table Id in the
* MergeableStore.
*
* This type is mostly utilized internally within TinyBase itself and is
* generally assumed to be opaque to applications that use it.
* @category Syncing
* @since v5.0.0
*/
export type TableHashes = {[tableId: Id]: Hash};
/**
* The TableStamp type is used as metadata to decide how to merge two different
* Table objects together.
*
* This type is mostly utilized internally within TinyBase itself and is
* generally assumed to be opaque to applications that use it.
* @category Stamps
* @since v5.0.0
*/
export type TableStamp<Hashed extends boolean = false> = Stamp<
{[rowId: Id]: RowStamp<Hashed>},
Hashed
>;
/**
* The RowHashes type is used to quickly compare the content of two sets of Row
* objects.
*
* It is simply a nested object of Hash types, one for each Row Id, for each
* TableId, in the MergeableStore.
*
* This type is mostly utilized internally within TinyBase itself and is
* generally assumed to be opaque to applications that use it.
* @category Syncing
* @since v5.0.0
*/
export type RowHashes = {[tableId: Id]: {[rowId: Id]: Hash}};
/**
* The RowStamp type is used as metadata to decide how to merge two different
* Row objects together.
*
* This type is mostly utilized internally within TinyBase itself and is
* generally assumed to be opaque to applications that use it.
* @category Stamps
* @since v5.0.0
*/
export type RowStamp<Hashed extends boolean = false> = Stamp<
{[cellId: Id]: CellStamp<Hashed>},
Hashed
>;
/**
* The CellHashes type is used to quickly compare the content of two sets of
* Cell objects.
*
* It is simply a nested object of Hash types, one for each Cell Id, for each
* Row Id, for each TableId, in the MergeableStore.
*
* This type is mostly utilized internally within TinyBase itself and is
* generally assumed to be opaque to applications that use it.
* @category Syncing
* @since v5.0.0
*/
export type CellHashes = {[tableId: Id]: {[rowId: Id]: {[cellId: Id]: Hash}}};
/**
* The CellStamp type is used as metadata to decide how to merge two different
* Cell objects together.
*
* This type is mostly utilized internally within TinyBase itself and is
* generally assumed to be opaque to applications that use it.
* @category Stamps
* @since v5.0.0
*/
export type CellStamp<Hashed extends boolean = false> = Stamp<
CellOrUndefined,
Hashed
>;
/**
* The ValuesStamp type is used as metadata to decide how to merge two different
* sets of Values together.
*
* This type is mostly utilized internally within TinyBase itself and is
* generally assumed to be opaque to applications that use it.
* @category Stamps
* @since v5.0.0
*/
export type ValuesStamp<Hashed extends boolean = false> = Stamp<
{[valueId: Id]: ValueStamp<Hashed>},
Hashed
>;
/**
* The ValueHashes type is used to quickly compare the content of two sets of
* Value objects.
*
* It is simply an object of Hash types, one for each Value Id in the
* MergeableStore.
*
* This type is mostly utilized internally within TinyBase itself and is
* generally assumed to be opaque to applications that use it.
* @category Syncing
* @since v5.0.0
*/
export type ValueHashes = {[valueId: Id]: Hash};
/**
* The ValueStamp type is used as metadata to decide how to merge two different
* Value objects together.
*
* This type is mostly utilized internally within TinyBase itself and is
* generally assumed to be opaque to applications that use it.
* @category Stamps
* @since v5.0.0
*/
export type ValueStamp<Hashed extends boolean = false> = Stamp<
ValueOrUndefined,
Hashed
>;
/**
* The MergeableContent type represents the content of a MergeableStore and the
* metadata about that content) required to merge it with another.
*
* It is simply an array of two Stamp types, one for the MergeableStore's Tables
* and one for its Values.
*
* This type is mostly utilized internally within TinyBase itself and is
* generally assumed to be opaque to applications that use it.
* @category Mergeable
* @since v5.0.0
*/
export type MergeableContent = [
mergeableTables: TablesStamp<true>,
mergeableValues: ValuesStamp<true>,
];
/**
* The MergeableChanges type represents changes to the content of a
* MergeableStore and the metadata about that content) required to merge it with
* another.
*
* It is simply an array of two Stamp types, one for changes to the
* MergeableStore's Tables and one for changes to its Values. A final `1` is
* used to distinguish it from a full MergeableContent object.
*
* This type is mostly utilized internally within TinyBase itself and is
* generally assumed to be opaque to applications that use it.
* @category Mergeable
* @since v5.0.0
*/
export type MergeableChanges<Hashed extends boolean = false> = [
mergeableTables: TablesStamp<Hashed>,
mergeableValues: ValuesStamp<Hashed>,
isChanges: 1,
];
/**
* The MergeableStore type represents a Store that carries with it sufficient
* metadata to be able to be merged with another MergeableStore with
* deterministic results.
*
* This is the key data type used when you need TinyBase data to be cleanly
* synchronized or merged with data elsewhere on the system, or on another
* system. It acts as a Conflict-Free Replicated Data Type (CRDT) which allows
* deterministic disambiguation of how changes to different instances should be
* merged.
*
* Please be aware that a lot of the methods exposed by this interface are used
* internally within TinyBase itself (in particular the Synchronizer framework).
* They're documented here, but mostly for interest, and it is generally assumed
* that they won't be called directly by applications.
*
* As an application developer, it's more likely that you will continue to use
* the main Store methods for reading, writing, and listening to data, and rely
* on Synchronizer instances to keep the data in step with other places.
*
* One possible exceptions is the merge method, which can be used to simply
* merge two co-located MergeableStore instances together.
* @example
* This example shows very simple usage of the MergeableStore: whereby two are
* created, updated with different data, and then merged with one another.
*
* ```js
* import {createMergeableStore} from 'tinybase';
*
* const localStore1 = createMergeableStore();
* const localStore2 = createMergeableStore();
*
* localStore1.setCell('pets', 'fido', 'color', 'brown');
* localStore2.setCell('pets', 'felix', 'color', 'black');
*
* localStore1.merge(localStore2);
*
* console.log(localStore1.getContent());
* // -> [{pets: {felix: {color: 'black'}, fido: {color: 'brown'}}}, {}]
*
* console.log(localStore2.getContent());
* // -> [{pets: {felix: {color: 'black'}, fido: {color: 'brown'}}}, {}]
*```
* @category Mergeable
* @since v5.0.0
*/
export interface MergeableStore extends Store {
//
/**
* The getMergeableContent method returns the full content of a
* MergeableStore, together with the metadata required to make it mergeable
* with another.
*
* The method is generally intended to be used internally within TinyBase
* itself and the return type is assumed to be opaque to applications that use
* it.
* @returns A MergeableContent object for the full content of the
* MergeableStore.
* @example
* This example creates a MergeableStore, sets some data, and then accesses
* the content and metadata required to make it mergeable.
*
* ```js
* import {createMergeableStore} from 'tinybase';
*
* const store = createMergeableStore('store1'); // !resetHlc
*
* store.setCell('pets', 'fido', 'color', 'brown');
*
* console.log(store.getMergeableContent());
* // ->
* [
* [
* {
* pets: [
* {
* fido: [
* {color: ['brown', 'Nn1JUF-----FnHIC', 923684530]},
* '',
* 851131566,
* ],
* },
* '',
* 518810247,
* ],
* },
* '',
* 784336119,
* ],
* [{}, '', 0],
* ];
* ```
* @category Getter
* @since v5.0.0
*/
getMergeableContent(): MergeableContent;
/**
* The getMergeableContentHashes method returns hashes for the full content of
* a MergeableStore.
*
* If two MergeableStore instances have different hashes, that indicates that
* the mergeable Tables or Values within them are different and should be
* synchronized.
*
* The method is generally intended to be used internally within TinyBase
* itself and the return type is assumed to be opaque to applications that use
* it.
* @returns A ContentHashes array for the hashes of the full content of the
* MergeableStore.
* @example
* This example creates a MergeableStore, sets some data, and then accesses
* the content hashes.
*
* ```js
* import {createMergeableStore} from 'tinybase';
*
* const store = createMergeableStore('store1'); // !resetHlc
*
* store.setCell('pets', 'fido', 'color', 'brown');
* console.log(store.getMergeableContentHashes());
* // -> [784336119, 0]
*
* store.setValue('open', true);
* console.log(store.getMergeableContentHashes());
* // -> [784336119, 2829789038]
* ```
* @category Syncing
* @since v5.0.0
*/
getMergeableContentHashes(): ContentHashes;
/**
* The getMergeableTableHashes method returns hashes for the Table objects in
* a MergeableStore.
*
* If two Table Ids have different hashes, that indicates that the content
* within them is different and should be synchronized.
*
* The method is generally intended to be used internally within TinyBase
* itself and the return type is assumed to be opaque to applications that use
* it.
* @returns A TableHashes object with the hashes of each Table in the
* MergeableStore.
* @example
* This example creates a MergeableStore, sets some data, and then accesses
* the Table hashes.
*
* ```js
* import {createMergeableStore} from 'tinybase';
*
* const store = createMergeableStore('store1'); // !resetHlc
*
* store.setCell('pets', 'fido', 'color', 'brown');
* console.log(store.getMergeableTableHashes());
* // -> {pets: 518810247}
*
* store.setCell('species', 'dog', 'price', 5);
* console.log(store.getMergeableTableHashes());
* // -> {pets: 518810247, species: 2324343240}
* ```
* @category Syncing
* @since v5.0.0
*/
getMergeableTableHashes(): TableHashes;
/**
* The getMergeableTableDiff method returns information about new and
* differing Table objects of a MergeableStore relative to another.
*
* The method is generally intended to be used internally within TinyBase
* itself and the return type is assumed to be opaque to applications that use
* it.
* @param otherTableHashes The TableHashes of another MergeableStore.
* @returns A pair of objects describing the new and differing Table objects
* of this MergeableStore relative to the other.
* @example
* This example creates two MergeableStores, sets some differing data, and
* then identifies the differences in the Table objects of one versus the
* other. Once they have been merged, the differences are empty.
*
* ```js
* import {createMergeableStore} from 'tinybase';
*
* const store1 = createMergeableStore('store1'); // !resetHlc
* store1.setTables({pets: {fido: {color: 'brown'}}});
*
* const store2 = createMergeableStore('store2');
* store2.setTables({
* pets: {fido: {species: 'dog'}},
* species: {dog: {price: 5}},
* });
*
* console.log(
* store2.getMergeableTableDiff(store1.getMergeableTableHashes()),
* );
* // ->
* [
* [{species: [{dog: [{price: [5, 'Nn1JUF----0CnH-J']}]}]}],
* {pets: 1212600658},
* ];
*
* store1.merge(store2);
*
* console.log(
* store2.getMergeableTableDiff(store1.getMergeableTableHashes()),
* );
* // -> [[{}], {}]
* ```
* @category Syncing
* @since v5.0.0
*/
getMergeableTableDiff(
otherTableHashes: TableHashes,
): [newTables: TablesStamp, differingTableHashes: TableHashes];
/**
* The getMergeableRowHashes method returns hashes for Row objects in a
* MergeableStore.
*
* If two Row Ids have different hashes, that indicates that the content
* within them is different and should be synchronized.
*
* The method is generally intended to be used internally within TinyBase
* itself and the return type is assumed to be opaque to applications that use
* it.
* @param otherTableHashes The TableHashes from the other MergeableStore so
* that the differences can be efficiently identified.
* @returns A RowHashes object with the hashes of each Row in the relevant
* Table objects of the MergeableStore.
* @example
* This example creates a MergeableStore, sets some data, and then accesses
* the Row hashes for the differing Table Ids.
*
* ```js
* import {createMergeableStore} from 'tinybase';
*
* const store1 = createMergeableStore('store1'); // !resetHlc
* store1.setTables({pets: {fido: {color: 'brown'}, felix: {color: 'tan'}}});
*
* const store2 = createMergeableStore('store2');
* store2.setTables({pets: {fido: {color: 'black'}, felix: {color: 'tan'}}});
*
* console.log(
* store1.getMergeableRowHashes(
* store2.getMergeableTableDiff(store1.getMergeableTableHashes())[1],
* ),
* );
* // -> {pets: {felix: 1683761402, fido: 851131566}}
* ```
* @category Syncing
* @since v5.0.0
*/
getMergeableRowHashes(otherTableHashes: TableHashes): RowHashes;
/**
* The getMergeableRowDiff method returns information about new and differing
* Row objects of a MergeableStore relative to another.
*
* The method is generally intended to be used internally within TinyBase
* itself and the return type is assumed to be opaque to applications that use
* it.
* @param otherTableRowHashes The RowHashes of another MergeableStore.
* @returns A pair of objects describing the new and differing Row objects of
* this MergeableStore relative to the other.
* @example
* This example creates two MergeableStores, sets some differing data, and
* then identifies the differences in the Row objects of one versus the other.
* Once they have been merged, the differences are empty.
*
* ```js
* import {createMergeableStore} from 'tinybase';
*
* const store1 = createMergeableStore('store1'); // !resetHlc
* store1.setTables({pets: {fido: {color: 'brown'}}});
*
* const store2 = createMergeableStore('store2');
* store2.setTables({pets: {fido: {color: 'black'}, felix: {color: 'tan'}}});
*
* console.log(
* store2.getMergeableRowDiff(
* store1.getMergeableRowHashes(
* store2.getMergeableTableDiff(store1.getMergeableTableHashes())[1],
* ),
* ),
* );
* // ->
* [
* [{pets: [{felix: [{color: ['tan', 'Nn1JUF----0CnH-J']}]}]}],
* {pets: {fido: 1038491054}},
* ];
*
* store1.merge(store2);
*
* console.log(
* store2.getMergeableRowDiff(
* store1.getMergeableRowHashes(
* store2.getMergeableTableDiff(store1.getMergeableTableHashes())[1],
* ),
* ),
* );
* // -> [[{}], {}]
* ```
* @category Syncing
* @since v5.0.0
*/
getMergeableRowDiff(
otherTableRowHashes: RowHashes,
): [newRows: TablesStamp, differingRowHashes: RowHashes];
/**
* The getMergeableCellHashes method returns hashes for Cell objects in a
* MergeableStore.
*
* If two Cell Ids have different hashes, that indicates that the content
* within them is different and should be synchronized.
*
* The method is generally intended to be used internally within TinyBase
* itself and the return type is assumed to be opaque to applications that use
* it.
* @param otherTableRowHashes The RowHashes from the other MergeableStore so
* that the differences can be efficiently identified.
* @returns A CellHashes object with the hashes of each Cell in the relevant
* Row objects of the MergeableStore.
* @example
* This example creates a MergeableStore, sets some data, and then accesses
* the Cell hashes for the differing Table Ids.
*
* ```js
* import {createMergeableStore} from 'tinybase';
*
* const store1 = createMergeableStore('store1'); // !resetHlc
* store1.setTables({pets: {fido: {color: 'brown', species: 'dog'}}});
*
* const store2 = createMergeableStore('store2');
* store2.setTables({pets: {fido: {color: 'black', species: 'dog'}}});
*
* console.log(
* store1.getMergeableCellHashes(
* store2.getMergeableRowDiff(
* store1.getMergeableRowHashes(
* store2.getMergeableTableDiff(store1.getMergeableTableHashes())[1],
* ),
* )[1],
* ),
* );
* // -> {pets: {fido: {color: 923684530, species: 227729753}}}
* ```
* @category Syncing
* @since v5.0.0
*/
getMergeableCellHashes(otherTableRowHashes: RowHashes): CellHashes;
/**
* The getMergeableCellDiff method returns information about new and differing
* Cell objects of a MergeableStore relative to another.
*
* The method is generally intended to be used internally within TinyBase
* itself and the return type is assumed to be opaque to applications that use
* it.
* @param otherTableRowCellHashes The CellHashes of another MergeableStore.
* @returns The new and differing Cell objects of this MergeableStore relative
* to the other.
* @example
* This example creates two MergeableStores, sets some differing data, and
* then identifies the differences in the Cell objects of one versus the
* other. Once they have been merged, the differences are empty.
*
* ```js
* import {createMergeableStore} from 'tinybase';
*
* const store1 = createMergeableStore('store1'); // !resetHlc
* store1.setTables({pets: {fido: {color: 'brown'}}});
*
* const store2 = createMergeableStore('store2');
* store2.setTables({pets: {fido: {color: 'black', species: 'dog'}}});
*
* console.log(
* store2.getMergeableCellDiff(
* store1.getMergeableCellHashes(
* store2.getMergeableRowDiff(
* store1.getMergeableRowHashes(
* store2.getMergeableTableDiff(
* store1.getMergeableTableHashes(),
* )[1],
* ),
* )[1],
* ),
* ),
* );
* // ->
* [
* {
* pets: [
* {
* fido: [
* {
* color: ['black', 'Nn1JUF-----CnH-J'],
* species: ['dog', 'Nn1JUF----0CnH-J'],
* },
* ],
* },
* ],
* },
* ];
*
* store1.merge(store2);
*
* console.log(
* store2.getMergeableCellDiff(
* store1.getMergeableCellHashes(
* store2.getMergeableRowDiff(
* store1.getMergeableRowHashes(
* store2.getMergeableTableDiff(
* store1.getMergeableTableHashes(),
* )[1],
* ),
* )[1],
* ),
* ),
* );
* // -> [{}]
* ```
* @category Syncing
* @since v5.0.0
*/
getMergeableCellDiff(otherTableRowCellHashes: CellHashes): TablesStamp;
/**
* The getMergeableValueHashes method returns hashes for the Value objects in
* a MergeableStore.
*
* If two Value Ids have different hashes, that indicates that the content
* within them is different and should be synchronized.
*
* The method is generally intended to be used internally within TinyBase
* itself and the return type is assumed to be opaque to applications that use
* it.
* @returns A ValueHashes object with the hashes of each Value in the
* MergeableStore.
* @example
* This example creates a MergeableStore, sets some data, and then accesses
* the Value hashes.
*
* ```js
* import {createMergeableStore} from 'tinybase';
*
* const store = createMergeableStore('store1'); // !resetHlc
*
* store.setValue('employees', 3);
* console.log(store.getMergeableValueHashes());
* // -> {employees: 1940815977}
*
* store.setValue('open', true);
* console.log(store.getMergeableValueHashes());
* // -> {employees: 1940815977, open: 3860530645}
* ```
* @category Syncing
* @since v5.0.0
*/
getMergeableValueHashes(): ValueHashes;
/**
* The getMergeableValueDiff method returns information about new and
* differing Value objects of a MergeableStore relative to another.
*
* The method is generally intended to be used internally within TinyBase
* itself and the return type is assumed to be opaque to applications that use
* it.
* @param otherValueHashes The ValueHashes of another MergeableStore.
* @returns The new and differing Value objects of this MergeableStore
* relative to the other.
* @example
* This example creates two MergeableStores, sets some differing data, and
* then identifies the differences in the Value objects of one versus the
* other. Once they have been merged, the differences are empty.
*
* ```js
* import {createMergeableStore} from 'tinybase';
*
* const store1 = createMergeableStore('store1'); // !resetHlc
* store1.setValues({employees: 3});
*
* const store2 = createMergeableStore('store2');
* store2.setValues({employees: 4, open: true});
*
* console.log(
* store2.getMergeableValueDiff(store1.getMergeableValueHashes()),
* );
* // ->
* [
* {
* employees: [4, 'Nn1JUF-----CnH-J'],
* open: [true, 'Nn1JUF----0CnH-J'],
* },
* ];
*
* store1.merge(store2);
*
* console.log(
* store2.getMergeableValueDiff(store1.getMergeableValueHashes()),
* );
* // -> [{}]
* ```
* @category Syncing
* @since v5.0.0
*/
getMergeableValueDiff(otherValueHashes: ValueHashes): ValuesStamp;
/**
* The setMergeableContent method sets the full content of a MergeableStore,
* together with the metadata required to make it mergeable with another.
*
* The method is generally intended to be used internally within TinyBase
* itself and the return type is assumed to be opaque to applications that use
* it.
* @param mergeableContent The full content and metadata of a MergeableStore.
* @returns A reference to the MergeableStore.
* @example
* This example creates a new MergeableStore and initializes it with
* the content and metadata from another.
*
* ```js
* import {createMergeableStore} from 'tinybase';
*
* const store1 = createMergeableStore('store1'); // !resetHlc
* store1.setValues({employees: 3});
* console.log(store1.getMergeableContent());
* // ->
* [
* [{}, '', 0],
* [{employees: [3, 'Nn1JUF-----FnHIC', 1940815977]}, '', 1260895905],
* ];
*
* const store2 = createMergeableStore('store2');
* store2.setMergeableContent(store1.getMergeableContent());
* console.log(store2.getMergeableContent());
* // ->
* [
* [{}, '', 0],
* [{employees: [3, 'Nn1JUF-----FnHIC', 1940815977]}, '', 1260895905],
* ];
* ```
* @category Setter
* @since v5.0.0
*/
setMergeableContent(mergeableContent: MergeableContent): MergeableStore;
/**
* The setDefaultContent method sets initial content of a MergeableStore.
*
* This differs from the setMergeableContent method in that all of the
* metadata is initialized with a empty HLC timestamp - meaning that any
* changes applied to it will 'win', yet ensuring that at least default,
* initial data exists.
*
* The method is generally intended to be used internally within TinyBase
* itself and the return type is assumed to be opaque to applications that use
* it.
*
* Since v5.4.2, this method can also take a function that returns the
* content.
* @param content An array containing the tabular and keyed-value data to be
* set, or a function that returns the array.
* @returns A reference to the MergeableStore.
* @example
* This example creates a new MergeableStore with default data, and
* demonstrates that it is overwritten with another MergeableStore's data on
* merge, even if the other MergeableStore was provisioned earlier.
*
* ```js
* import {createMergeableStore} from 'tinybase';
*
* const store1 = createMergeableStore('store1'); // !resetHlc
* store1.setValues({employees: 3});
*
* const store2 = createMergeableStore('store2');
* store2.setDefaultContent([{}, {employees: 4}]);
* console.log(store2.getMergeableContent());
* // -> [[{}, "", 0], [{"employees": [4, "", 2414055963]}, "", 3035768673]]
*
* store2.merge(store1);
* console.log(store2.getContent());
* // -> [{}, {employees: 3}]
* ```
* @category Setter
* @since v5.0.0
*/
setDefaultContent(content: Content | (() => Content)): MergeableStore;
/**
* The getTransactionMergeableChanges method returns the net meaningful
* changes that have been made to a MergeableStore during a transaction.
*
* The method is generally intended to be used internally within TinyBase
* itself and the return type is assumed to be opaque to applications that use
* it.
* @param withHashes Whether to include hashes in the output, defaulting to
* false.
* @returns A MergeableChanges object representing the changes, with hashes.
* @example
* This example makes changes to the MergeableStore. At the end of the
* transaction, detail about what changed is enumerated.
*
* ```js
* import {createMergeableStore} from 'tinybase';
*
* const store = createMergeableStore('store1'); // !resetHlc
* store.setTables({pets: {fido: {species: 'dog', color: 'brown'}}});
* store.setValues({open: true});
*
* store
* .startTransaction()
* .setCell('pets', 'fido', 'color', 'black')
* .setValue('open', false)
* .finishTransaction(() => {
* console.log(store.getTransactionMergeableChanges());
* });
* // ->
* [
* [{pets: [{fido: [{color: ['black', 'Nn1JUF----2FnHIC']}]}]}],
* [{open: [false, 'Nn1JUF----3FnHIC']}],
* 1,
* ];
* ```
* @category Transaction
* @since v5.0.0
*/
getTransactionMergeableChanges(withHashes?: boolean): MergeableChanges<true>;
/**
* The applyMergeableChanges method applies a set of mergeable changes or
* content to the MergeableStore.
*
* The method is generally intended to be used internally within TinyBase
* itself and the return type is assumed to be opaque to applications that use
* it.
* @param mergeableChanges The MergeableChanges or MergeableContent to apply
* to the MergeableStore.
* @returns A reference to the MergeableStore.
* @example
* This example applies a MergeableChanges object that sets a Cell and removes
* a Value.
*
* ```js
* import {createMergeableStore} from 'tinybase';
*
* const store = createMergeableStore('store1')
* .setTables({pets: {fido: {species: 'dog', color: 'brown'}}})
* .setValues({open: true});
*
* store.applyMergeableChanges([
* [{pets: [{fido: [{color: ['black', 'Nn1JUF----2FnHIC']}]}]}],
* [{open: [null, 'Nn1JUF----3FnHIC']}],
* 1,
* ]);
* console.log(store.getTables());
* // -> {pets: {fido: {species: 'dog', color: 'black'}}}
* console.log(store.getValues());
* // -> {}
* ```
* @category Setter
* @since v5.0.0
*/
applyMergeableChanges(
mergeableChanges: MergeableChanges | MergeableContent,
): MergeableStore;
/**
* The merge method is a convenience method that applies the mergeable content
* from two MergeableStores to each other in order to bring them to the same
* state.
*
* This method is symmetrical: applying `store1` to `store2` will have exactly
* the same effect as applying `store2` to `store1`.
* @param mergeableStore A reference to the other MergeableStore to merge with
* this one.
* @returns A reference to this MergeableStore.
* @example
* This example merges two MergeableStore objects together. Note how the final
* part of the timestamps on each Cell give you a clue that the data comes
* from changes made to different MergeableStore objects.
*
* ```js
* import {createMergeableStore} from 'tinybase';
*
* const store1 = createMergeableStore('store1');
* store1.setTables({pets: {fido: {species: 'dog', color: 'brown'}}});
*
* const store2 = createMergeableStore('store2');
* store2.setTables({pets: {felix: {species: 'cat', color: 'tan'}}});
*
* store1.merge(store2);
*
* console.log(store1.getContent());
* // ->
* [
* {
* pets: {
* felix: {color: 'tan', species: 'cat'},
* fido: {color: 'brown', species: 'dog'},
* },
* },
* {},
* ];
*
* console.log(store2.getContent());
* // ->
* [
* {
* pets: {
* felix: {color: 'tan', species: 'cat'},
* fido: {color: 'brown', species: 'dog'},
* },
* },
* {},
* ];
* console.log(store2.getMergeableContent());
* // ->
* [
* [
* {
* pets: [
* {
* felix: [
* {
* color: ['tan', 'Nn1JUF----0CnH-J', 2576658292],
* species: ['cat', 'Nn1JUF-----CnH-J', 3409607562],
* },
* '',
* 4146239216,
* ],
* fido: [
* {
* color: ['brown', 'Nn1JUF----0FnHIC', 1240535355],
* species: ['dog', 'Nn1JUF-----FnHIC', 290599168],
* },
* '',
* 3989065420,
* ],
* },
* '',
* 4155188296,
* ],
* },
* '',
* 972931118,
* ],
* [{}, '', 0],
* ];
* ```
* @category Setter
* @since v5.0.0
*/
merge(mergeableStore: MergeableStore): MergeableStore;
/**
* The isMergeable method lets you know if the Store is mergeable.
*
* This will always return false for a Store, and true for a MergeableStore.
* @returns Whether the Store is mergeable.
* @category Getter
* @since v5.0.0
*/
isMergeable(): boolean;
}
/**
* The createMergeableStore function creates a MergeableStore, and is the main
* entry point into the mergeable-store module.
*
* There is one optional parameter which is a uniqueId for the MergeableStore.
* This is used to distinguish conflicting changes made in the same millisecond
* by two different MergeableStore objects as its hash is added to the end of
* the HLC timestamps. Generally this can be omitted unless you have a need for
* deterministic HLCs, such as in a testing scenario. Otherwise, TinyBase will
* assign a unique Id to the Store at the time of creation.
* @returns A reference to the new MergeableStore.
* @example
* This example creates a MergeableStore.
*
* ```js
* import {createMergeableStore} from 'tinybase';
*
* const store = createMergeableStore('store1');
*
* console.log(store.getContent());
* // -> [{}, {}]
* console.log(store.getMergeableContent());
* // -> [[{}, '', 0], [{}, '', 0]]
* ```
* @example
* This example creates a MergeableStore with some initial data:
*
* ```js
* import {createMergeableStore} from 'tinybase';
*
* const store = createMergeableStore('store1').setTables({
* pets: {fido: {species: 'dog'}},
* });
*
* console.log(store.getContent());
* // -> [{pets: {fido: {species: 'dog'}}}, {}]
* console.log(store.getMergeableContent());
* // ->
* [
* [
* {
* pets: [
* {
* fido: [
* {species: ['dog', 'Nn1JUF-----FnHIC', 290599168]},
* '',
* 2682656941,
* ],
* },
* '',
* 2102515304,
* ],
* },
* '',
* 3506229770,
* ],
* [{}, '', 0],
* ];
* ```
* @example
* This example creates a MergeableStore with some initial data and a
* TablesSchema:
*
* ```js
* import {createMergeableStore} from 'tinybase';
*
* const store = createMergeableStore('store1')
* .setTables({pets: {fido: {species: 'dog'}}})
* .setTablesSchema({
* pets: {
* species: {type: 'string'},
* sold: {type: 'boolean', default: false},
* },
* });
*
* console.log(store.getContent());
* // -> [{pets: {fido: {sold: false, species: 'dog'}}}, {}]
* console.log(store.getMergeableContent());
* // ->
* [
* [
* {
* pets: [
* {
* fido: [
* {
* sold: [false, 'Nn1JUF----2FnHIC', 2603026204],
* species: ['dog', 'Nn1JUF----1FnHIC', 2817056260],
* },
* '',
* 2859424112,
* ],
* },
* '',
* 1640515891,
* ],
* },
* '',
* 2077041985,
* ],
* [{}, '', 0],
* ];
* ```
* @category Creation
* @since v5.0.0
*/
export function createMergeableStore(uniqueId?: Id): MergeableStore;