tinybase
Version: 
A reactive data store and sync engine.
1,545 lines (1,497 loc) • 323 kB
TypeScript
/**
 * The store module is the core of the TinyBase project and contains the types,
 * interfaces, and functions to work with Store objects.
 *
 * The main entry point to this module is the createStore function, which
 * returns a new Store. From there, you can set and get data, register
 * listeners, and use other modules to build an entire app around the state and
 * tabular data within.
 * @packageDocumentation
 * @module store
 * @since v1.0.0
 */
import type {
  AllCellIdFromSchema,
  CellIdFromSchema,
  DefaultCellIdFromSchema,
  DefaultValueIdFromSchema,
  DefaultedCellFromSchema,
  DefaultedValueFromSchema,
  StoreAlias,
  TableIdFromSchema,
  Truncate,
  ValueIdFromSchema,
} from '../../_internal/store/with-schemas/index.d.ts';
import type {
  Id,
  IdOrNull,
  Ids,
  Json,
} from '../../common/with-schemas/index.d.ts';
/**
 * The TablesSchema type describes the tabular structure of a Store in terms of
 * valid Table Ids and the types of Cell that can exist within them.
 *
 * A TablesSchema comprises a JavaScript object describing each Table, in turn a
 * nested JavaScript object containing information about each Cell and its
 * CellSchema. It is provided to the setTablesSchema method.
 * @example
 * When applied to a Store, this TablesSchema only allows one Table called
 * `pets`, in which each Row may contain a string `species` Cell, and is
 * guaranteed to contain a boolean `sold` Cell that defaults to `false`.
 *
 * ```js
 * import type {TablesSchema} from 'tinybase';
 *
 * export const tableSchema: TablesSchema = {
 *   pets: {
 *     species: {type: 'string'},
 *     sold: {type: 'boolean', default: false},
 *   },
 * };
 * ```
 * @category Schema
 * @since v1.0.0
 */
export type TablesSchema = {[tableId: Id]: {[cellId: Id]: CellSchema}};
/**
 * The CellSchema type describes what values are allowed for each Cell in a
 * Table.
 *
 * A CellSchema specifies the type of the Cell (`string`, `boolean`, or
 * `number`), and what the default value can be when an explicit value is not
 * specified.
 *
 * If a default value is provided (and its type is correct), you can be certain
 * that that Cell will always be present in a Row.
 *
 * If the default value is _not_ provided (or its type is incorrect), the Cell
 * may be missing from the Row, but when present you can be guaranteed it is of
 * the correct type.
 * @example
 * When applied to a Store, this CellSchema ensures a boolean Cell is always
 * present, and defaults it to `false`.
 *
 * ```js
 * import type {CellSchema} from 'tinybase';
 *
 * export const requiredBoolean: CellSchema = {
 *   type: 'boolean',
 *   default: false,
 * };
 * ```
 * @category Schema
 * @since v1.0.0
 */
export type CellSchema =
  | {type: 'string'; default?: string}
  | {type: 'number'; default?: number}
  | {type: 'boolean'; default?: boolean};
/**
 * The ValuesSchema type describes the keyed Values that can be set in a Store
 * and their types.
 *
 * A ValuesSchema comprises a JavaScript object describing each Value and its
 * ValueSchema. It is provided to the setValuesSchema method.
 * @example
 * When applied to a Store, this ValuesSchema only allows one boolean Value
 * called `open`, that defaults to `false`.
 *
 * ```js
 * import type {ValuesSchema} from 'tinybase';
 *
 * export const valuesSchema: ValuesSchema = {
 *   open: {type: 'boolean', default: false},
 * };
 * ```
 * @category Schema
 * @since v3.0.0
 */
export type ValuesSchema = {[valueId: Id]: ValueSchema};
/**
 * The ValueSchema type describes what values are allowed for keyed Values in a
 * Store.
 *
 * A ValueSchema specifies the type of the Value (`string`, `boolean`, or
 * `number`), and what the default value can be when an explicit value is not
 * specified.
 *
 * If a default value is provided (and its type is correct), you can be certain
 * that the Value will always be present in a Store.
 *
 * If the default value is _not_ provided (or its type is incorrect), the Value
 * may not be present in the Store, but when present you can be guaranteed it is
 * of the correct type.
 * @example
 * When applied to a Store, this ValueSchema ensures a boolean Value is always
 * present, and defaults it to `false`.
 *
 * ```js
 * import type {ValueSchema} from 'tinybase';
 *
 * export const requiredBoolean: ValueSchema = {
 *   type: 'boolean',
 *   default: false,
 * };
 * ```
 * @category Schema
 * @since v3.0.0
 */
export type ValueSchema =
  | {type: 'string'; default?: string}
  | {type: 'number'; default?: number}
  | {type: 'boolean'; default?: boolean};
/**
 * The NoTablesSchema type is a TablesSchema-like type for when one has not been
 * provided.
 * @category Schema
 * @since v1.0.0
 */
export type NoTablesSchema = {[tableId: Id]: {[cellId: Id]: {type: 'any'}}};
/**
 * The NoValuesSchema type is a ValuesSchema-like type for when one has not been
 * provided.
 * @category Schema
 * @since v1.0.0
 */
export type NoValuesSchema = {[valueId: Id]: {type: 'any'}};
/**
 * The OptionalTablesSchema type is used by generic types that can optionally
 * take a TablesSchema.
 * @category Schema
 * @since v1.0.0
 */
export type OptionalTablesSchema = TablesSchema | NoTablesSchema;
/**
 * The OptionalValuesSchema type is used by generic types that can optionally
 * take a ValuesSchema.
 * @category Schema
 * @since v1.0.0
 */
export type OptionalValuesSchema = ValuesSchema | NoValuesSchema;
/**
 * The OptionalSchemas type is used by generic types that can optionally take
 * either or both of a TablesSchema and ValuesSchema.
 * @category Schema
 * @since v1.0.0
 */
export type OptionalSchemas = [OptionalTablesSchema, OptionalValuesSchema];
/**
 * The NoSchemas type is used as a default by generic types that can optionally
 * take either or both of a TablesSchema and ValuesSchema.
 * @category Schema
 * @since v1.0.0
 */
export type NoSchemas = [NoTablesSchema, NoValuesSchema];
/**
 * The Content type describes both the Tables and Values in a Store.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * [Tables, Values];
 * ```
 *
 * It is an array of two objects, representing tabular and keyed value content.
 * @example
 * The following is a valid Content array:
 * ```json
 * [
 *   {
 *     "pets": {
 *       "fido": {
 *         "sold": false,
 *         "price": 4,
 *       },
 *       "felix": {
 *         "sold": true,
 *         "price": 5,
 *       },
 *     },
 *   },
 *   {
 *     open: true,
 *     employees: 3,
 *   },
 * ]
 * ```
 * @category Store
 * @since v5.0.0
 */
export type Content<
  Schemas extends OptionalSchemas,
  WhenSet extends boolean = false,
> = [Tables<Schemas[0], WhenSet>, Values<Schemas[1], WhenSet>];
/**
 * The Tables type is the data structure representing all of the data in a
 * Store.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * {[tableId: Id]: Table};
 * ```
 *
 * A Tables object is used when setting all of the tables together with the
 * setTables method, and when getting them back out again with the getTables
 * method. A Tables object is a regular JavaScript object containing individual
 * Table objects, keyed by their Id.
 * @example
 * ```js
 * import type {Tables} from 'tinybase';
 *
 * export const tables: Tables = {
 *   pets: {
 *     fido: {species: 'dog', color: 'brown'},
 *     felix: {species: 'cat'},
 *   },
 *   species: {
 *     dog: {price: 5},
 *     cat: {price: 4},
 *   },
 * };
 * ```
 * @category Store
 * @since v1.0.0
 */
export type Tables<
  Schema extends OptionalTablesSchema,
  WhenSet extends boolean = false,
> = {
  -readonly [TableId in TableIdFromSchema<Schema>]?: Table<
    Schema,
    TableId,
    WhenSet
  >;
};
/**
 * The Table type is the data structure representing the data in a single table.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * {[rowId: Id]: Row};
 * ```
 *
 * A Table is used when setting a table with the setTable method, and when
 * getting it back out again with the getTable method. A Table object is a
 * regular JavaScript object containing individual Row objects, keyed by their
 * Id.
 * @example
 * ```js
 * import type {Table} from 'tinybase';
 *
 * export const table: Table = {
 *   fido: {species: 'dog', color: 'brown'},
 *   felix: {species: 'cat'},
 * };
 * ```
 * @category Store
 * @since v1.0.0
 */
export type Table<
  Schema extends OptionalTablesSchema,
  TableId extends TableIdFromSchema<Schema>,
  WhenSet extends boolean = false,
> = {[rowId: Id]: Row<Schema, TableId, WhenSet>};
/**
 * The Row type is the data structure representing the data in a single row.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * {[cellId: Id]: Cell};
 * ```
 *
 * A Row is used when setting a row with the setRow method, and when getting it
 * back out again with the getRow method. A Row object is a regular JavaScript
 * object containing individual Cell objects, keyed by their Id.
 * @example
 * ```js
 * import type {Row} from 'tinybase';
 *
 * export const row: Row = {species: 'dog', color: 'brown'};
 * ```
 * @category Store
 * @since v1.0.0
 */
export type Row<
  Schema extends OptionalTablesSchema,
  TableId extends TableIdFromSchema<Schema>,
  WhenSet extends boolean = false,
> = (WhenSet extends true
  ? {
      -readonly [CellId in DefaultCellIdFromSchema<Schema, TableId>]?: Cell<
        Schema,
        TableId,
        CellId
      >;
    }
  : {
      -readonly [CellId in DefaultCellIdFromSchema<Schema, TableId>]: Cell<
        Schema,
        TableId,
        CellId
      >;
    }) & {
  -readonly [CellId in DefaultCellIdFromSchema<Schema, TableId, false>]?: Cell<
    Schema,
    TableId,
    CellId
  >;
};
/**
 * The Cell type is the data structure representing the data in a single cell.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * string | number | boolean;
 * ```
 *
 * A Cell is used when setting a cell with the setCell method, and when getting
 * it back out again with the getCell method. A Cell is a JavaScript string,
 * number, or boolean.
 * @example
 * ```js
 * import type {Cell} from 'tinybase';
 *
 * export const cell: Cell = 'dog';
 * ```
 * @category Store
 * @since v1.0.0
 */
export type Cell<
  Schema extends OptionalTablesSchema,
  TableId extends TableIdFromSchema<Schema>,
  CellId extends CellIdFromSchema<Schema, TableId>,
  CellType = Schema[TableId][CellId]['type'],
> = CellType extends 'string'
  ? string
  : CellType extends 'number'
    ? number
    : CellType extends 'boolean'
      ? boolean
      : string | number | boolean;
/**
 * The CellOrUndefined type is a data structure representing the data in a
 * single cell, or the value `undefined`.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * Cell | undefined;
 * ```
 *
 * This is used when describing a Cell that is present _or_ that is not present,
 * such as when it has been deleted, or when describing a previous state where
 * the Cell value has since been added.
 * @category Store
 * @since v1.0.0
 */
export type CellOrUndefined<
  Schema extends OptionalTablesSchema,
  TableId extends TableIdFromSchema<Schema>,
  CellId extends CellIdFromSchema<Schema, TableId>,
> = Cell<Schema, TableId, CellId> | undefined;
/**
 * The Values type is the data structure representing all the keyed values in a
 * Store.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * {[valueId: Id]: Value};
 * ```
 *
 * A Values object is used when setting values with the setValues method, and
 * when getting them back out again with the getValues method. A Values object
 * is a regular JavaScript object containing individual Value objects, keyed by
 * their Id.
 * @example
 * ```js
 * import type {Values} from 'tinybase';
 *
 * export const values: Values = {open: true, employees: 4};
 * ```
 * @category Store
 * @since v3.0.0
 */
export type Values<
  Schema extends OptionalValuesSchema,
  WhenSet extends boolean = false,
> = (WhenSet extends true
  ? {
      -readonly [ValueId in DefaultValueIdFromSchema<Schema>]?: Value<
        Schema,
        ValueId
      >;
    }
  : {
      -readonly [ValueId in DefaultValueIdFromSchema<Schema>]: Value<
        Schema,
        ValueId
      >;
    }) & {
  -readonly [ValueId in DefaultValueIdFromSchema<Schema, false>]?: Value<
    Schema,
    ValueId
  >;
};
/**
 * The Value type is the data structure representing the data in a single keyed
 * value.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * string | number | boolean;
 * ```
 *
 * A Value is used when setting a value with the setValue method, and when
 * getting it back out again with the getValue method. A Value is a JavaScript
 * string, number, or boolean.
 * @example
 * ```js
 * import type {Value} from 'tinybase';
 *
 * export const value: Value = 'dog';
 * ```
 * @category Store
 * @since v3.0.0
 */
export type Value<
  Schema extends OptionalValuesSchema,
  ValueId extends ValueIdFromSchema<Schema>,
  ValueType = Schema[ValueId]['type'],
> = ValueType extends 'string'
  ? string
  : ValueType extends 'number'
    ? number
    : ValueType extends 'boolean'
      ? boolean
      : string | number | boolean;
/**
 * The ValueOrUndefined type is a data structure representing the data in a
 * single value, or the value `undefined`.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * Value | undefined;
 * ```
 *
 * This is used when describing a Value that is present _or_ that is not
 * present, such as when it has been deleted, or when describing a previous
 * state where the Value has since been added.
 * @category Store
 * @since v3.0.0
 */
export type ValueOrUndefined<
  Schema extends OptionalValuesSchema,
  ValueId extends ValueIdFromSchema<Schema>,
> = Value<Schema, ValueId> | undefined;
/**
 * The TableCallback type describes a function that takes a Table's Id and a
 * callback to loop over each Row within it.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * (
 *   tableId: Id,
 *   forEachRow: (rowCallback: RowCallback) => void,
 * ) => void;
 * ```
 *
 * A TableCallback is provided when using the forEachTable method, so that you
 * can do something based on every Table in the Store. See that method for
 * specific examples.
 * @param tableId The Id of the Table that the callback can operate on.
 * @param forEachRow A function that will let you iterate over the Row objects
 * in this Table.
 * @category Callback
 * @since v1.0.0
 */
export type TableCallback<
  Schema extends OptionalTablesSchema,
  Params extends any[] = TableIdFromSchema<Schema> extends infer TableId
    ? TableId extends TableIdFromSchema<Schema>
      ? [
          tableId: TableId,
          forEachRow: (rowCallback: RowCallback<Schema, TableId>) => void,
        ]
      : never
    : never,
  Params2 extends any[] = Params | [tableId: never, forEachRow: never],
  Params1 extends any[] = Truncate<Params2>,
> = ((...params: Params2) => void) | ((...params: Params1) => void);
/**
 * The TableCellCallback type describes a function that takes a Cell's Id and
 * the count of times it appears across a whole Table.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * (cellId: Id, count: number) => void;
 * ```
 *
 * A TableCellCallback is provided when using the forEachTableCell method, so
 * that you can do something based on every Cell used across a Table. See that
 * method for specific examples.
 * @param cellId The Id of the Cell that the callback can operate on.
 * @param count The number of times this Cell is used across a whole Table.
 * @category Callback
 * @since v1.0.0
 */
export type TableCellCallback<
  Schema extends OptionalTablesSchema,
  TableId extends TableIdFromSchema<Schema>,
> = (cellId: CellIdFromSchema<Schema, TableId>, count: number) => void;
/**
 * The RowCallback type describes a function that takes a Row's Id and a
 * callback to loop over each Cell within it.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * (
 *   rowId: Id,
 *   forEachCell: (cellCallback: CellCallback) => void,
 * ) => void;
 * ```
 *
 * A RowCallback is provided when using the forEachRow method, so that you can
 * do something based on every Row in a Table. See that method for specific
 * examples.
 * @param rowId The Id of the Row that the callback can operate on.
 * @param forEachCell A function that will let you iterate over the Cell values
 * in this Row.
 * @category Callback
 * @since v1.0.0
 */
export type RowCallback<
  Schema extends OptionalTablesSchema,
  TableIdOrNull extends TableIdFromSchema<Schema> | null = null,
  Params extends any[] = [
    rowId: Id,
    forEachCell: (cellCallback: CellCallback<Schema, TableIdOrNull>) => void,
  ],
  Params2 extends any[] = Params | [rowId: never, forEachCell: never],
  // Params1 extends any[] = Truncate<Params2>,
> = Params extends any[] ? (...params: Params2) => void : never;
// | ((...params: Params1) => void)
/**
 * The CellCallback type describes a function that takes a Cell's Id and its
 * value.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * (cellId: Id, cell: Cell) => void;
 * ```
 *
 * A CellCallback is provided when using the forEachCell method, so that you can
 * do something based on every Cell in a Row. See that method for specific
 * examples.
 * @param cellId The Id of the Cell that the callback can operate on.
 * @param cell The value of the Cell.
 * @category Callback
 * @since v1.0.0
 */
export type CellCallback<
  Schema extends OptionalTablesSchema,
  TableIdOrNull extends TableIdFromSchema<Schema> | null = null,
  Params extends any[] = (
    TableIdOrNull extends null ? TableIdFromSchema<Schema> : TableIdOrNull
  ) extends infer TableId
    ? TableId extends TableIdFromSchema<Schema>
      ? CellIdFromSchema<Schema, TableId> extends infer CellId
        ? CellId extends CellIdFromSchema<Schema, TableId>
          ? [cellId: CellId, cell: Cell<Schema, TableId, CellId>]
          : never
        : never
      : never
    : never,
  Params2 extends any[] = Params | [cellId: never, cell: never],
  Params1 extends any[] = Truncate<Params2>,
> = Params extends any[]
  ? ((...params: Params2) => void) | ((...params: Params1) => void)
  : never;
/**
 * The ValueCallback type describes a function that takes a Value's Id and its
 * actual value.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * (valueId: Id, value: Value) => void;
 * ```
 *
 * A ValueCallback is provided when using the forEachValue method, so that you
 * can do something based on every Value in a Store. See that method for
 * specific examples.
 * @param valueId The Id of the Value that the callback can operate on.
 * @param value The Value itself.
 * @category Callback
 * @since v3.0.0
 */
export type ValueCallback<
  Schema extends OptionalValuesSchema,
  Params extends any[] = ValueIdFromSchema<Schema> extends infer ValueId
    ? ValueId extends ValueIdFromSchema<Schema>
      ?
          | [valueId: ValueId, value: Value<Schema, ValueId>]
          | [valueId: never, value: never]
      : never
    : never,
  Params2 extends any[] = Params | [valueId: never, value: never],
  Params1 extends any[] = Truncate<Params2>,
> = Params extends any[]
  ? ((...params: Params2) => void) | ((...params: Params1) => void)
  : never;
/**
 * The MapCell type describes a function that takes an existing Cell value and
 * returns another.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * (cell: CellOrUndefined) => Cell;
 * ```
 *
 * A MapCell can be provided in the setCell method to map an existing value to a
 * new one, such as when incrementing a number. See that method for specific
 * examples.
 * @param cell The current value of the Cell to map to a new value.
 * @category Callback
 * @since v1.0.0
 */
export type MapCell<
  Schema extends OptionalTablesSchema,
  TableId extends TableIdFromSchema<Schema>,
  CellId extends CellIdFromSchema<Schema, TableId>,
> = (
  cell: CellOrUndefined<Schema, TableId, CellId>,
) => Cell<Schema, TableId, CellId>;
/**
 * The MapValue type describes a function that takes an existing Value and
 * returns another.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * (value: ValueOrUndefined) => Value;
 * ```
 *
 * A MapValue can be provided in the setValue method to map an existing Value to
 * a new one, such as when incrementing a number. See that method for specific
 * examples.
 * @param value The current Value to map to a new Value.
 * @category Callback
 * @since v3.0.0
 */
export type MapValue<
  Schema extends OptionalValuesSchema,
  ValueId extends ValueIdFromSchema<Schema> = ValueIdFromSchema<Schema>,
> = (value: ValueOrUndefined<Schema, ValueId>) => Value<Schema, ValueId>;
/**
 * The GetCell type describes a function that takes a Id and returns the Cell
 * value for a particular Row.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * (cellId: Id) => CellOrUndefined;
 * ```
 *
 * A GetCell can be provided when setting definitions, as in the
 * setMetricDefinition method of a Metrics object, or the setIndexDefinition
 * method of an Indexes object. See those methods for specific examples.
 * @param cellId The Id of the Cell to fetch the value for.
 * @category Callback
 * @since v1.0.0
 */
export type GetCell<
  Schema extends OptionalTablesSchema,
  TableId extends TableIdFromSchema<Schema>,
> = <CellId extends CellIdFromSchema<Schema, TableId>>(
  cellId: CellId,
) => DefaultedCellFromSchema<Schema, TableId, CellId>;
/**
 * The IdAddedOrRemoved type describes a change made to an Id in either the
 * tabular or keyed-value part of the Store (or in other TinyBase modules).
 *
 * This type is used in other types like ChangedTableIds, ChangedRowIds,
 * ChangedCellIds, and ChangedValueIds, as well as in other events or listeners
 * where a list of Ids has changed.
 *
 * It is a simple number: a 1 indicates that a given Id was added to a list of
 * Ids, and a -1 indicates that it was removed.
 * @category Transaction
 * @since v4.0.0
 */
export type IdAddedOrRemoved = 1 | -1;
/**
 * The ChangedTableIds type describes the Table Ids that were added or removed
 * during a transaction.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * {[tableId: Id]: IdAddedOrRemoved};
 * ```
 *
 * It is available to the DoRollback function and to a TransactionListener
 * function via the TransactionLog object.
 *
 * It is a simple object that has Table Id as key, and an IdAddedOrRemoved
 * number indicating whether the Table Id was added (1) or removed (-1).
 *
 * Note that there will be no entry if the content of the Table itself changed.
 * For that you should consult the ChangedRowIds, ChangedCellIds, or
 * ChangedCells types.
 * @category Transaction
 * @since v4.0.0
 */
export type ChangedTableIds<Schema extends OptionalTablesSchema> = {
  [TableId in TableIdFromSchema<Schema>]: IdAddedOrRemoved;
};
/**
 * The ChangedRowIds type describes the Row Ids that were added or removed
 * during a transaction.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * {[tableId: Id]: {[rowId: Id]: IdAddedOrRemoved}};
 * ```
 *
 * It is available to the DoRollback function and to a TransactionListener
 * function via the TransactionLog object.
 *
 * It is a nested object that has Table Id as a top-level key, and then Row Id
 * as an inner key. The values of the inner objects are IdAddedOrRemoved numbers
 * indicating whether the Row Id was added (1) or removed (-1) to the given
 * Table.
 *
 * Note that there will be no entry if the content of the Row itself changed.
 * For that you should consult the ChangedCellIds or ChangedCells types.
 * @category Transaction
 * @since v4.0.0
 */
export type ChangedRowIds<Schema extends OptionalTablesSchema> = {
  [TableId in TableIdFromSchema<Schema>]: {[rowId: Id]: IdAddedOrRemoved};
};
/**
 * The ChangedCellIds type describes the Cell Ids that were added or removed
 * during a transaction.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * {
 *   [tableId: Id]: {[rowId: Id]: {[cellId: Id]: IdAddedOrRemoved}};
 * };
 * ```
 *
 * It is available to the DoRollback function and to a TransactionListener
 * function via the TransactionLog object.
 *
 * It is a nested object that has Table Id as a top-level key, and Row Id, and
 * then CellId as inner keys. The values of the inner objects are
 * IdAddedOrRemoved numbers indicating whether the Cell Id was added (1) or
 * removed (-1) to the given Row.
 *
 * Note that there will be no entry if the content of the Cell itself changed.
 * For that you should consult the ChangedCells type.
 * @category Transaction
 * @since v4.0.0
 */
export type ChangedCellIds<Schema extends OptionalTablesSchema> = {
  [TableId in TableIdFromSchema<Schema>]: {
    [rowId: Id]: {
      [CellId in CellIdFromSchema<Schema, TableId>]: IdAddedOrRemoved;
    };
  };
};
/**
 * The ChangedValueIds type describes the Value Ids that were added or removed
 * during a transaction.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * {[valueId: Id]: IdAddedOrRemoved};
 * ```
 *
 * It is available to the DoRollback function and to a TransactionListener
 * function via the TransactionLog object.
 *
 * It is a simple object that has Value Id as key, and an IdAddedOrRemoved
 * number indicating whether the Value Id was added (1) or removed (-1).
 *
 * Note that there will be no entry if the content of the Value itself changed.
 * For that you should consult the ChangedValues type.
 * @category Transaction
 * @since v4.0.0
 */
export type ChangedValueIds<Schema extends OptionalValuesSchema> = {
  [ValueId in ValueIdFromSchema<Schema>]: IdAddedOrRemoved;
};
/**
 * The DoRollback type describes a function that you can use to rollback the
 * transaction if it did not complete to your satisfaction.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * (store: Store) => boolean;
 * ```
 *
 * A DoRollback can be provided when calling the transaction method or the
 * finishTransaction method. See those methods for specific examples.
 *
 * Since v5.0, this function is called with the Store as a single argument. You
 * can use the getTransactionChanges method and getTransactionLog method of the
 * Store directly to decide whether to do the rollback.
 * @param store A reference to the Store that is completing a transaction.
 * @category Callback
 * @since v1.0.0
 */
export type DoRollback<Schemas extends OptionalSchemas> = (
  store: Store<Schemas>,
) => boolean;
/**
 * The SortedRowIdsArgs type describes the arguments used to sort Row Ids using
 * the getSortedRowIds method.
 *
 * It's an object containing the Id of the Table in the Store, and optional
 * `cellId`, `descending`, `offset`, and `limit` parameters. See the
 * getSortedRowIds method for specific examples.
 * @category Store
 * @since v6.1.0
 */
export type SortedRowIdsArgs<
  Schema extends OptionalTablesSchema,
  TableId extends TableIdFromSchema<Schema>,
  CellIdOrUndefined extends CellIdFromSchema<Schema, TableId> | undefined =
    | CellIdFromSchema<Schema, TableId>
    | undefined,
> = {
  /**
   * The Id of the Table in the Store, required.
   * @category Argument
   * @since v6.1.0
   */
  tableId: TableId;
  /**
   * The optional Id of the Cell whose values are used for the sorting, defaults
   * to sorting by the Row Id itself.
   * @category Argument
   * @since v6.1.0
   */
  cellId?: CellIdOrUndefined;
  /**
   * Whether the sorting should be in descending order, defaulting to false.
   * @category Argument
   * @since v6.1.0
   */
  descending?: boolean;
  /**
   * The number of Row Ids to skip for pagination purposes, defaulting to 0.
   * @category Argument
   * @since v6.1.0
   */
  offset?: number;
  /**
   * The maximum number of Row Ids to return, defaulting to all.
   * @category Argument
   * @since v6.1.0
   */
  limit?: number;
};
/**
 * The TransactionListener type describes a function that is used to listen to
 * the completion of a transaction for the Store.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * export type TransactionListener<Store extends StoreAlias = StoreAlias> = (
 *   store: Store,
 * ) => void;
 * ```
 *
 * A TransactionListener is provided when using the
 * addWillFinishTransactionListener and addDidFinishTransactionListener methods.
 * See those methods for specific examples.
 *
 * Since v5.0, this listener is called with no arguments other than the Store.
 * You can use the getTransactionChanges method and getTransactionLog method of
 * the Store directly to get information about the changes made within the
 * transaction.
 * @param store A reference to the Store that is completing a transaction.
 * @category Listener
 * @since v1.0.0
 */
export type TransactionListener<
  Schemas extends OptionalSchemas,
  Store extends StoreAlias<Schemas> = StoreAlias<Schemas>,
> = (store: Store) => void;
/**
 * The HasTablesListener type describes a function that is used to listen to
 * Tables as a whole being added to or removed from the Store.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * export type HasTablesListener<Store extends StoreAlias = StoreAlias> = (
 *   store: Store,
 *   hasTables: boolean,
 * ) => void;
 * ```
 *
 * A HasTablesListener is provided when using the addHasTablesListener method.
 * See that method for specific examples.
 *
 * When called, a HasTablesListener is given a reference to the Store. It is
 * also given a flag to indicate whether Tables now exist (having not done
 * previously), or do not (having done so previously).
 * @param store A reference to the Store that changed.
 * @param hasTables Whether Tables now exist or not.
 * @category Listener
 * @since v4.4.0
 */
export type HasTablesListener<
  Schemas extends OptionalSchemas,
  Store extends StoreAlias<Schemas> = StoreAlias<Schemas>,
> = (store: Store, hasTables: boolean) => void;
/**
 * The TablesListener type describes a function that is used to listen to
 * changes to the tabular part of the Store.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * export type TablesListener<Store extends StoreAlias = StoreAlias> = (
 *   store: Store,
 *   getCellChange: GetCellChange | undefined,
 * ) => void;
 * ```
 *
 * A TablesListener is provided when using the addTablesListener method. See
 * that method for specific examples.
 *
 * When called, a TablesListener is given a reference to the Store and a
 * GetCellChange function that can be used to query Cell values before and after
 * the current transaction.
 *
 * Note that if the listener was manually forced to be called (with the
 * callListener method rather than due to a real change in the Store), the
 * GetCellChange function will not be present.
 * @param store A reference to the Store that changed.
 * @param getCellChange A function that returns information about any Cell's
 * changes.
 * @category Listener
 * @since v1.0.0
 */
export type TablesListener<
  Schemas extends OptionalSchemas,
  Store extends StoreAlias<Schemas> = StoreAlias<Schemas>,
> = (
  store: Store,
  getCellChange: GetCellChange<Schemas[0]> | undefined,
) => void;
/**
 * The TableIdsListener type describes a function that is used to listen to
 * changes to the Table Ids in the Store.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * export type TableIdsListener<Store extends StoreAlias = StoreAlias> = (
 *   store: Store,
 *   getIdChanges: GetIdChanges | undefined,
 * ) => void;
 * ```
 *
 * A TableIdsListener is provided when using the addTableIdsListener method. See
 * that method for specific examples.
 *
 * When called, a TableIdsListener is given a reference to the Store.
 *
 * Since v3.3, the listener is also passed a GetIdChanges function that can be
 * used to query which Ids changed during the transaction.
 * @param store A reference to the Store that changed.
 * @param getIdChanges A function that returns information about the Id changes,
 * since v3.3.
 * @category Listener
 * @since v1.0.0
 */
export type TableIdsListener<
  Schemas extends OptionalSchemas,
  Store extends StoreAlias<Schemas> = StoreAlias<Schemas>,
> = (
  store: Store,
  getIdChanges: GetIdChanges<TableIdFromSchema<Schemas[0]>> | undefined,
) => void;
/**
 * The HasTableListener type describes a function that is used to listen to a
 * Table being added to or removed from the Store.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * export type HasTableListener<Store extends StoreAlias = StoreAlias> = (
 *   store: Store,
 *   tableId: Id,
 *   hasTable: boolean,
 * ) => void;
 * ```
 *
 * A HasTableListener is provided when using the addHasTableListener method. See
 * that method for specific examples.
 *
 * When called, a HasTableListener is given a reference to the Store, and the Id
 * of the Table that changed. It is also given a flag to indicate whether the
 * Table now exists (having not done previously), or does not (having done so
 * previously).
 * @param store A reference to the Store that changed.
 * @param tableId The Id of the Table that changed.
 * @param hasTable Whether the Table now exists or not.
 * @category Listener
 * @since v4.4.0
 */
export type HasTableListener<
  Schemas extends OptionalSchemas,
  TableIdOrNull extends TableIdFromSchema<Schemas[0]> | null,
  Store extends StoreAlias<Schemas> = StoreAlias<Schemas>,
> = (
  store: Store,
  tableId: TableIdOrNull extends null
    ? TableIdFromSchema<Schemas[0]>
    : TableIdOrNull,
  hasTable: boolean,
) => void;
/**
 * The TableListener type describes a function that is used to listen to changes
 * to a Table.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * export type TableListener<Store extends StoreAlias = StoreAlias> = (
 *   store: Store,
 *   tableId: Id,
 *   getCellChange: GetCellChange | undefined,
 * ) => void;
 * ```
 *
 * A TableListener is provided when using the addTableListener method. See that
 * method for specific examples.
 *
 * When called, a TableListener is given a reference to the Store, the Id of the
 * Table that changed, and a GetCellChange function that can be used to query
 * Cell values before and after the current transaction.
 *
 * Note that if the listener was manually forced to be called (with the
 * callListener method rather than due to a real change in the Store), the
 * GetCellChange function will not be present.
 * @param store A reference to the Store that changed.
 * @param tableId The Id of the Table that changed.
 * @param getCellChange A function that returns information about any Cell's
 * changes.
 * @category Listener
 * @since v1.0.0
 */
export type TableListener<
  Schemas extends OptionalSchemas,
  TableIdOrNull extends TableIdFromSchema<Schemas[0]> | null,
  Store extends StoreAlias<Schemas> = StoreAlias<Schemas>,
> = (
  store: Store,
  tableId: TableIdOrNull extends null
    ? TableIdFromSchema<Schemas[0]>
    : TableIdOrNull,
  getCellChange: GetCellChange<Schemas[0]> | undefined,
) => void;
/**
 * The TableCellIdsListener type describes a function that is used to listen to
 * changes to the Cell Ids that appear anywhere in a Table.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * export type TableCellIdsListener<Store extends StoreAlias = StoreAlias> = (
 *   store: Store,
 *   tableId: Id,
 *   getIdChanges: GetIdChanges | undefined,
 * ) => void;
 * ```
 *
 * A TableCellIdsListener is provided when using the addTableCellIdsListener
 * method. See that method for specific examples.
 *
 * When called, a TableCellIdsListener is given a reference to the Store, the Id
 * of the Table whose Cell Ids changed, and a GetIdChanges function that can be
 * used to query which Ids changed during the transaction.
 * @param store A reference to the Store that changed.
 * @param tableId The Id of the Table that changed.
 * @param getIdChanges A function that returns information about the Id changes.
 * @category Listener
 * @since v3.3.0
 */
export type TableCellIdsListener<
  Schemas extends OptionalSchemas,
  TableIdOrNull extends TableIdFromSchema<Schemas[0]> | null,
  Store extends StoreAlias<Schemas> = StoreAlias<Schemas>,
  Params extends any[] = (
    TableIdOrNull extends null ? TableIdFromSchema<Schemas[0]> : TableIdOrNull
  ) extends infer TableId
    ? TableId extends TableIdFromSchema<Schemas[0]>
      ? [
          store: Store,
          tableId: TableId,
          getIdChanges: GetIdChanges<CellIdFromSchema<Schemas[0], TableId>>,
        ]
      : never
    : never,
  Params3 extends any[] =
    | Params
    | [store: never, tableId: never, getIdChanges: never],
  Params2 extends any[] = Truncate<Params3>,
  // Params1 extends any[] = Truncate<Params2>,
> = Params extends any
  ? ((...params: Params3) => void) | ((...params: Params2) => void)
  : // | ((...params: Params1) => void)
    never;
/**
 * The HasTableCellListener type describes a function that is used to listen to
 * a Cell being added to or removed from a Table as a whole.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * export type HasTableCellListener<Store extends StoreAlias = StoreAlias> = (
 *   store: Store,
 *   tableId: Id,
 *   cellId: Id,
 *   hasTableCell: boolean,
 * ) => void;
 * ```
 *
 * A HasTableCellListener is provided when using the addHasTableCellListener
 * method. See that method for specific examples.
 *
 * When called, a HasTableCellListener is given a reference to the Store, the Id
 * of the Table that changed, and the Id of the Cell that changed. It is also
 * given a flag to indicate whether the Cell now exists anywhere in the Table
 * (having not done previously), or does not (having done so previously).
 * @param store A reference to the Store that changed.
 * @param tableId The Id of the Table that changed.
 * @param cellId The Id of the Table Cell that changed.
 * @param hasTableCell Whether the Cell now exists anywhere in the Table or not.
 * @category Listener
 * @since v4.4.0
 */
export type HasTableCellListener<
  Schemas extends OptionalSchemas,
  TableIdOrNull extends TableIdFromSchema<Schemas[0]> | null,
  CellIdOrNull extends
    | (TableIdOrNull extends TableIdFromSchema<Schemas[0]>
        ? CellIdFromSchema<Schemas[0], TableIdOrNull>
        : AllCellIdFromSchema<Schemas[0]>)
    | null,
  Store extends StoreAlias<Schemas> = StoreAlias<Schemas>,
  Params extends any[] = (
    TableIdOrNull extends null ? TableIdFromSchema<Schemas[0]> : TableIdOrNull
  ) extends infer TableId
    ? TableId extends TableIdFromSchema<Schemas[0]>
      ? (
          CellIdOrNull extends null
            ? CellIdFromSchema<Schemas[0], TableId>
            : CellIdOrNull
        ) extends infer CellId
        ? CellId extends CellIdFromSchema<Schemas[0], TableId>
          ? [
              store: Store,
              tableId: TableId,
              cellId: CellId,
              hasTableCell: boolean,
            ]
          : never
        : never
      : never
    : never,
  Params4 extends any[] =
    | Params
    | [store: never, tableId: never, cellId: never, hasTableCell: never],
  Params3 extends any[] = Truncate<Params4>,
  //  Params2 extends any[] = Truncate<Params3>,
  // Params1 extends any[] = Truncate<Params2>,
> = Params extends any
  ? ((...params: Params4) => void) | ((...params: Params3) => void)
  : // | ((...params: Params2) => void)
    // | ((...params: Params1) => void)
    never;
/**
 * The RowCountListener type describes a function that is used to listen to
 * changes to the number of Row objects in a Table.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * export type RowCountListener<Store extends StoreAlias = StoreAlias> = (
 *   store: Store,
 *   tableId: Id,
 *   count: number,
 * ) => void;
 * ```
 *
 * A RowCountListener is provided when using the addRowCountListener method. See
 * that method for specific examples.
 *
 * When called, a RowCountListener is given a reference to the Store, the Id of
 * the Table whose Row Ids changed, and the number of Row objects in the Table.
 * @param store A reference to the Store that changed.
 * @param tableId The Id of the Table that changed.
 * @param count The number of Row objects in the Table.
 * @category Listener
 * @since v4.1.0
 */
export type RowCountListener<
  Schemas extends OptionalSchemas,
  TableIdOrNull extends TableIdFromSchema<Schemas[0]> | null,
  Store extends StoreAlias<Schemas> = StoreAlias<Schemas>,
> = (
  store: Store,
  tableId: TableIdOrNull extends null
    ? TableIdFromSchema<Schemas[0]>
    : TableIdOrNull,
  count: number,
) => void;
/**
 * The RowIdsListener type describes a function that is used to listen to
 * changes to the Row Ids in a Table.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * export type RowIdsListener<Store extends StoreAlias = StoreAlias> = (
 *   store: Store,
 *   tableId: Id,
 *   getIdChanges: GetIdChanges | undefined,
 * ) => void;
 * ```
 *
 * A RowIdsListener is provided when using the addRowIdsListener method. See
 * that method for specific examples.
 *
 * When called, a RowIdsListener is given a reference to the Store, and the Id
 * of the Table whose Row Ids changed.
 *
 * Since v3.3, the listener is also passed a GetIdChanges function that can be
 * used to query which Ids changed during the transaction.
 * @param store A reference to the Store that changed.
 * @param tableId The Id of the Table that changed.
 * @param getIdChanges A function that returns information about the Id changes,
 * since v3.3.
 * @category Listener
 * @since v1.0.0
 */
export type RowIdsListener<
  Schemas extends OptionalSchemas,
  TableIdOrNull extends TableIdFromSchema<Schemas[0]> | null,
  Store extends StoreAlias<Schemas> = StoreAlias<Schemas>,
> = (
  store: Store,
  tableId: TableIdOrNull extends null
    ? TableIdFromSchema<Schemas[0]>
    : TableIdOrNull,
  getIdChanges: GetIdChanges<Id> | undefined,
) => void;
/**
 * The SortedRowIdsListener type describes a function that is used to listen to
 * changes to sorted Row Ids in a Table.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * export type SortedRowIdsListener<Store extends StoreAlias = StoreAlias> = (
 *   store: Store,
 *   tableId: Id,
 *   cellId: Id | undefined,
 *   descending: boolean,
 *   offset: number,
 *   limit: number | undefined,
 *   sortedRowIds: Ids,
 * ) => void;
 * ```
 *
 * A SortedRowIdsListener is provided when using the addSortedRowIdsListener
 * method. See that method for specific examples.
 *
 * When called, a SortedRowIdsListener is given a reference to the Store, the Id
 * of the Table whose Row Ids sorting changed, the Cell Id being used to sort
 * them, whether descending or not, and the offset and limit of the number of
 * Ids returned, for pagination purposes. It also receives the sorted array of
 * Ids itself, so that you can use them in the listener without the additional
 * cost of an explicit call to getSortedRowIds.
 * @param store A reference to the Store that changed.
 * @param tableId The Id of the Table whose sorted Row Ids changed.
 * @param cellId The Id of the Cell whose values were used for the sorting.
 * @param descending Whether the sorting was in descending order.
 * @param offset The number of Row Ids skipped.
 * @param limit The maximum number of Row Ids returned.
 * @param sortedRowIds The sorted Row Ids themselves.
 * @category Listener
 * @since v2.0.0
 */
export type SortedRowIdsListener<
  Schemas extends OptionalSchemas,
  TableId extends TableIdFromSchema<Schemas[0]>,
  CellIdOrUndefined extends CellIdFromSchema<Schemas[0], TableId> | undefined,
  Store extends StoreAlias<Schemas> = StoreAlias<Schemas>,
> = (
  store: Store,
  tableId: TableId,
  cellId: CellIdOrUndefined,
  descending: boolean,
  offset: number,
  limit: number | undefined,
  sortedRowIds: Ids,
) => void;
/**
 * The HasRowListener type describes a function that is used to listen to a Row
 * being added to or removed from the Store.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * export type HasRowListener<Store extends StoreAlias = StoreAlias> = (
 *   store: Store,
 *   tableId: Id,
 *   rowId: Id,
 *   hasRow: boolean,
 * ) => void;
 * ```
 *
 * A HasRowListener is provided when using the addHasRowListener method. See
 * that method for specific examples.
 *
 * When called, a HasRowListener is given a reference to the Store, the Id of
 * the Table that changed, and the Id of the Row that changed. It is also given
 * a flag to indicate whether the Row now exists (having not done previously),
 * or does not (having done so previously).
 * @param store A reference to the Store that changed.
 * @param tableId The Id of the Table that changed.
 * @param rowId The Id of the Row that changed.
 * @param hasRow Whether the Row now exists or not.
 * @category Listener
 * @since v4.4.0
 */
export type HasRowListener<
  Schemas extends OptionalSchemas,
  TableIdOrNull extends TableIdFromSchema<Schemas[0]> | null,
  RowIdOrNull extends IdOrNull,
  Store extends StoreAlias<Schemas> = StoreAlias<Schemas>,
> = (
  store: Store,
  tableId: TableIdOrNull extends null
    ? TableIdFromSchema<Schemas[0]>
    : TableIdOrNull,
  rowId: RowIdOrNull extends null ? Id : RowIdOrNull,
  hasRow: boolean,
) => void;
/**
 * The RowListener type describes a function that is used to listen to changes
 * to a Row.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * export type RowListener<Store extends StoreAlias = StoreAlias> = (
 *   store: Store,
 *   tableId: Id,
 *   rowId: Id,
 *   getCellChange: GetCellChange | undefined,
 * ) => void;
 * ```
 *
 * A RowListener is provided when using the addRowListener method. See that
 * method for specific examples.
 *
 * When called, a RowListener is given a reference to the Store, the Id of the
 * Table that changed, the Id of the Row that changed, and a GetCellChange
 * function that can be used to query Cell values before and after the current
 * transaction.
 *
 * Note that if the listener was manually forced to be called (with the
 * callListener method rather than due to a real change in the Store), the
 * GetCellChange function will not be present.
 * @param store A reference to the Store that changed.
 * @param tableId The Id of the Table that changed.
 * @param rowId The Id of the Row that changed.
 * @param getCellChange A function that returns information about any Cell's
 * changes.
 * @category Listener
 * @since v1.0.0
 */
export type RowListener<
  Schemas extends OptionalSchemas,
  TableIdOrNull extends TableIdFromSchema<Schemas[0]> | null,
  RowIdOrNull extends IdOrNull,
  Store extends StoreAlias<Schemas> = StoreAlias<Schemas>,
> = (
  store: Store,
  tableId: TableIdOrNull extends null
    ? TableIdFromSchema<Schemas[0]>
    : TableIdOrNull,
  rowId: RowIdOrNull extends null ? Id : RowIdOrNull,
  getCellChange: GetCellChange<Schemas[0]> | undefined,
) => void;
/**
 * The CellIdsListener type describes a function that is used to listen to
 * changes to the Cell Ids in a Row.
 *
 * This has schema-based typing. The following is a simplified representation:
 *
 * ```ts override
 * export type CellIdsListener<Store extends StoreAlias = StoreAlias> = (
 *   store: Store,
 *   tableId: Id,
 *   rowId: Id,
 *   getIdChanges: GetIdChanges | undefined,
 * ) => void;
 * ```
 *
 * A CellIdsListener is provided when using the addCellIdsListener method. See
 * that method for specific examples.
 *
 * When called, a CellIdsListener is given a reference to the Store, the Id of
 * the Table that changed, and the Id of the Row whose Cell Ids changed.
 *
 * Since v3.3, the listener is also passed a GetIdChanges function that can be
 * used to query which Ids changed during the transaction.
 * @param store A reference to the Store that changed.
 * @param tableId The Id of the Table that changed.
 * @param rowId The Id of the Row that changed.
 * @param getIdChanges A function that returns information about the Id changes,
 * since v3.3.
 * @category Listener
 * @since v1.0.0
 */
export type CellIdsListener<
  Schemas extends OptionalSchemas,
  TableIdOrNull extends TableIdFromSchema<Schemas[0]> | null,
  RowIdOrNull extends IdOrNull,
  Store extends StoreAlias<Schemas> = StoreAlias<Schemas>,
  Params extends any[] = (
    TableIdOrNull extends null ? TableIdFromSchema<Schemas[0]> : TableIdOrNull
  ) extends infer TableId
    ? TableId extends TableIdFromSchema<Schemas[0]>
      ? [
          store: Store,
          tableId: TableId,
          rowId: RowIdOrNull extends null ? Id : RowI