Skip to content

Commit 44ed77a

Browse files
committed
enhance: Switch denormalize paths back to object
1 parent eefef66 commit 44ed77a

File tree

16 files changed

+62
-52
lines changed

16 files changed

+62
-52
lines changed

packages/core/src/controller/Controller.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -650,7 +650,7 @@ function entityExpiresAt(
650650
},
651651
) {
652652
let expiresAt = Infinity;
653-
for (const [key, pk] of paths) {
653+
for (const { key, pk } of paths) {
654654
const entityExpiry = entitiesMeta[key]?.[pk]?.expiresAt;
655655
// expiresAt will always resolve to false with any comparison
656656
if (entityExpiry < expiresAt) expiresAt = entityExpiry;

packages/core/src/state/GCPolicy.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export class GCPolicy implements GCInterface {
4646
if (key)
4747
this.endpointCount.set(key, (this.endpointCount.get(key) ?? 0) + 1);
4848
paths.forEach(path => {
49-
const [key, pk] = path;
49+
const { key, pk } = path;
5050
if (!this.entityCount.has(key)) {
5151
this.entityCount.set(key, new Map<string, number>());
5252
}
@@ -69,7 +69,7 @@ export class GCPolicy implements GCInterface {
6969
}
7070
}
7171
paths.forEach(path => {
72-
const [key, pk] = path;
72+
const { key, pk } = path;
7373
if (!this.entityCount.has(key)) {
7474
return;
7575
}
@@ -133,9 +133,9 @@ export class GCPolicy implements GCInterface {
133133
const nextEntitiesQ: EntityPath[] = [];
134134
for (const path of this.entitiesQ) {
135135
if (
136-
!this.entityCount.get(path[0])?.has(path[1]) &&
136+
!this.entityCount.get(path.key)?.has(path.pk) &&
137137
this.expiresAt(
138-
state.entitiesMeta[path[0]]?.[path[1]] ?? {
138+
state.entitiesMeta[path.key]?.[path.pk] ?? {
139139
fetchedAt: 0,
140140
date: 0,
141141
expiresAt: 0,

packages/core/src/state/__tests__/GCPolicy.test.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ describe('GCPolicy', () => {
2525

2626
it('should increment and decrement endpoint and entity counts', () => {
2727
const key = 'testEndpoint';
28-
const paths: EntityPath[] = [['testEntity', '1']];
28+
const paths: EntityPath[] = [{ key: 'testEntity', pk: '1' }];
2929
const countRef = gcPolicy.createCountRef({ key, paths });
3030

3131
const decrement = countRef();
@@ -39,7 +39,7 @@ describe('GCPolicy', () => {
3939

4040
it('should dispatch GC action once no ref counts and is expired', () => {
4141
const key = 'testEndpoint';
42-
const paths: EntityPath[] = [['testEntity', '1']];
42+
const paths: EntityPath[] = [{ key: 'testEntity', pk: '1' }];
4343
const state = {
4444
meta: {
4545
testEndpoint: {
@@ -74,14 +74,14 @@ describe('GCPolicy', () => {
7474
gcPolicy['runSweep']();
7575
expect(controller.dispatch).toHaveBeenCalledWith({
7676
type: GC,
77-
entities: [['testEntity', '1']],
77+
entities: [{ key: 'testEntity', pk: '1' }],
7878
endpoints: ['testEndpoint'],
7979
});
8080
});
8181

8282
it('should dispatch GC action once no ref counts and is expired with extra decrements', () => {
8383
const key = 'testEndpoint';
84-
const paths: EntityPath[] = [['testEntity', '1']];
84+
const paths: EntityPath[] = [{ key: 'testEntity', pk: '1' }];
8585
const state = {
8686
meta: {
8787
testEndpoint: {
@@ -117,14 +117,14 @@ describe('GCPolicy', () => {
117117
gcPolicy['runSweep']();
118118
expect(controller.dispatch).toHaveBeenCalledWith({
119119
type: GC,
120-
entities: [['testEntity', '1']],
120+
entities: [{ key: 'testEntity', pk: '1' }],
121121
endpoints: ['testEndpoint'],
122122
});
123123
});
124124

125125
it('should dispatch GC action once no ref counts and no expiry state', () => {
126126
const key = 'testEndpoint';
127-
const paths: EntityPath[] = [['testEntity', '1']];
127+
const paths: EntityPath[] = [{ key: 'testEntity', pk: '1' }];
128128
const state = {
129129
meta: {},
130130
entitiesMeta: {},
@@ -145,15 +145,15 @@ describe('GCPolicy', () => {
145145
gcPolicy['runSweep']();
146146
expect(controller.dispatch).toHaveBeenCalledWith({
147147
type: GC,
148-
entities: [['testEntity', '1']],
148+
entities: [{ key: 'testEntity', pk: '1' }],
149149
endpoints: ['testEndpoint'],
150150
});
151151
});
152152

153153
it('should not dispatch GC action if expiresAt has not passed, but dispatch later when it has', () => {
154154
jest.useFakeTimers();
155155
const key = 'testEndpoint';
156-
const paths: EntityPath[] = [['testEntity', '1']];
156+
const paths: EntityPath[] = [{ key: 'testEntity', pk: '1' }];
157157
const futureTime = Date.now() + 1000;
158158
const state = {
159159
meta: {
@@ -211,7 +211,7 @@ describe('GCPolicy', () => {
211211

212212
expect(controller.dispatch).toHaveBeenCalledWith({
213213
type: GC,
214-
entities: [['testEntity', '1']],
214+
entities: [{ key: 'testEntity', pk: '1' }],
215215
endpoints: ['testEndpoint'],
216216
});
217217

@@ -223,7 +223,7 @@ describe('GCPolicy', () => {
223223
gcPolicy = new GCPolicy({ expiresAt: () => 0 });
224224
gcPolicy.init(controller);
225225
const key = 'testEndpoint';
226-
const paths: EntityPath[] = [['testEntity', '1']];
226+
const paths: EntityPath[] = [{ key: 'testEntity', pk: '1' }];
227227
const futureTime = Date.now() + 1000;
228228
const state = {
229229
meta: {

packages/core/src/state/__tests__/reducer.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -720,8 +720,8 @@ describe('reducer', () => {
720720
const action: GCAction = {
721721
type: GC,
722722
entities: [
723-
[Article.key, '10'],
724-
[Article.key, '250'],
723+
{ key: Article.key, pk: '10' },
724+
{ key: Article.key, pk: '250' },
725725
],
726726
endpoints: ['abc'],
727727
};
@@ -739,8 +739,8 @@ describe('reducer', () => {
739739
const action: GCAction = {
740740
type: GC,
741741
entities: [
742-
[Article.key, '100000000'],
743-
['sillythings', '10'],
742+
{ key: Article.key, pk: '100000000' },
743+
{ key: 'sillythings', pk: '10' },
744744
],
745745
endpoints: [],
746746
};

packages/core/src/state/reducer/createReducer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export default function createReducer(controller: Controller): ReducerType {
2626
switch (action.type) {
2727
case GC:
2828
// inline deletes are fine as these should have 0 refcounts
29-
action.entities.forEach(([key, pk]) => {
29+
action.entities.forEach(({ key, pk }) => {
3030
delete (state as any).entities[key]?.[pk];
3131
delete (state as any).entitiesMeta[key]?.[pk];
3232
});

packages/endpoint/src/interface.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,12 @@ export interface Visit {
113113
creating?: boolean;
114114
}
115115

116-
export type EntityPath = [key: string, pk: string];
116+
/** Used in denormalize. Lookup to find an entity in the store table */
117+
export interface EntityPath {
118+
key: string;
119+
pk: string;
120+
}
121+
117122
export type IndexPath = [key: string, index: string, value: string];
118123
export type EntitiesPath = [key: string];
119124

@@ -124,11 +129,11 @@ export interface CheckLoop {
124129

125130
/** Get all normalized entities of one type from store */
126131
export interface GetEntities {
127-
(...path: EntitiesPath): { readonly [pk: string]: any } | undefined;
132+
(key: string): { readonly [pk: string]: any } | undefined;
128133
}
129134
/** Get normalized Entity from store */
130135
export interface GetEntity {
131-
(...path: EntityPath): any;
136+
(key: string, pk: string): any;
132137
}
133138
/** Get PK using an Entity Index */
134139
export interface GetIndex {

packages/endpoint/src/schemas/__tests__/All.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
MemoCache,
66
denormalize,
77
INVALID,
8-
Delegate,
8+
PlainDelegate,
99
} from '@data-client/normalizr';
1010
import { DelegateImmutable } from '@data-client/normalizr/immutable';
1111
import { IDEntity } from '__tests__/new';
@@ -103,7 +103,7 @@ describe.each([[]])(`${schema.All.name} normalization (%s)`, () => {
103103
});
104104

105105
describe.each([
106-
['direct', <T>(data: T) => data, <T>(data: T) => data, Delegate],
106+
['direct', <T>(data: T) => data, <T>(data: T) => data, PlainDelegate],
107107
[
108108
'immutable',
109109
fromJSState,

packages/endpoint/src/schemas/__tests__/Query.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// eslint-env jest
2-
import { MemoCache, Delegate } from '@data-client/normalizr';
2+
import { MemoCache, PlainDelegate } from '@data-client/normalizr';
33
import { DelegateImmutable } from '@data-client/normalizr/immutable';
44
import { useQuery, useSuspense, __INTERNAL__ } from '@data-client/react';
55
import { RestEndpoint } from '@data-client/rest';
@@ -27,7 +27,7 @@ class User extends IDEntity {
2727
}
2828

2929
describe.each([
30-
['direct', <T>(data: T) => data, <T>(data: T) => data, Delegate],
30+
['direct', <T>(data: T) => data, <T>(data: T) => data, PlainDelegate],
3131
[
3232
'immutable',
3333
fromJSState,

packages/normalizr/src/__tests__/WeakDependencyMap.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ describe('WeakDependencyMap', () => {
2020
},
2121
};
2222
const getEntity = getEntities(state);
23-
const depA = { path: ['A', '1'] as EntityPath, entity: a };
24-
const depB = { path: ['B', '2'] as EntityPath, entity: b };
25-
const depC = { path: ['C', '3'] as EntityPath, entity: c };
23+
const depA = { path: { key: 'A', pk: '1' }, entity: a };
24+
const depB = { path: { key: 'B', pk: '2' }, entity: b };
25+
const depC = { path: { key: 'C', pk: '3' }, entity: c };
2626

2727
it('should construct', () => {
2828
const wem = new WeakDependencyMap<EntityPath>();

packages/normalizr/src/__tests__/__snapshots__/MemoCache.ts.snap

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ exports[`MemoCache query (direct) works with pk 1`] = `
1616
"username": "m",
1717
},
1818
"paths": [
19-
[
20-
"Cat",
21-
"1",
22-
],
19+
{
20+
"key": "Cat",
21+
"pk": "1",
22+
},
2323
],
2424
}
2525
`;
@@ -40,10 +40,10 @@ exports[`MemoCache query (immutable) works with pk 1`] = `
4040
"username": "m",
4141
},
4242
"paths": [
43-
[
44-
"Cat",
45-
"1",
46-
],
43+
{
44+
"key": "Cat",
45+
"pk": "1",
46+
},
4747
],
4848
}
4949
`;

packages/normalizr/src/denormalize/getEntities.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ export function getEntities<K extends object>(
88
const entityIsImmutable = isImmutable(state);
99

1010
if (entityIsImmutable) {
11-
return (path: EntityPath) => state.getIn(path);
11+
return ({ key, pk }: EntityPath) => state.getIn([key, pk]);
1212
} else {
13-
return ([key, pk]: EntityPath) => state[key]?.[pk];
13+
return ({ key, pk }: EntityPath) => state[key]?.[pk];
1414
}
1515
}
1616

packages/normalizr/src/denormalize/unvisit.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ const getUnvisitEntity = (
1818
entityOrId: Record<string, any> | string,
1919
): object | undefined | typeof INVALID {
2020
const inputIsId = typeof entityOrId !== 'object';
21-
const entity = inputIsId ? getEntity([schema.key, entityOrId]) : entityOrId;
21+
const entity =
22+
inputIsId ? getEntity({ key: schema.key, pk: entityOrId }) : entityOrId;
2223
if (typeof entity === 'symbol') {
2324
return schema.denormalize(entity, args, unvisit);
2425
}

packages/normalizr/src/interface.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,15 @@ export interface Visit {
9999
(schema: any, value: any, parent: any, key: any, args: readonly any[]): any;
100100
}
101101

102-
export type EntityPath = [key: string, pk: string];
102+
/** Used in denormalize. Lookup to find an entity in the store table */
103+
export interface EntityPath {
104+
key: string;
105+
pk: string;
106+
}
107+
103108
export type IndexPath = [key: string, index: string, value: string];
104109
export type EntitiesPath = [key: string];
105-
export type QueryPath = IndexPath | EntityPath | EntitiesPath;
110+
export type QueryPath = IndexPath | [key: string, pk: string] | EntitiesPath;
106111

107112
/** Returns true if a circular reference is found */
108113
export interface CheckLoop {
@@ -111,11 +116,11 @@ export interface CheckLoop {
111116

112117
/** Get all normalized entities of one type from store */
113118
export interface GetEntities {
114-
(...path: EntitiesPath): { readonly [pk: string]: any } | undefined;
119+
(key: string): { readonly [pk: string]: any } | undefined;
115120
}
116121
/** Get normalized Entity from store */
117122
export interface GetEntity {
118-
(...path: EntityPath): any;
123+
(key: string, pk: string): any;
119124
}
120125
/** Get PK using an Entity Index */
121126
export interface GetIndex {

packages/normalizr/src/memo/BaseDelegate.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import type { Dep } from './WeakDependencyMap.js';
22
import { INVALID } from '../denormalize/symbol.js';
33
import type {
4-
EntityPath,
54
QueryPath,
65
IndexPath,
76
EntitiesPath,
@@ -25,7 +24,7 @@ export abstract class BaseDelegate {
2524
}
2625

2726
abstract getEntities(...path: EntitiesPath): object | undefined;
28-
abstract getEntity(...path: EntityPath): object | undefined;
27+
abstract getEntity(key: string, pk: string): object | undefined;
2928
abstract getIndex(...path: IndexPath): object | undefined;
3029
abstract getIndexEnd(entity: any, value: string): string | undefined;
3130

@@ -42,7 +41,7 @@ export abstract class BaseDelegate {
4241
dependencies.push({ path, entity });
4342
return base.getIndexEnd(entity, path[2]);
4443
},
45-
getEntity(...path: EntityPath) {
44+
getEntity(...path: [key: string, pk: string]) {
4645
const entity = base.getEntity(...path);
4746
dependencies.push({ path, entity });
4847
return entity;

packages/normalizr/src/memo/Delegate.immutable.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export class DelegateImmutable extends BaseDelegate {
2222
return this.entities.get(key)?.toJS();
2323
}
2424

25-
getEntity(...path: EntityPath): any {
25+
getEntity(...path: [key: string, pk: string]): any {
2626
return this.entities.getIn(path);
2727
}
2828

packages/normalizr/src/memo/globalCache.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export default class GlobalCache implements Cache {
5858
else {
5959
const trackingIndex = this.dependencies.length;
6060
cycleCacheKey.set(pk, trackingIndex);
61-
this.dependencies.push({ path: [key, pk], entity });
61+
this.dependencies.push({ path: { key, pk }, entity });
6262

6363
/** NON-GLOBAL_CACHE CODE */
6464
computeValue(localCacheKey);
@@ -87,7 +87,7 @@ export default class GlobalCache implements Cache {
8787
this.cycleIndex = cycleCacheKey.get(pk)!;
8888
} else {
8989
// with no cycle, globalCacheEntry will have already been set
90-
this.dependencies.push({ path: [key, pk], entity });
90+
this.dependencies.push({ path: { key, pk }, entity });
9191
}
9292
}
9393
return localCacheKey.get(pk);
@@ -125,7 +125,7 @@ export default class GlobalCache implements Cache {
125125
// we want to do this before we add our 'input' entry
126126
paths = this.paths();
127127
// for the first entry, `path` is ignored so empty members is fine
128-
this.dependencies.unshift({ path: ['', ''], entity: input });
128+
this.dependencies.unshift({ path: { key: '', pk: '' }, entity: input });
129129
this.resultCache.set(this.dependencies, data);
130130
} else {
131131
paths.shift();

0 commit comments

Comments
 (0)