Skip to content

Commit

Permalink
enhance: state.results -> state.endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
ntucker committed Mar 7, 2024
1 parent 51427ac commit 443ec62
Show file tree
Hide file tree
Showing 31 changed files with 166 additions and 109 deletions.
5 changes: 5 additions & 0 deletions .changeset/nasty-items-count.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@data-client/normalizr": minor
---

type ResultCache -> EndpointCache
6 changes: 6 additions & 0 deletions .changeset/violet-numbers-pump.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@data-client/react": minor
"@data-client/core": minor
---

BREAKING: Internal state.results -> state.endpoints
2 changes: 1 addition & 1 deletion examples/benchmark/old-normalizr/normalizr.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ function mergeWithStore({ entities, result }, storeState) {
return {
...storeState,
entities: newEntities,
results: { ...storeState.results, ...{ abc: result } },
endpoints: { ...storeState.endpoints, ...{ abc: result } },
};
}

Expand Down
2 changes: 1 addition & 1 deletion packages/core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ function useSuspense(endpoint, ...args)
const controller = useController();

const key = args[0] !== null ? endpoint.key(...args) : '';
const cacheResults = key && state.results[key];
const cacheResults = key && state.endpoints[key];
const meta = state.meta[key];

// Compute denormalized value
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ export interface ResetAction {
export interface GCAction {
type: typeof GC_TYPE;
entities: [string, string][];
results: string[];
endpoints: string[];
}

export type ActionTypes =
Expand Down
20 changes: 10 additions & 10 deletions packages/core/src/controller/Controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export default class Controller<
getState = unsetState,
globalCache = {
entities: {},
results: {},
endpoints: {},
},
}: ConstructorProps<D> = {}) {
this.dispatch = dispatch;
Expand Down Expand Up @@ -327,9 +327,9 @@ export default class Controller<
const key = endpoint.key(...args);

const meta = selectMeta(state, key);
const results = state.results[key];
const error = state.endpoints[key];

if (results !== undefined && meta?.errorPolicy === 'soft') return;
if (error !== undefined && meta?.errorPolicy === 'soft') return;

return meta?.error as any;
};
Expand Down Expand Up @@ -386,14 +386,14 @@ export default class Controller<
.map(ensurePojo);
const isActive = args.length !== 1 || args[0] !== null;
const key = isActive ? endpoint.key(...args) : '';
const cacheResults = isActive ? state.results[key] : undefined;
const cacheEndpoints = isActive ? state.endpoints[key] : undefined;
const schema = endpoint.schema;
const meta = selectMeta(state, key);
let expiresAt = meta?.expiresAt;

let invalidResults = false;
let results;
if (cacheResults === undefined && endpoint.schema !== undefined) {
if (cacheEndpoints === undefined && endpoint.schema !== undefined) {
results = inferResults(
endpoint.schema,
args,
Expand All @@ -403,7 +403,7 @@ export default class Controller<
invalidResults = !validateInference(results);
if (!expiresAt && invalidResults) expiresAt = 1;
} else {
results = cacheResults;
results = cacheEndpoints;
}

if (!isActive) {
Expand All @@ -419,22 +419,22 @@ export default class Controller<
data: results,
expiryStatus:
meta?.invalidated ? ExpiryStatus.Invalid
: cacheResults && !endpoint.invalidIfStale ? ExpiryStatus.Valid
: cacheEndpoints && !endpoint.invalidIfStale ? ExpiryStatus.Valid
: ExpiryStatus.InvalidIfStale,
expiresAt: expiresAt || 0,
};
}

if (!this.globalCache.results[key])
this.globalCache.results[key] = new WeakEntityMap();
if (!this.globalCache.endpoints[key])
this.globalCache.endpoints[key] = new WeakEntityMap();

return this.getSchemaResponse(
results,
schema as Exclude<Schema, undefined>,
args,
state,
expiresAt,
this.globalCache.results[key],
this.globalCache.endpoints[key],
endpoint.invalidIfStale || invalidResults,
meta,
);
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/controller/__tests__/Controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ describe('Controller', () => {
const state = {
...initialState,
entities,
results: {
endpoints: {
[fetchKey]: result,
},
entityMeta: createEntityMeta(entities),
Expand Down Expand Up @@ -80,7 +80,7 @@ describe('Controller', () => {
const state = {
...initialState,
entities,
results: {
endpoints: {
[fetchKey]: result,
},
entityMeta: createEntityMeta(entities),
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/controller/__tests__/getResponse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ describe('Controller.getResponse()', () => {
const state = {
...initialState,
entities,
results: {
endpoints: {
[ep.key()]: {
data: ['1', '2'],
},
Expand Down Expand Up @@ -84,7 +84,7 @@ describe('Controller.getResponse()', () => {
const state = {
...initialState,
entities,
results: {
endpoints: {
[ep.key()]: {
data: ['1', '2'],
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

exports[`reducer should set error in meta for "set" 1`] = `
{
"endpoints": {},
"entities": {},
"entityMeta": {},
"indexes": {},
Expand All @@ -15,12 +16,14 @@ exports[`reducer should set error in meta for "set" 1`] = `
},
},
"optimistic": [],
"results": {},
}
`;

exports[`reducer singles should update state correctly 1`] = `
{
"endpoints": {
"http://test.com/article/20": "20",
},
"entities": {
"Article": {
"20": {
Expand Down Expand Up @@ -49,8 +52,5 @@ exports[`reducer singles should update state correctly 1`] = `
},
},
"optimistic": [],
"results": {
"http://test.com/article/20": "20",
},
}
`;
50 changes: 25 additions & 25 deletions packages/core/src/state/__tests__/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ describe('reducer', () => {
});
});

it('mutate should never change results', () => {
it('mutate should never change endpoints', () => {
const id = 20;
const payload = { id, title: 'hi', content: 'this is the content' };
const action: SetAction = {
Expand All @@ -224,10 +224,10 @@ describe('reducer', () => {
};
const iniState = {
...initialState,
results: { abc: '5', [ArticleResource.get.key(payload)]: `${id}` },
endpoints: { abc: '5', [ArticleResource.get.key(payload)]: `${id}` },
};
const newState = reducer(iniState, action);
expect(newState.results).toStrictEqual(iniState.results);
expect(newState.endpoints).toStrictEqual(iniState.endpoints);
});
it('purge should delete entities', () => {
const id = 20;
Expand Down Expand Up @@ -256,10 +256,10 @@ describe('reducer', () => {
},
'5': undefined,
},
results: { abc: '20' },
endpoints: { abc: '20' },
};
const newState = reducer(iniState, action);
expect(newState.results.abc).toBe(iniState.results.abc);
expect(newState.endpoints.abc).toBe(iniState.endpoints.abc);
const expectedEntities = { ...iniState.entities[Article.key] };
expectedEntities['20'] = INVALID;
expect(newState.entities[Article.key]).toEqual(expectedEntities);
Expand All @@ -277,8 +277,8 @@ describe('reducer', () => {
'10': PaginatedArticle.fromJS({ id: 10 }),
},
},
results: {
[PaginatedArticleResource.getList.key({})]: { results: ['10'] },
endpoints: {
[PaginatedArticleResource.getList.key({})]: { endpoints: ['10'] },
},
};
Expand All @@ -301,7 +301,7 @@ describe('reducer', () => {
);
const newState = reducer(iniState, action);
expect(
newState.results[PaginatedArticleResource.getList.key({})],
newState.endpoints[PaginatedArticleResource.getList.key({})],
).toStrictEqual({
results: ['10', '11', '12'],
});
Expand All @@ -328,7 +328,7 @@ describe('reducer', () => {
),
);
expect(
newState.results[PaginatedArticleResource.getList.key({})],
newState.endpoints[PaginatedArticleResource.getList.key({})],
).toStrictEqual({
results: ['11', '12', '10'],
});
Expand All @@ -342,7 +342,7 @@ describe('reducer', () => {
'10': PaginatedArticle.fromJS({ id: 10 }),
},
},
results: {
endpoints: {
[PaginatedArticleResource.getList.key({ admin: true })]: {
results: ['10'],
},
Expand All @@ -369,7 +369,7 @@ describe('reducer', () => {
),
);
expect(
newState.results[
newState.endpoints[
PaginatedArticleResource.getList.key({ admin: true })
],
).toStrictEqual({
Expand Down Expand Up @@ -400,7 +400,7 @@ describe('reducer', () => {
},
'5': undefined,
},
results: { abc: '20' },
endpoints: { abc: '20' },
meta: {
'20': {
expiresAt: 500,
Expand All @@ -411,7 +411,7 @@ describe('reducer', () => {
},
};
const newState = reducer(iniState, action);
expect(newState.results).toEqual(iniState.results);
expect(newState.endpoints).toEqual(iniState.endpoints);
expect(newState.entities).toBe(iniState.entities);
const expectedMeta = { ...iniState.meta };
expectedMeta['20'] = { expiresAt: 0, invalidated: true };
Expand Down Expand Up @@ -481,7 +481,7 @@ describe('reducer', () => {
[id]: Article.fromJS({}),
},
},
results: {
endpoints: {
[ArticleResource.get.url({ id })]: id,
},
};
Expand Down Expand Up @@ -509,7 +509,7 @@ describe('reducer', () => {
};
const iniState = {
...initialState,
results: { abc: '5' },
endpoints: { abc: '5' },
};
const newState = reducer(iniState, action);
expect(newState).toBe(iniState);
Expand All @@ -524,7 +524,7 @@ describe('reducer', () => {
};
const iniState = {
...initialState,
results: { abc: '5' },
endpoints: { abc: '5' },
};
const newState = reducer(iniState, action);
expect(newState).toBe(iniState);
Expand Down Expand Up @@ -556,10 +556,10 @@ describe('reducer', () => {
},
'5': undefined,
},
results: { abc: '20' },
endpoints: { abc: '20' },
};
const newState = reducer(iniState, action);
expect(newState.results).toEqual({});
expect(newState.endpoints).toEqual({});
expect(newState.meta).toEqual({});
expect(newState.entities).toEqual({});
});
Expand Down Expand Up @@ -591,21 +591,21 @@ describe('reducer', () => {
'250': { date: 0, expiresAt: 10000, fetchedAt: 0 },
},
},
results: { abc: '20' },
endpoints: { abc: '20' },
};
});

it('empty targets should do nothing', () => {
const action: GCAction = {
type: GC_TYPE,
entities: [],
results: [],
endpoints: [],
};

const newState = reducer(iniState, action);
expect(newState).toBe(iniState);
expect(Object.keys(newState.entities[Article.key] ?? {}).length).toBe(4);
expect(Object.keys(newState.results).length).toBe(1);
expect(Object.keys(newState.endpoints).length).toBe(1);
});

it('empty deleting entities should work', () => {
Expand All @@ -615,7 +615,7 @@ describe('reducer', () => {
[Article.key, '10'],
[Article.key, '250'],
],
results: ['abc'],
endpoints: ['abc'],
};

const newState = reducer(iniState, action);
Expand All @@ -624,7 +624,7 @@ describe('reducer', () => {
expect(Object.keys(newState.entityMeta[Article.key] ?? {}).length).toBe(
2,
);
expect(Object.keys(newState.results).length).toBe(0);
expect(Object.keys(newState.endpoints).length).toBe(0);
});

it('empty deleting nonexistant things should passthrough', () => {
Expand All @@ -634,13 +634,13 @@ describe('reducer', () => {
[Article.key, '100000000'],
['sillythings', '10'],
],
results: [],
endpoints: [],
};

const newState = reducer(iniState, action);
expect(newState).toBe(iniState);
expect(Object.keys(newState.entities[Article.key] ?? {}).length).toBe(4);
expect(Object.keys(newState.results).length).toBe(1);
expect(Object.keys(newState.endpoints).length).toBe(1);
});
});
});
Loading

1 comment on commit 443ec62

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmark

Benchmark suite Current: 443ec62 Previous: 51427ac Ratio
normalizeLong 423 ops/sec (±1.96%) 444 ops/sec (±2.03%) 1.05
infer All 8868 ops/sec (±2.13%) 9111 ops/sec (±2.10%) 1.03
denormalizeLong 226 ops/sec (±3.61%) 329 ops/sec (±1.13%) 1.46
denormalizeLong donotcache 812 ops/sec (±0.55%) 845 ops/sec (±1.29%) 1.04
denormalizeShort donotcache 500x 1329 ops/sec (±0.11%) 1378 ops/sec (±0.24%) 1.04
denormalizeShort 500x 693 ops/sec (±2.74%) 946 ops/sec (±0.93%) 1.37
denormalizeShort 500x withCache 4349 ops/sec (±0.43%) 4432 ops/sec (±0.28%) 1.02
denormalizeLong with mixin Entity 217 ops/sec (±2.19%) 296 ops/sec (±0.72%) 1.36
denormalizeLong withCache 7636 ops/sec (±0.23%) 7213 ops/sec (±0.26%) 0.94
denormalizeLongAndShort withEntityCacheOnly 1514 ops/sec (±0.42%) 1565 ops/sec (±0.40%) 1.03
denormalizeLong All withCache 6123 ops/sec (±0.24%) 6083 ops/sec (±0.18%) 0.99
denormalizeLong Query-sorted withCache 6558 ops/sec (±0.36%) 6441 ops/sec (±0.21%) 0.98
getResponse 5224 ops/sec (±1.29%) 4562 ops/sec (±0.46%) 0.87
getResponse (null) 3226161 ops/sec (±0.47%) 3102452 ops/sec (±0.27%) 0.96
getResponse Query-sorted 899 ops/sec (±0.67%) 985 ops/sec (±0.34%) 1.10
getResponse Collection 5113 ops/sec (±1.50%) 5071 ops/sec (±0.49%) 0.99
setLong 423 ops/sec (±1.96%) 431 ops/sec (±2.06%) 1.02
setLongWithMerge 172 ops/sec (±0.82%) 184 ops/sec (±1.02%) 1.07
setLongWithSimpleMerge 186 ops/sec (±0.46%) 195 ops/sec (±0.32%) 1.05

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.