tinybase
Version:
A reactive data store and sync engine.
918 lines (894 loc) • 32.5 kB
TypeScript
/**
* The metrics module of the TinyBase project provides the ability to create and
* track metrics and aggregates of the data in Store objects.
*
* The main entry point to this module is the createMetrics function, which
* returns a new Metrics object. From there, you can create new Metric
* definitions, access the values of those Metrics directly, and register
* listeners for when they change.
* @packageDocumentation
* @module metrics
* @since v1.0.0
*/
import type {Id, IdOrNull, Ids} from '../common/index.d.ts';
import type {GetCell, Store} from '../store/index.d.ts';
/**
* The Metric type is simply an alias, but represents a number formed by
* aggregating multiple other numbers together.
* @category Metric
* @since v1.0.0
*/
export type Metric = number;
/**
* The MetricCallback type describes a function that takes a Metric's Id and a
* callback to loop over each Row within it.
*
* A MetricCallback is provided when using the forEachMetric method, so that you
* can do something based on every Metric in the Metrics object. See that method
* for specific examples.
* @param metricId The Id of the Metric that the callback can operate on.
* @param metric The value of the Metric.
* @category Callback
* @since v1.0.0
*/
export type MetricCallback = (metricId: Id, metric?: Metric) => void;
/**
* The MetricAggregate type describes a custom function that takes an array of
* numbers and returns an aggregate that is used as a Metric.
*
* There are a number of common predefined aggregators, such as for counting,
* summing, and averaging values. This type is instead used for when you wish to
* use a more complex aggregation of your own devising. See the
* setMetricDefinition method for more examples.
* @param numbers The array of numbers in the Metric's aggregation.
* @param length The length of the array of numbers in the Metric's aggregation.
* @returns The value of the Metric.
* @category Aggregators
* @since v1.0.0
*/
export type MetricAggregate = (numbers: number[], length: number) => Metric;
/**
* The MetricAggregateAdd type describes a function that can be used to optimize
* a custom MetricAggregate by providing a shortcut for when a single value is
* added to the input values.
*
* Some aggregation functions do not need to recalculate the aggregation of the
* whole set when one value changes. For example, when adding a new number to a
* series, the new sum of the series is the new value added to the previous sum.
*
* If it is not possible to shortcut the aggregation based on just one value
* being added, return `undefined` and the Metric will be completely
* recalculated.
*
* When possible, if you are providing a custom MetricAggregate, seek an
* implementation of an MetricAggregateAdd function that can reduce the
* complexity cost of growing the input data set. See the setMetricDefinition
* method for more examples.
* @param metric The current value of the Metric.
* @param add The number being added to the Metric's aggregation.
* @param length The length of the array of numbers in the Metric's aggregation.
* @returns The new value of the Metric.
* @category Aggregators
* @since v1.0.0
*/
export type MetricAggregateAdd = (
metric: Metric,
add: number,
length: number,
) => Metric | undefined;
/**
* The MetricAggregateRemove type describes a function that can be used to
* optimize a custom MetricAggregate by providing a shortcut for when a single
* value is removed from the input values.
*
* Some aggregation functions do not need to recalculate the aggregation of the
* whole set when one value changes. For example, when removing a number from a
* series, the new sum of the series is the new value subtracted from the
* previous sum.
*
* If it is not possible to shortcut the aggregation based on just one value
* being removed, return `undefined` and the Metric will be completely
* recalculated. One example might be if you were taking the minimum of the
* values, and the previous minimum is being removed. The whole of the rest of
* the list will need to be re-scanned to find a new minimum.
*
* When possible, if you are providing a custom MetricAggregate, seek an
* implementation of an MetricAggregateRemove function that can reduce the
* complexity cost of shrinking the input data set. See the setMetricDefinition
* method for more examples.
* @param metric The current value of the Metric.
* @param remove The number being removed from the Metric's aggregation.
* @param length The length of the array of numbers in the Metric's aggregation.
* @returns The new value of the Metric.
* @category Aggregators
* @since v1.0.0
*/
export type MetricAggregateRemove = (
metric: Metric,
remove: number,
length: number,
) => Metric | undefined;
/**
* The MetricAggregateReplace type describes a function that can be used to
* optimize a custom MetricAggregate by providing a shortcut for when a single
* value in the input values is replaced with another.
*
* Some aggregation functions do not need to recalculate the aggregation of the
* whole set when one value changes. For example, when replacing a number in a
* series, the new sum of the series is the previous sum, plus the new value,
* minus the old value.
*
* If it is not possible to shortcut the aggregation based on just one value
* changing, return `undefined` and the Metric will be completely recalculated.
*
* When possible, if you are providing a custom MetricAggregate, seek an
* implementation of an MetricAggregateReplace function that can reduce the
* complexity cost of changing the input data set in place. See the
* setMetricDefinition method for more examples.
* @param metric The current value of the Metric.
* @param add The number being added to the Metric's aggregation.
* @param remove The number being removed from the Metric's aggregation.
* @param length The length of the array of numbers in the Metric's aggregation.
* @returns The new value of the Metric.
* @category Aggregators
* @since v1.0.0
*/
export type MetricAggregateReplace = (
metric: Metric,
add: number,
remove: number,
length: number,
) => Metric | undefined;
/**
* The MetricIdsListener type describes a function that is used to listen to
* Metric definitions being added or removed.
*
* A MetricIdsListener is provided when using the addMetricIdsListener method.
* See that method for specific examples.
*
* When called, a MetricIdsListener is given a reference to the Metrics object.
* @param metrics A reference to the Metrics object that changed.
* @category Listener
* @since v1.0.0
*/
export type MetricIdsListener = (metrics: Metrics) => void;
/**
* The MetricListener type describes a function that is used to listen to
* changes to a Metric.
*
* A MetricListener is provided when using the addMetricListener method. See
* that method for specific examples.
*
* When called, a MetricListener is given a reference to the Metrics object, the
* Id of the Metric that changed, and the new and old values of the Metric.
*
* If this is the first time that a Metric has had a value (such as when a table
* has gained its first row), the old value will be `undefined`. If a Metric now
* no longer has a value, the new value will be `undefined`.
* @param metrics A reference to the Metrics object that changed.
* @param metricId The Id of the Metric that changed.
* @param newMetric The new value of the Metric that changed.
* @param oldMetric The old value of the Metric that changed.
* @category Listener
* @since v1.0.0
*/
export type MetricListener = (
metrics: Metrics,
metricId: Id,
newMetric: Metric | undefined,
oldMetric: Metric | undefined,
) => void;
/**
* The MetricsListenerStats type describes the number of listeners registered
* with the Metrics object, and can be used for debugging purposes.
*
* A MetricsListenerStats object is returned from the getListenerStats method.
* @category Development
* @since v1.0.0
*/
export type MetricsListenerStats = {
/**
* The number of MetricListener functions registered with the Metrics object.
* @category Stat
* @since v1.0.0
*/
metric: number;
};
/**
* A Metrics object lets you define, query, and listen to, aggregations of Cell
* values within a Table in a Store.
*
* This is useful for counting the number of Row objects in a Table, averaging
* Cell values, or efficiently performing any arbitrary aggregations.
*
* Create a Metrics object easily with the createMetrics function. From there,
* you can add new Metric definitions (with the setMetricDefinition method),
* query their values (with the getMetric method), and add listeners for when
* they change (with the addMetricListener method).
*
* This module provides a number of predefined and self-explanatory aggregations
* ('sum', 'avg', 'min', and 'max'), and defaults to counting Row objects when
* using the setMetricDefinition method. However, far more complex aggregations
* can be configured with custom functions.
* @example
* This example shows a very simple lifecycle of a Metrics object: from
* creation, to adding a definition, getting a Metric, and then registering and
* removing a listener for it.
*
* ```js
* import {createMetrics, createStore} from 'tinybase';
*
* const store = createStore().setTable('species', {
* dog: {price: 5},
* cat: {price: 4},
* worm: {price: 1},
* });
*
* const metrics = createMetrics(store);
* metrics.setMetricDefinition(
* 'highestPrice', // metricId
* 'species', // tableId to aggregate
* 'max', // aggregation
* 'price', // cellId to aggregate
* );
*
* console.log(metrics.getMetric('highestPrice'));
* // -> 5
*
* const listenerId = metrics.addMetricListener('highestPrice', () => {
* console.log(metrics.getMetric('highestPrice'));
* });
* store.setCell('species', 'horse', 'price', 20);
* // -> 20
*
* metrics.delListener(listenerId);
* metrics.destroy();
* ```
* @see Using Metrics guides
* @see Rolling Dice demos
* @see Country demo
* @see Todo App demos
* @category Metrics
* @since v1.0.0
*/
export interface Metrics {
//
/**
* The setMetricDefinition method lets you set the definition of a Metric.
*
* Every Metric definition is identified by a unique Id, and if you re-use an
* existing Id with this method, the previous definition is overwritten.
*
* A Metric is an aggregation of numeric values produced from each Row within
* a single Table. Therefore the definition must specify the Table (by its Id)
* to be aggregated.
*
* Without the third `aggregate` parameter, the Metric will simply be a count
* of the number of Row objects in the Table. But often you will specify a
* more interesting aggregate - such as the four predefined aggregates, 'sum',
* 'avg', 'min', and 'max' - or a custom function that produces your own
* aggregation of an array of numbers.
*
* The fourth `getNumber` parameter specifies which Cell in each Row contains
* the numerical values to be used in the aggregation. Alternatively, a custom
* function can be provided that produces your own numeric value from the
* local Row as a whole.
*
* The final three parameters, `aggregateAdd`, `aggregateRemove`,
* `aggregateReplace` need only be provided when you are using your own custom
* `aggregate` function. These give you the opportunity to reduce your custom
* function's algorithmic complexity by providing shortcuts that can nudge an
* aggregation result when a single value is added, removed, or replaced in
* the input values.
* @param metricId The Id of the Metric to define.
* @param tableId The Id of the Table the Metric will be calculated from.
* @param aggregate Either a string representing one of a set of common
* aggregation techniques ('sum', 'avg', 'min', or 'max'), or a function that
* aggregates numeric values from each Row to create the Metric's overall
* value. Defaults to 'sum'.
* @param getNumber Either the Id of a Cell containing, or a function that
* produces, the numeric value that will be aggregated in the way specified by
* the `aggregate` parameter. Defaults to a function that returns `1` (meaning
* that if the `aggregate` and `getNumber` parameters are both omitted, the
* Metric will simply be a count of the Row objects in the Table).
* @param aggregateAdd A function that can be used to optimize a custom
* MetricAggregate by providing a shortcut for when a single value is added to
* the input values - for example, when a Row is added to the Table.
* @param aggregateRemove A function that can be used to optimize a custom
* MetricAggregate by providing a shortcut for when a single value is removed
* from the input values - for example ,when a Row is removed from the Table.
* @param aggregateReplace A function that can be used to optimize a custom
* MetricAggregate by providing a shortcut for when a single value in the
* input values is replaced with another - for example, when a Row is updated.
* @returns A reference to the Metrics object.
* @example
* This example creates a Store, creates a Metrics object, and defines a
* simple Metric to count the Row objects in the Table.
*
* ```js
* import {createMetrics, createStore} from 'tinybase';
*
* const store = createStore().setTable('species', {
* dog: {price: 5},
* cat: {price: 4},
* worm: {price: 1},
* });
*
* const metrics = createMetrics(store);
* metrics.setMetricDefinition('speciesCount', 'species');
*
* console.log(metrics.getMetric('speciesCount'));
* // -> 3
* ```
* @example
* This example creates a Store, creates a Metrics object, and defines a
* standard Metric to get the highest value of each `price` Cell in the Row
* objects in the Table.
*
* ```js
* import {createMetrics, createStore} from 'tinybase';
*
* const store = createStore().setTable('species', {
* dog: {price: 5},
* cat: {price: 4},
* worm: {price: 1},
* });
*
* const metrics = createMetrics(store);
* metrics.setMetricDefinition('highestPrice', 'species', 'max', 'price');
*
* console.log(metrics.getMetric('highestPrice'));
* // -> 5
* ```
* @example
* This example creates a Store, creates a Metrics object, and defines a
* custom Metric to get the lowest value of each `price` Cell, greater than 2.
*
* ```js
* import {createMetrics, createStore} from 'tinybase';
*
* const store = createStore().setTable('species', {
* dog: {price: 5},
* cat: {price: 4},
* worm: {price: 1},
* });
*
* const metrics = createMetrics(store);
* metrics.setMetricDefinition(
* 'lowestPriceOver2',
* 'species',
* (numbers) => Math.min(...numbers.filter((number) => number > 2)),
* 'price',
* );
*
* console.log(metrics.getMetric('lowestPriceOver2'));
* // -> 4
* ```
* @example
* This example also creates a Store, creates a Metrics object, and defines a
* custom Metric to get the lowest value of each `price` Cell, greater than 2.
* However, it also reduces algorithmic complexity with two shortcut
* functions.
*
* ```js
* import {createMetrics, createStore} from 'tinybase';
*
* const store = createStore().setTable('species', {
* dog: {price: 5},
* cat: {price: 4},
* worm: {price: 1},
* });
*
* const metrics = createMetrics(store);
* metrics.setMetricDefinition(
* 'lowestPriceOver2',
* 'species',
* (numbers) => Math.min(...numbers.filter((number) => number > 2)),
* 'price',
* (metric, add) => (add > 2 ? Math.min(metric, add) : metric),
* (metric, remove) => (remove == metric ? undefined : metric),
* (metric, add, remove) =>
* remove == metric
* ? undefined
* : add > 2
* ? Math.min(metric, add)
* : metric,
* );
*
* console.log(metrics.getMetric('lowestPriceOver2'));
* // -> 4
* store.setRow('species', 'fish', {price: 3});
* console.log(metrics.getMetric('lowestPriceOver2'));
* // -> 3
* ```
* @example
* This example creates a Store, creates a Metrics object, and defines a
* custom Metric to get the average value of a discounted price.
*
* ```js
* import {createMetrics, createStore} from 'tinybase';
*
* const store = createStore().setTable('species', {
* dog: {price: 5, discount: 0.3},
* cat: {price: 4, discount: 0.2},
* worm: {price: 1, discount: 0.2},
* });
*
* const metrics = createMetrics(store);
* metrics.setMetricDefinition(
* 'averageDiscountedPrice',
* 'species',
* 'avg',
* (getCell) => getCell('price') * (1 - getCell('discount')),
* );
*
* console.log(metrics.getMetric('averageDiscountedPrice'));
* // -> 2.5
* ```
* @category Configuration
* @since v1.0.0
*/
setMetricDefinition(
metricId: Id,
tableId: Id,
aggregate?: 'sum' | 'avg' | 'min' | 'max' | MetricAggregate,
getNumber?: Id | ((getCell: GetCell, rowId: Id) => number),
aggregateAdd?: MetricAggregateAdd,
aggregateRemove?: MetricAggregateRemove,
aggregateReplace?: MetricAggregateReplace,
): Metrics;
/**
* The delMetricDefinition method removes an existing Metric definition.
* @param metricId The Id of the Metric to remove.
* @returns A reference to the Metrics object.
* @example
* This example creates a Store, creates a Metrics object, defines a simple
* Metric, and then removes it.
*
* ```js
* import {createMetrics, createStore} from 'tinybase';
*
* const store = createStore().setTable('species', {
* dog: {price: 5},
* cat: {price: 4},
* worm: {price: 1},
* });
*
* const metrics = createMetrics(store);
* metrics.setMetricDefinition('speciesCount', 'species');
* console.log(metrics.getMetricIds());
* // -> ['speciesCount']
*
* metrics.delMetricDefinition('speciesCount');
* console.log(metrics.getMetricIds());
* // -> []
* ```
* @category Configuration
* @since v1.0.0
*/
delMetricDefinition(metricId: Id): Metrics;
/**
* The getStore method returns a reference to the underlying Store that is
* backing this Metrics object.
* @returns A reference to the Store.
* @example
* This example creates a Metrics object against a newly-created Store and
* then gets its reference in order to update its data.
*
* ```js
* import {createMetrics, createStore} from 'tinybase';
*
* const metrics = createMetrics(createStore());
* metrics.setMetricDefinition('speciesCount', 'species');
* metrics.getStore().setCell('species', 'dog', 'price', 5);
* console.log(metrics.getMetric('speciesCount'));
* // -> 1
* ```
* @category Getter
* @since v1.0.0
*/
getStore(): Store;
/**
* The getMetricIds method returns an array of the Metric Ids registered with
* this Metrics object.
* @returns An array of Ids.
* @example
* This example creates a Metrics object with two definitions, and then gets
* the Ids of the definitions.
*
* ```js
* import {createMetrics, createStore} from 'tinybase';
*
* const metrics = createMetrics(createStore())
* .setMetricDefinition('speciesCount', 'species')
* .setMetricDefinition('petsCount', 'pets');
*
* console.log(metrics.getMetricIds());
* // -> ['speciesCount', 'petsCount']
* ```
* @category Getter
* @since v1.0.0
*/
getMetricIds(): Ids;
/**
* The forEachMetric method takes a function that it will then call for each
* Metric in the Metrics object.
*
* This method is useful for iterating over all the Metrics in a functional
* style. The `metricCallback` parameter is a MetricCallback function that
* will be called with the Id of each Metric and its value.
* @param metricCallback The function that should be called for every Metric.
* @example
* This example iterates over each Metric in a Metrics object.
*
* ```js
* import {createMetrics, createStore} from 'tinybase';
*
* const store = createStore().setTable('species', {
* dog: {price: 5},
* cat: {price: 4},
* worm: {price: 1},
* });
* const metrics = createMetrics(store)
* .setMetricDefinition('highestPrice', 'species', 'max', 'price')
* .setMetricDefinition('lowestPrice', 'species', 'min', 'price');
*
* metrics.forEachMetric((metricId, metric) => {
* console.log([metricId, metric]);
* });
* // -> ['highestPrice', 5]
* // -> ['lowestPrice', 1]
* ```
* @category Iterator
* @since v1.0.0
*/
forEachMetric(metricCallback: MetricCallback): void;
/**
* The hasMetric method returns a boolean indicating whether a given Metric
* exists in the Metrics object, and has a value.
* @param metricId The Id of a possible Metric in the Metrics object.
* @returns Whether a Metric with that Id exists.
* @example
* This example shows two simple Metric existence checks.
*
* ```js
* import {createMetrics, createStore} from 'tinybase';
*
* const store = createStore();
* const metrics = createMetrics(store);
* metrics.setMetricDefinition('highestPrice', 'species', 'max', 'price');
*
* console.log(metrics.hasMetric('lowestPrice'));
* // -> false
* console.log(metrics.hasMetric('highestPrice'));
* // -> false
* store.setTable('species', {dog: {price: 5}, cat: {price: 4}});
* console.log(metrics.hasMetric('highestPrice'));
* // -> true
* ```
* @category Getter
* @since v1.0.0
*/
hasMetric(metricId: Id): boolean;
/**
* The getTableId method returns the Id of the underlying Table that is
* backing a Metric.
*
* If the Metric Id is invalid, the method returns `undefined`.
* @param metricId The Id of a Metric.
* @returns The Id of the Table backing the Metric, or `undefined`.
* @example
* This example creates a Metrics object, a single Metric definition, and then
* queries it (and a non-existent definition) to get the underlying Table Id.
*
* ```js
* import {createMetrics, createStore} from 'tinybase';
*
* const metrics = createMetrics(createStore());
* metrics.setMetricDefinition('speciesCount', 'species');
*
* console.log(metrics.getTableId('speciesCount'));
* // -> 'species'
* console.log(metrics.getTableId('petsCount'));
* // -> undefined
* ```
* @category Getter
* @since v1.0.0
*/
getTableId(metricId: Id): Id | undefined;
/**
* The getMetric method gets the current value of a Metric.
*
* If the identified Metric does not exist (or if the definition references a
* Table or Cell value that does not exist) then `undefined` is returned.
* @param metricId The Id of the Metric.
* @returns The numeric value of the Metric, or `undefined`.
* @example
* This example creates a Store, creates a Metrics object, and defines a
* simple Metric to average the price values in the Table. It then uses
* getMetric to access its value (and also the value of a Metric that has not
* been defined).
*
* ```js
* import {createMetrics, createStore} from 'tinybase';
*
* const store = createStore().setTable('species', {
* dog: {price: 5},
* cat: {price: 4},
* worm: {price: 1},
* });
*
* const metrics = createMetrics(store);
* metrics.setMetricDefinition('highestPrice', 'species', 'max', 'price');
*
* console.log(metrics.getMetric('highestPrice'));
* // -> 5
* console.log(metrics.getMetric('lowestPrice'));
* // -> undefined
* ```
* @category Getter
* @since v1.0.0
*/
getMetric(metricId: Id): Metric | undefined;
/**
* The addMetricIdsListener method registers a listener function with the
* Metrics object that will be called whenever a Metric definition is added or
* removed.
*
* The provided listener is a MetricIdsListener function, and will be called
* with a reference to the Metrics object.
* @param listener The function that will be called whenever a Metric
* definition is added or removed.
* @example
* This example creates a Store, a Metrics object, and then registers a
* listener that responds to the addition and the removal of a Metric
* definition.
*
* ```js
* import {createMetrics, createStore} from 'tinybase';
*
* const store = createStore().setTable('species', {
* dog: {price: 5},
* cat: {price: 4},
* worm: {price: 1},
* });
*
* const metrics = createMetrics(store);
* const listenerId = metrics.addMetricIdsListener((metrics) => {
* console.log(metrics.getMetricIds());
* });
*
* metrics.setMetricDefinition('highestPrice', 'species', 'max', 'price');
* // -> ['highestPrice']
* metrics.delMetricDefinition('highestPrice');
* // -> []
*
* metrics.delListener(listenerId);
* ```
* @category Listener
* @since v4.1.0
*/
addMetricIdsListener(listener: MetricIdsListener): Id;
/**
* The addMetricListener method registers a listener function with the Metrics
* object that will be called whenever the value of a specified Metric
* changes.
*
* You can either listen to a single Metric (by specifying the Metric Id as
* the method's first parameter), or changes to any Metric (by providing a
* `null` wildcard).
*
* The provided listener is a MetricListener function, and will be called with
* a reference to the Metrics object, the Id of the Metric that changed, the
* new Metric value, and the old Metric value.
* @param metricId The Id of the Metric to listen to, or `null` as a wildcard.
* @param listener The function that will be called whenever the Metric
* changes.
* @returns A unique Id for the listener that can later be used to remove it.
* @example
* This example creates a Store, a Metrics object, and then registers a
* listener that responds to any changes to a specific Metric.
*
* ```js
* import {createMetrics, createStore} from 'tinybase';
*
* const store = createStore().setTable('species', {
* dog: {price: 5},
* cat: {price: 4},
* worm: {price: 1},
* });
*
* const metrics = createMetrics(store);
* metrics.setMetricDefinition('highestPrice', 'species', 'max', 'price');
*
* const listenerId = metrics.addMetricListener(
* 'highestPrice',
* (metrics, _metricId, newMetric, oldMetric) => {
* console.log('highestPrice metric changed');
* console.log([oldMetric, newMetric]);
* },
* );
*
* store.setCell('species', 'horse', 'price', 20);
* // -> 'highestPrice metric changed'
* // -> [5, 20]
*
* metrics.delListener(listenerId);
* ```
* @example
* This example creates a Store, a Metrics object, and then registers a
* listener that responds to any changes to any Metric.
*
* ```js
* import {createMetrics, createStore} from 'tinybase';
*
* const store = createStore().setTable('species', {
* dog: {price: 5},
* cat: {price: 4},
* worm: {price: 1},
* });
*
* const metrics = createMetrics(store)
* .setMetricDefinition('highestPrice', 'species', 'max', 'price')
* .setMetricDefinition('speciesCount', 'species');
*
* const listenerId = metrics.addMetricListener(
* null,
* (metrics, metricId, newMetric, oldMetric) => {
* console.log(`${metricId} metric changed`);
* console.log([oldMetric, newMetric]);
* },
* );
*
* store.setCell('species', 'horse', 'price', 20);
* // -> 'highestPrice metric changed'
* // -> [5, 20]
* // -> 'speciesCount metric changed'
* // -> [3, 4]
*
* metrics.delListener(listenerId);
* ```
* @category Listener
* @since v1.0.0
*/
addMetricListener(metricId: IdOrNull, listener: MetricListener): Id;
/**
* The delListener method removes a listener that was previously added to the
* Metrics object.
*
* Use the Id returned by the addMetricListener method. Note that the Metrics
* object may re-use this Id for future listeners added to it.
* @param listenerId The Id of the listener to remove.
* @returns A reference to the Metrics object.
* @example
* This example creates a Store, a Metrics object, registers a listener, and
* then removes it.
*
* ```js
* import {createMetrics, createStore} from 'tinybase';
*
* const store = createStore().setTable('species', {
* dog: {price: 5},
* cat: {price: 4},
* worm: {price: 1},
* });
*
* const metrics = createMetrics(store);
* metrics.setMetricDefinition('highestPrice', 'species', 'max', 'price');
*
* const listenerId = metrics.addMetricListener('highestPrice', () => {
* console.log('highestPrice metric changed');
* });
*
* store.setCell('species', 'horse', 'price', 20);
* // -> 'highestPrice metric changed'
*
* metrics.delListener(listenerId);
*
* store.setCell('species', 'giraffe', 'price', 50);
* // -> undefined
* // The listener is not called.
* ```
* @category Listener
* @since v1.0.0
*/
delListener(listenerId: Id): Metrics;
/**
* The destroy method should be called when this Metrics object is no longer
* used.
*
* This guarantees that all of the listeners that the object registered with
* the underlying Store are removed and it can be correctly garbage collected.
* @example
* This example creates a Store, adds a Metrics object with a definition (that
* registers a RowListener with the underlying Store), and then destroys it
* again, removing the listener.
*
* ```js
* import {createMetrics, createStore} from 'tinybase';
*
* const store = createStore().setTable('species', {
* dog: {price: 5},
* cat: {price: 4},
* worm: {price: 1},
* });
*
* const metrics = createMetrics(store);
* metrics.setMetricDefinition('speciesCount', 'species');
* console.log(store.getListenerStats().row);
* // -> 1
*
* metrics.destroy();
*
* console.log(store.getListenerStats().row);
* // -> 0
* ```
* @category Lifecycle
* @since v1.0.0
*/
destroy(): void;
/**
* The getListenerStats method provides a set of statistics about the
* listeners registered with the Metrics object, and is used for debugging
* purposes.
*
* The method is intended to be used during development to ensure your
* application is not leaking listener registrations, for example.
* @returns A MetricsListenerStats object containing Metrics listener
* statistics.
* @example
* This example gets the listener statistics of a Metrics object.
*
* ```js
* import {createMetrics, createStore} from 'tinybase';
*
* const store = createStore();
* const metrics = createMetrics(store);
* metrics.addMetricListener(null, () => console.log('Metric changed'));
*
* console.log(metrics.getListenerStats());
* // -> {metric: 1}
* ```
* @category Development
* @since v1.0.0
*/
getListenerStats(): MetricsListenerStats;
//
}
/**
* The createMetrics function creates a Metrics object, and is the main entry
* point into the metrics module.
*
* A given Store can only have one Metrics object associated with it. If you
* call this function twice on the same Store, your second call will return a
* reference to the Metrics object created by the first.
* @param store The Store for which to register Metric definitions.
* @returns A reference to the new Metrics object.
* @example
* This example creates a Metrics object.
*
* ```js
* import {createMetrics, createStore} from 'tinybase';
*
* const store = createStore();
* const metrics = createMetrics(store);
* console.log(metrics.getMetricIds());
* // -> []
* ```
* @example
* This example creates a Metrics object, and calls the method a second time
* for the same Store to return the same object.
*
* ```js
* import {createMetrics, createStore} from 'tinybase';
*
* const store = createStore();
* const metrics1 = createMetrics(store);
* const metrics2 = createMetrics(store);
* console.log(metrics1 === metrics2);
* // -> true
* ```
* @category Creation
* @since v1.0.0
*/
export function createMetrics(store: Store): Metrics;