Skip to content

Commit 3d537db

Browse files
committed
[store] addSortedRowIdsListener object arg
1 parent 0e6d998 commit 3d537db

File tree

5 files changed

+161
-48
lines changed

5 files changed

+161
-48
lines changed

src/@types/store/docs.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5403,6 +5403,51 @@
54035403
* @since v2.0.0
54045404
*/
54055405
/// Store.addSortedRowIdsListener
5406+
/**
5407+
* When called with an object as the first argument, the
5408+
* addSortedRowIdsListener method destructures it to make it easier to skip
5409+
* optional parameters.
5410+
* @param args A SortedRowIdsArgs object containing the Id of the Table in the
5411+
* Store, and optional `cellId`, `descending`, `offset`, and `limit`
5412+
* parameters.
5413+
* @param listener The function that will be called whenever the sorted Row
5414+
* Ids in the Table change.
5415+
* @param mutator An optional boolean that indicates that the listener mutates
5416+
* Store data.
5417+
* @returns A unique Id for the listener that can later be used to call it
5418+
* explicitly, or to remove it.
5419+
* @example
5420+
* This example registers a listener that responds to any change to the first
5421+
* of the sorted Row Ids of a specific Table.
5422+
*
5423+
* ```js
5424+
* import {createStore} from 'tinybase';
5425+
*
5426+
* const store = createStore().setTables({
5427+
* pets: {fido: {price: 6}, felix: {price: 5}},
5428+
* });
5429+
*
5430+
* const listenerId = store.addSortedRowIdsListener(
5431+
* {tableId: 'pets', limit: 1},
5432+
* (store, tableId, cellId, descending, offset, limit, sortedRowIds) => {
5433+
* console.log(`First sorted Row Id for ${tableId} table changed`);
5434+
* console.log(sortedRowIds);
5435+
* // ^ cheaper than calling getSortedRowIds again
5436+
* },
5437+
* );
5438+
* console.log(store.getSortedRowIds({tableId: 'pets', limit: 1}));
5439+
* // -> ['felix']
5440+
*
5441+
* store.setRow('pets', 'carnaby', {price: 4.5});
5442+
* // -> 'First sorted Row Id for pets table changed'
5443+
* // -> ['carnaby']
5444+
*
5445+
* store.delListener(listenerId);
5446+
* ```
5447+
* @category Listener
5448+
* @since v6.1.0
5449+
*/
5450+
/// Store.addSortedRowIdsListener.2
54065451
/**
54075452
* The addHasRowListener method registers a listener function with the Store
54085453
* that will be called when a Row is added to or removed from the Store.

src/@types/store/index.d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,13 @@ export interface Store {
698698
mutator?: boolean,
699699
): Id;
700700

701+
/// Store.addSortedRowIdsListener.2
702+
addSortedRowIdsListener(
703+
args: SortedRowIdsArgs,
704+
listener: SortedRowIdsListener<this>,
705+
mutator?: boolean,
706+
): Id;
707+
701708
/// Store.addHasRowListener
702709
addHasRowListener(
703710
tableId: IdOrNull,

src/@types/store/with-schemas/index.d.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,6 +1321,27 @@ export interface Store<in out Schemas extends OptionalSchemas> {
13211321
mutator?: boolean,
13221322
): Id;
13231323

1324+
/// Store.addSortedRowIdsListener.2
1325+
addSortedRowIdsListener<
1326+
TableId extends TableIdFromSchema<Schemas[0]>,
1327+
CellIdOrUndefined extends CellIdFromSchema<Schemas[0], TableId> | undefined,
1328+
Descending extends boolean,
1329+
Offset extends number,
1330+
Limit extends number | undefined,
1331+
>(
1332+
args: SortedRowIdsArgs<Schemas[0], TableId>,
1333+
listener: SortedRowIdsListener<
1334+
Schemas,
1335+
TableId,
1336+
CellIdOrUndefined,
1337+
Descending,
1338+
Offset,
1339+
Limit,
1340+
this
1341+
>,
1342+
mutator?: boolean,
1343+
): Id;
1344+
13241345
/// Store.addHasRowListener
13251346
addHasRowListener<
13261347
TableIdOrNull extends TableIdFromSchema<Schemas[0]> | null,

src/store/index.ts

Lines changed: 55 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -992,6 +992,28 @@ export const createStore: typeof createStoreDecl = (): Store => {
992992
return store;
993993
};
994994

995+
const addSortedRowIdsListenerImpl = (
996+
tableId: Id,
997+
cellId: Id | undefined,
998+
otherArgs: [descending: boolean, offset: number, limit: number | undefined],
999+
listener: SortedRowIdsListener,
1000+
mutator?: boolean,
1001+
): Id => {
1002+
let sortedRowIds = getSortedRowIds(tableId, cellId, ...otherArgs);
1003+
return addListener(
1004+
() => {
1005+
const newSortedRowIds = getSortedRowIds(tableId, cellId, ...otherArgs);
1006+
if (!arrayIsEqual(newSortedRowIds, sortedRowIds)) {
1007+
sortedRowIds = newSortedRowIds;
1008+
listener(store, tableId, cellId, ...otherArgs, sortedRowIds);
1009+
}
1010+
},
1011+
sortedRowIdsListeners[mutator ? 1 : 0],
1012+
[tableId, cellId],
1013+
[getTableIds],
1014+
);
1015+
};
1016+
9951017
// --
9961018

9971019
const getContent = (): Content => [getTables(), getValues()];
@@ -1013,25 +1035,25 @@ export const createStore: typeof createStoreDecl = (): Store => {
10131035
mapKeys(mapGet(tablesMap, id(tableId)));
10141036

10151037
const getSortedRowIds = (
1016-
tableId: Id | SortedRowIdsArgs,
1038+
tableIdOrArgs: Id | SortedRowIdsArgs,
10171039
cellId?: Id,
10181040
descending?: boolean,
10191041
offset = 0,
10201042
limit?: number,
10211043
): Ids =>
1022-
isObject(tableId)
1044+
isObject(tableIdOrArgs)
10231045
? getSortedRowIds(
1024-
tableId.tableId,
1025-
tableId.cellId,
1026-
tableId.descending,
1027-
tableId.offset,
1028-
tableId.limit,
1046+
tableIdOrArgs.tableId,
1047+
tableIdOrArgs.cellId,
1048+
tableIdOrArgs.descending,
1049+
tableIdOrArgs.offset,
1050+
tableIdOrArgs.limit,
10291051
)
10301052
: arrayMap(
10311053
slice(
10321054
arraySort(
10331055
mapMap<Id, RowMap, [Cell, Id]>(
1034-
mapGet(tablesMap, id(tableId)),
1056+
mapGet(tablesMap, id(tableIdOrArgs)),
10351057
(row, rowId) => [
10361058
isUndefined(cellId)
10371059
? rowId
@@ -1520,48 +1542,33 @@ export const createStore: typeof createStoreDecl = (): Store => {
15201542
mapForEach(valuesMap, valueCallback);
15211543

15221544
const addSortedRowIdsListener = (
1523-
tableId: Id,
1524-
cellId: Id | undefined,
1525-
descending: boolean,
1526-
offset: number,
1527-
limit: number | undefined,
1528-
listener: SortedRowIdsListener,
1545+
tableIdOrArgs: Id | SortedRowIdsArgs,
1546+
cellIdOrListener: Id | undefined | SortedRowIdsListener,
1547+
descendingOrMutator?: boolean,
1548+
offset?: number,
1549+
limit?: number | undefined,
1550+
listener?: SortedRowIdsListener,
15291551
mutator?: boolean,
1530-
): Id => {
1531-
let sortedRowIds = getSortedRowIds(
1532-
tableId,
1533-
cellId,
1534-
descending,
1535-
offset,
1536-
limit,
1537-
);
1538-
return addListener(
1539-
() => {
1540-
const newSortedRowIds = getSortedRowIds(
1541-
tableId,
1542-
cellId,
1543-
descending,
1544-
offset,
1545-
limit,
1552+
): Id =>
1553+
isObject(tableIdOrArgs)
1554+
? addSortedRowIdsListenerImpl(
1555+
tableIdOrArgs.tableId,
1556+
tableIdOrArgs.cellId,
1557+
[
1558+
tableIdOrArgs.descending ?? false,
1559+
tableIdOrArgs.offset ?? 0,
1560+
tableIdOrArgs.limit,
1561+
],
1562+
cellIdOrListener as SortedRowIdsListener,
1563+
descendingOrMutator,
1564+
)
1565+
: addSortedRowIdsListenerImpl(
1566+
tableIdOrArgs,
1567+
cellIdOrListener as Id | undefined,
1568+
[descendingOrMutator as boolean, offset as number, limit],
1569+
listener as SortedRowIdsListener,
1570+
mutator,
15461571
);
1547-
if (!arrayIsEqual(newSortedRowIds, sortedRowIds)) {
1548-
sortedRowIds = newSortedRowIds;
1549-
listener(
1550-
store,
1551-
tableId,
1552-
cellId,
1553-
descending,
1554-
offset,
1555-
limit,
1556-
sortedRowIds,
1557-
);
1558-
}
1559-
},
1560-
sortedRowIdsListeners[mutator ? 1 : 0],
1561-
[tableId, cellId],
1562-
[getTableIds],
1563-
);
1564-
};
15651572

15661573
const addStartTransactionListener = (listener: TransactionListener): Id =>
15671574
addListener(listener, startTransactionListeners);

test/unit/core/store/store-advanced.test.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,39 @@ describe.each([
356356
store.setRow('t1', 'r7', {c1: 7, c2: 'seven'});
357357
});
358358

359+
test('Cell sort listener, add row with relevant cell, object arg', () => {
360+
expect.assertions(7);
361+
store.addSortedRowIdsListener(
362+
{tableId: 't1', cellId: 'c2', limit: 8},
363+
(_store, tableId, cellId, descending, offset, limit, sortedRowIds) => {
364+
expect(tableId).toEqual('t1');
365+
expect(cellId).toEqual('c2');
366+
expect(descending).toEqual(false);
367+
expect(offset).toEqual(0);
368+
expect(limit).toEqual(8);
369+
expect(sortedRowIds).toEqual([
370+
'r5',
371+
'r4',
372+
'r1',
373+
'r7',
374+
'r6',
375+
'r3',
376+
'r2',
377+
]);
378+
expect(store.getSortedRowIds('t1', 'c2')).toEqual([
379+
'r5',
380+
'r4',
381+
'r1',
382+
'r7',
383+
'r6',
384+
'r3',
385+
'r2',
386+
]);
387+
},
388+
);
389+
store.setRow('t1', 'r7', {c1: 7, c2: 'seven'});
390+
});
391+
359392
test('Cell sort listener, add row without relevant cell', () => {
360393
expect.assertions(1);
361394
store.addSortedRowIdsListener(

0 commit comments

Comments
 (0)