UNPKG

tinybase

Version:

A reactive data store and sync engine.

1,576 lines (1,537 loc) 51.2 kB
/** * 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 { CellIdFromSchema, TableIdFromSchema, ValueIdFromSchema, } from '../../_internal/store/with-schemas/index.d.cts'; import type {Id} from '../../common/with-schemas/index.d.cts'; import type { CellOrUndefined, Content, NoSchemas, NoTablesSchema, NoValuesSchema, OptionalSchemas, OptionalTablesSchema, OptionalValuesSchema, Store, TablesSchema, ValueOrUndefined, ValuesSchema, } from '../../store/with-schemas/index.d.cts'; /** * 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 has schema-based typing. The following is a simplified representation: * * ```ts override * export type TablesStamp<Hashed extends boolean = false> = Stamp< * {[tableId: Id]: TableStamp<Hashed>}, * Hashed * >; * ``` * * 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< Schema extends OptionalTablesSchema, Hashed extends boolean = false, > = Stamp< { [TableId in TableIdFromSchema<Schema>]?: TableStamp< Schema, TableId, Hashed >; }, Hashed >; /** * The TableHashes type is used to quickly compare the content of two sets of * Table objects. * * This has schema-based typing. The following is a simplified representation: * * ```ts override * {[tableId: Id]: Hash}; * ``` * * 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<Schema extends OptionalTablesSchema> = { [TableId in TableIdFromSchema<Schema>]?: Hash; }; /** * The TableStamp type is used as metadata to decide how to merge two different * Table objects together. * * This has schema-based typing. The following is a simplified representation: * * ```ts override * export type TableStamp<Hashed extends boolean = false> = Stamp< * {[rowId: Id]: RowStamp<Hashed>}, * Hashed * >; * ``` * * 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< Schema extends OptionalTablesSchema, TableId extends TableIdFromSchema<Schema>, Hashed extends boolean = false, > = Stamp<{[rowId: Id]: RowStamp<Schema, TableId, Hashed>}, Hashed>; /** * The RowHashes type is used to quickly compare the content of two sets of Row * objects. * * This has schema-based typing. The following is a simplified representation: * * ```ts override * {[tableId: Id]: {[rowId: Id]: Hash}}; * ``` * * 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<Schema extends OptionalTablesSchema> = { [TableId in TableIdFromSchema<Schema>]?: {[rowId: Id]: Hash}; }; /** * The RowStamp type is used as metadata to decide how to merge two different * Row objects together. * * This has schema-based typing. The following is a simplified representation: * * ```ts override * export type RowStamp<Hashed extends boolean = false> = Stamp< * {[cellId: Id]: CellStamp<Hashed>}, * Hashed * >; * ``` * * 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< Schema extends OptionalTablesSchema, TableId extends TableIdFromSchema<Schema>, Hashed extends boolean = false, > = Stamp< { [CellId in CellIdFromSchema<Schema, TableId>]?: CellStamp< Schema, TableId, CellId, Hashed >; }, Hashed >; /** * The CellHashes type is used to quickly compare the content of two sets of * Cell objects. * * This has schema-based typing. The following is a simplified representation: * * ```ts override * {[tableId: Id]: {[rowId: Id]: {[cellId: Id]: Hash}}}; * ``` * * 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<Schema extends OptionalTablesSchema> = { [TableId in TableIdFromSchema<Schema>]?: { [rowId: Id]: {[CellId in CellIdFromSchema<Schema, TableId>]?: Hash}; }; }; /** * The CellStamp type is used as metadata to decide how to merge two different * Cell objects together. * * This has schema-based typing. The following is a simplified representation: * * ```ts override * export type CellStamp<Hashed extends boolean = false> = Stamp< * CellOrUndefined, * Hashed * >; * ``` * * 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< Schema extends OptionalTablesSchema, TableId extends TableIdFromSchema<Schema>, CellId extends CellIdFromSchema<Schema, TableId>, Hashed extends boolean = false, > = Stamp<CellOrUndefined<Schema, TableId, CellId>, Hashed>; /** * The ValuesStamp type is used as metadata to decide how to merge two different * sets of Values together. * * This has schema-based typing. The following is a simplified representation: * * ```ts override * export type ValuesStamp<Hashed extends boolean = false> = Stamp< * {[valueId: Id]: ValueStamp<Hashed>}, * Hashed * >; * ``` * * 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< Schema extends OptionalValuesSchema, Hashed extends boolean = false, > = Stamp< { [ValueId in ValueIdFromSchema<Schema>]?: ValueStamp< Schema, ValueId, Hashed >; }, Hashed >; /** * The ValueHashes type is used to quickly compare the content of two sets of * Value objects. * * This has schema-based typing. The following is a simplified representation: * * ```ts override * {[valueId: Id]: Hash}; * ``` * * 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<Schema extends OptionalValuesSchema> = { [ValueId in ValueIdFromSchema<Schema>]?: Hash; }; /** * The ValueStamp type is used as metadata to decide how to merge two different * Value objects together. * * This has schema-based typing. The following is a simplified representation: * * ```ts override * export type ValueStamp<Hashed extends boolean = false> = Stamp< * ValueOrUndefined, * Hashed * >; * ``` * * 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< Schema extends OptionalValuesSchema, ValueId extends ValueIdFromSchema<Schema>, Hashed extends boolean = false, > = Stamp<ValueOrUndefined<Schema, ValueId>, Hashed>; /** * The MergeableContent type represents the content of a MergeableStore and the * metadata about that content) required to merge it with another. * * This has schema-based typing. The following is a simplified representation: * * ```ts override * [ * mergeableTables: TablesStamp<true>, * mergeableValues: ValuesStamp<true>, * ]; * ``` * * 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<Schemas extends OptionalSchemas> = [ mergeableTables: TablesStamp<Schemas[0], true>, mergeableValues: ValuesStamp<Schemas[1], true>, ]; /** * The MergeableChanges type represents changes to the content of a * MergeableStore and the metadata about that content) required to merge it with * another. * * This has schema-based typing. The following is a simplified representation: * * ```ts override * export type MergeableChanges<Hashed extends boolean = false> = [ * mergeableTables: TablesStamp<Hashed>, * mergeableValues: ValuesStamp<Hashed>, * isChanges: 1, * ]; * ``` * * 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< Schemas extends OptionalSchemas, Hashed extends boolean = false, > = [ mergeableTables: TablesStamp<Schemas[0], Hashed>, mergeableValues: ValuesStamp<Schemas[1], 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<Schemas extends OptionalSchemas> extends Store<Schemas> { // /** * The getMergeableContent method returns the full content of a * MergeableStore, together with the metadata required to make it mergeable * with another. * * This has schema-based typing. The following is a simplified representation: * * ```ts override * getMergeableContent(): MergeableContent; * ``` * * 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<Schemas>; /** * 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. * * This has schema-based typing. The following is a simplified representation: * * ```ts override * getMergeableTableHashes(): TableHashes; * ``` * * 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<Schemas[0]>; /** * The getMergeableTableDiff method returns information about new and * differing Table objects of a MergeableStore relative to another. * * This has schema-based typing. The following is a simplified representation: * * ```ts override * getMergeableTableDiff( * otherTableHashes: TableHashes, * ): [newTables: TablesStamp, differingTableHashes: TableHashes]; * ``` * * 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<Schemas[0]>, ): [ newTables: TablesStamp<Schemas[0]>, differingTableHashes: TableHashes<Schemas[0]>, ]; /** * The getMergeableRowHashes method returns hashes for Row objects in a * MergeableStore. * * This has schema-based typing. The following is a simplified representation: * * ```ts override * getMergeableRowHashes(otherTableHashes: TableHashes): RowHashes; * ``` * * 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<Schemas[0]>, ): RowHashes<Schemas[0]>; /** * The getMergeableRowDiff method returns information about new and differing * Row objects of a MergeableStore relative to another. * * This has schema-based typing. The following is a simplified representation: * * ```ts override * getMergeableRowDiff( * otherTableRowHashes: RowHashes, * ): [newRows: TablesStamp, differingRowHashes: RowHashes]; * ``` * * 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<Schemas[0]>, ): [ newRows: TablesStamp<Schemas[0]>, differingRowHashes: RowHashes<Schemas[0]>, ]; /** * The getMergeableCellHashes method returns hashes for Cell objects in a * MergeableStore. * * This has schema-based typing. The following is a simplified representation: * * ```ts override * getMergeableCellHashes(otherTableRowHashes: RowHashes): CellHashes; * ``` * * 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<Schemas[0]>, ): CellHashes<Schemas[0]>; /** * The getMergeableCellDiff method returns information about new and differing * Cell objects of a MergeableStore relative to another. * * This has schema-based typing. The following is a simplified representation: * * ```ts override * getMergeableCellDiff(otherTableRowCellHashes: CellHashes): TablesStamp; * ``` * * 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<Schemas[0]>, ): TablesStamp<Schemas[0]>; /** * The getMergeableValueHashes method returns hashes for the Value objects in * a MergeableStore. * * This has schema-based typing. The following is a simplified representation: * * ```ts override * getMergeableValueHashes(): ValueHashes; * ``` * * 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<Schemas[1]>; /** * The getMergeableValueDiff method returns information about new and * differing Value objects of a MergeableStore relative to another. * * This has schema-based typing. The following is a simplified representation: * * ```ts override * getMergeableValueDiff(otherValueHashes: ValueHashes): ValuesStamp; * ``` * * 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<Schemas[1]>, ): ValuesStamp<Schemas[1]>; /** * The setMergeableContent method sets the full content of a MergeableStore, * together with the metadata required to make it mergeable with another. * * This has schema-based typing. The following is a simplified representation: * * ```ts override * setMergeableContent(mergeableContent: MergeableContent): 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 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<Schemas>, ): MergeableStore<Schemas>; /** * The setDefaultContent method sets initial content of a MergeableStore. * * This has schema-based typing. The following is a simplified representation: * * ```ts override * setDefaultContent(content: Content | (() => Content)): 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<Schemas> | (() => Content<Schemas>), ): MergeableStore<Schemas>; /** * The getTransactionMergeableChanges method returns the net meaningful * changes that have been made to a MergeableStore during a transaction. * * This has schema-based typing. The following is a simplified representation: * * ```ts override * getTransactionMergeableChanges(withHashes?: boolean): MergeableChanges<true>; * ``` * * 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<Schemas, true>; /** * The applyMergeableChanges method applies a set of mergeable changes or * content to the MergeableStore. * * This has schema-based typing. The following is a simplified representation: * * ```ts override * applyMergeableChanges( * mergeableChanges: MergeableChanges | MergeableContent, * ): 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<Schemas> | MergeableContent<Schemas>, ): MergeableStore<Schemas>; /** * 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 has schema-based typing. The following is a simplified representation: * * ```ts override * merge(mergeableStore: MergeableStore): MergeableStore; * ``` * * 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<Schemas>): MergeableStore<Schemas>; /** * 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 setTablesSchema method lets you specify the TablesSchema of the tabular * part of the Store. * * Note that this may result in a change to data in the Store, as defaults are * applied or as invalid Table, Row, or Cell objects are removed. These * changes will fire any listeners to that data, as expected. * * When no longer needed, you can also completely remove an existing * TablesSchema with the delTablesSchema method. * @param tablesSchema The TablesSchema to be set for the Store. * @returns A reference to the Store. * @example * This example sets the TablesSchema of a Store after it has been created. * * ```js * import {createStore} from 'tinybase'; * * const store = createStore().setTablesSchema({ * pets: { * species: {type: 'string'}, * sold: {type: 'boolean', default: false}, * }, * }); * store.addRow('pets', {species: 'dog', color: 'brown', sold: 'maybe'}); * * console.log(store.getTables()); * // -> {pets: {0: {species: 'dog', sold: false}}} * ``` * @category Setter * @since v3.0.0 */ setTablesSchema<TS extends TablesSchema>( tablesSchema: TS, ): MergeableStore<[typeof tablesSchema, Schemas[1]]>; /** * The setValuesSchema method lets you specify the ValuesSchema of the keyed * Values part of the Store. * * Note that this may result in a change to data in the Store, as defaults are * applied or as invalid Values are removed. These changes will fire any * listeners to that data, as expected. * * When no longer needed, you can also completely remove an existing * ValuesSchema with the delValuesSchema method. * @param valuesSchema The ValuesSchema to be set for the Store. * @returns A reference to the Store. * @example * This example sets the ValuesSchema of a Store after it has been created. * * ```js * import {createStore} from 'tinybase'; * * const store = createStore().setValuesSchema({ * open: {type: 'boolean', default: false}, * }); * store.setValue('open', 'maybe'); * * console.log(store.getValues()); * // -> {open: false} * ``` * @category Setter * @since v3.0.0 */ setValuesSchema<VS extends ValuesSchema>( valuesSchema: VS, ): MergeableStore<[Schemas[0], typeof valuesSchema]>; /** * The setSchema method lets you specify the TablesSchema and ValuesSchema of * the Store. * * Note that this may result in a change to data in the Store, as defaults are * applied or as invalid Table, Row, Cell, or Value objects are removed. These * changes will fire any listeners to that data, as expected. * * From v3.0 onwards, this method takes two arguments. The first is the * TablesSchema object, the second the ValuesSchema. In previous versions * (before the existence of the ValuesSchema data structure), only the first * was present. For backwards compatibility the new second parameter is * optional. * @param tablesSchema The TablesSchema to be set for the Store. * @param valuesSchema The ValuesSchema to be set for the Store. * @returns A reference to the Store. * @example * This example sets the TablesSchema and ValuesSchema of a Store after it has * been created. * * ```js * import {createStore} from 'tinybase'; * * const store = createStore().setSchema( * { * pets: { * species: {type: 'string'}, * sold: {type: 'boolean', default: false}, * }, * }, * {open: {type: 'boolean', default: false}}, * ); * store.addRow('pets', {species: 'dog', color: 'brown', sold: 'maybe'}); * store.setValue('open', 'maybe'); * * console.log(store.getTables()); * // -> {pets: {0: {species: 'dog', sold: false}}} * console.log(store.getValues()); * // -> {open: false} * ``` * @example * This example sets just the TablesSchema of a Store after it has been * created. * * ```js * import {createStore} from 'tinybase'; * * const store = createStore().setSchema({ * pets: { * species: {type: 'string'}, * sold: {type: 'boolean', default: false}, * }, * }); * store.addRow('pets', {species: 'dog', color: 'brown', sold: 'maybe'}); * * console.log(store.getTables()); * // -> {pets: {0: {species: 'dog', sold: false}}} * ``` * @category Setter * @since v1.0.0 */ setSchema<TS extends TablesSchema, VS extends ValuesSchema>( tablesSchema: TS, valuesSchema?: VS, ): MergeableStore< [ typeof tablesSchema, Exclude<ValuesSchema, typeof valuesSchema> extends never ? NoValuesSchema : NonNullable<typeof valuesSchema>, ] >; /** * The delTablesSchema method lets you remove the TablesSchema of the Store. * @returns A reference to the Store. * @example * This example removes the TablesSchema of a Store. * * ```js * import {createStore} from 'tinybase'; * * const store = createStore().setTablesSchema({ * pets: {species: {type: 'string'}}, * }); * store.delTablesSchema(); * console.log(store.getTablesSchemaJson()); * // -> '{}' * ``` * @category Deleter * @since v1.0.0 */ delTablesSchema< ValuesSchema extends OptionalValuesSchema = Schemas[1], >(): MergeableStore<[NoTablesSchema, ValuesSchema]>; /** * The delValuesSchema method lets you remove the ValuesSchema of the Store. * @returns A reference to the Store. * @example * This example removes the ValuesSchema of a Store. * * ```js * import {createStore} from 'tinybase'; * * const store = createStore().setValuesSchema({ * sold: {type: 'boolean', default: false}, * }); * store.delValuesSchema(); * console.log(store.getValuesSchemaJson()); * // -> '{}' * ``` * @category Deleter * @since v3.0.0 */ delValuesSchema< TablesSchema extends OptionalTablesSchema = Schemas[0], >(): MergeableStore<[TablesSchema, NoValuesSchema]>; /** * The delSchema method lets you remove both the TablesSchema and ValuesSchema * of the Store. * * Prior to v3.0, this method removed the TablesSchema only. * @returns A reference to the Store. * @example * This example removes the TablesSchema and ValuesSchema of a Store. * * ```js * import {createStore} from 'tinybase'; * * const store = createStore() * .setTablesSchema({ * pets: {species: {type: 'string'}}, * }) * .setValuesSchema({ * sold: {type: 'boolean', default: false}, * }); * store.delSchema(); * console.log(store.getSchemaJson()); * // -> '[{},{}]' * ``` * @category Deleter * @since v3.0.0 */ delSchema(): MergeableStore<NoSchemas>; } /** * The createMergeableStore function creates a MergeableStore, and is the main * entry point into the mergeable-store module. * * This has schema-based typing. The following is a simplified representation: * * ```ts override * createMergeableStore(uniqueId?: Id): MergeableStore; * ``` * * 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, * ], * }, * '', * 35062