Skip to content

Commit c47bda2

Browse files
committed
enhance: MemoCache.query returns {data, paths} just like denormalize
1 parent 7d8eef9 commit c47bda2

File tree

11 files changed

+108
-83
lines changed

11 files changed

+108
-83
lines changed

.changeset/stale-socks-accept.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
'@data-client/normalizr': minor
3+
---
4+
5+
MemoCache.query returns `{ data, paths }` just like denormalize
6+
7+
#### Before
8+
9+
```ts
10+
const data = this.memo.query(schema, args, state);
11+
```
12+
13+
#### After
14+
15+
```ts
16+
const { data } = this.memo.query(schema, args, state);
17+
```

docs/rest/api/schema.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,7 @@ is an Array of paths of all entities included in the result.
222222
const data = memo.query(
223223
Article,
224224
args,
225-
normalizedData.entities,
226-
normalizedData.indexes,
225+
normalizedData,
227226
);
228227
```
229228

packages/core/src/controller/Controller.ts

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,8 @@ export default class Controller<
589589
.slice(0, rest.length - 1)
590590
.map(ensurePojo) as SchemaArgs<S>;
591591

592-
return this.memo.query(schema, args, state);
592+
const { data } = this.memo.query(schema, args, state);
593+
return typeof data === 'symbol' ? undefined : (data as any);
593594
}
594595

595596
/**
@@ -612,27 +613,10 @@ export default class Controller<
612613
.slice(0, rest.length - 1)
613614
.map(ensurePojo) as SchemaArgs<S>;
614615

615-
// TODO: breaking: Switch back to this.memo.query(schema, args, state.entities as any, state.indexes) to do
616-
// this logic
617-
const input = this.memo.buildQueryKey(
618-
schema,
619-
args,
620-
state,
621-
JSON.stringify(args),
622-
);
616+
const { data, paths } = this.memo.query(schema, args, state);
623617

624-
if (!input) {
625-
return { data: undefined, countRef: () => () => undefined };
626-
}
627-
628-
const { data, paths } = this.memo.denormalize(
629-
schema,
630-
input,
631-
state.entities,
632-
args,
633-
);
634618
return {
635-
data: typeof data === 'symbol' ? undefined : (data as any),
619+
data: typeof data === 'symbol' ? undefined : data,
636620
countRef: this.gcPolicy.createCountRef({ paths }),
637621
};
638622
}

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

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,9 @@ describe.each([
135135
indexes: {},
136136
});
137137
// use memocache because we don't support 'object' schemas in controller yet
138-
expect(new MemoCache().query(catSchema, [], state)).toMatchSnapshot();
138+
expect(
139+
new MemoCache().query(catSchema, [], state).data,
140+
).toMatchSnapshot();
139141
});
140142

141143
test('denormalizes nested in object with primitive', () => {
@@ -150,7 +152,7 @@ describe.each([
150152
},
151153
indexes: {},
152154
});
153-
const value = new MemoCache().query(catSchema, [], state);
155+
const value = new MemoCache().query(catSchema, [], state).data;
154156
expect(value).not.toEqual(expect.any(Symbol));
155157
if (typeof value === 'symbol' || value === undefined) return;
156158
expect(createOutput(value.results)).toMatchSnapshot();
@@ -171,7 +173,7 @@ describe.each([
171173
},
172174
indexes: {},
173175
});
174-
const value = new MemoCache().query(catSchema, [], state);
176+
const value = new MemoCache().query(catSchema, [], state).data;
175177
expect(value).not.toEqual(expect.any(Symbol));
176178
if (typeof value === 'symbol' || value === undefined) return;
177179
expect(createOutput(value.results).length).toBe(2);
@@ -194,11 +196,11 @@ describe.each([
194196
indexes: {},
195197
};
196198
const memo = new MemoCache();
197-
const value = memo.query(catSchema, [], state);
199+
const value = memo.query(catSchema, [], state).data;
198200

199201
expect(createOutput(value).results?.length).toBe(2);
200202
expect(createOutput(value).results).toMatchSnapshot();
201-
const value2 = memo.query(catSchema, [], state);
203+
const value2 = memo.query(catSchema, [], state).data;
202204
expect(createOutput(value).results[0]).toBe(
203205
createOutput(value2).results[0],
204206
);
@@ -214,7 +216,7 @@ describe.each([
214216
},
215217
},
216218
};
217-
const value3 = memo.query(catSchema, [], state);
219+
const value3 = memo.query(catSchema, [], state).data;
218220
expect(createOutput(value3).results?.length).toBe(3);
219221
expect(createOutput(value3).results).toMatchSnapshot();
220222
expect(createOutput(value).results[0]).toBe(
@@ -238,8 +240,8 @@ describe.each([
238240
},
239241
indexes: {},
240242
});
241-
const value = new MemoCache().query(catSchema, [], state);
242-
expect(createOutput(value)).toBeUndefined();
243+
const value = new MemoCache().query(catSchema, [], state).data;
244+
expect(createOutput(value)).toEqual(expect.any(Symbol));
243245
});
244246

245247
test('denormalizes should not be found when no entities are present (polymorphic)', () => {
@@ -270,8 +272,8 @@ describe.each([
270272
},
271273
indexes: {},
272274
});
273-
const value = new MemoCache().query(listSchema, [], state);
274-
expect(createOutput(value)).toBeUndefined();
275+
const value = new MemoCache().query(listSchema, [], state).data;
276+
expect(createOutput(value)).toEqual(expect.any(Symbol));
275277
});
276278

277279
test('returns the input value if is null', () => {
@@ -333,7 +335,7 @@ describe.each([
333335
},
334336
indexes: {},
335337
});
336-
const value = new MemoCache().query(listSchema, [], state);
338+
const value = new MemoCache().query(listSchema, [], state).data;
337339
expect(value).not.toEqual(expect.any(Symbol));
338340
if (typeof value === 'symbol') return;
339341
expect(value).toMatchSnapshot();

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

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ describe.each([
7676
},
7777
});
7878
const users: DenormalizeNullable<typeof sortedUsers> | symbol =
79-
new MemoCache().query(sortedUsers, [], state);
79+
new MemoCache().query(sortedUsers, [], state).data;
8080
expect(users).not.toEqual(expect.any(Symbol));
8181
if (typeof users === 'symbol') return;
8282
expect(users && users[0].name).toBe('Zeta');
@@ -101,7 +101,7 @@ describe.each([
101101
},
102102
});
103103
expect(
104-
new MemoCache().query(sortedUsers, [{ asc: true }], state),
104+
new MemoCache().query(sortedUsers, [{ asc: true }], state).data,
105105
).toMatchSnapshot();
106106
});
107107

@@ -115,9 +115,9 @@ describe.each([
115115
},
116116
},
117117
};
118-
const data = new MemoCache().query(sortedUsers, [], state);
118+
const { data } = new MemoCache().query(sortedUsers, [], state);
119119

120-
expect(createOutput(data)).toEqual(undefined);
120+
expect(createOutput(data)).not.toEqual(expect.any(Array));
121121
});
122122

123123
test('denormalize aggregates', () => {
@@ -152,7 +152,7 @@ describe.each([
152152
});
153153
const totalCount:
154154
| DenormalizeNullable<typeof userCountByAdmin>
155-
| symbol = new MemoCache().query(userCountByAdmin, [], state);
155+
| symbol = new MemoCache().query(userCountByAdmin, [], state).data;
156156

157157
expect(totalCount).toBe(4);
158158
const nonAdminCount:
@@ -161,15 +161,15 @@ describe.each([
161161
userCountByAdmin,
162162
[{ isAdmin: false }],
163163
state,
164-
);
164+
).data;
165165
expect(nonAdminCount).toBe(3);
166166
const adminCount:
167167
| DenormalizeNullable<typeof userCountByAdmin>
168168
| symbol = new MemoCache().query(
169169
userCountByAdmin,
170170
[{ isAdmin: true }],
171171
state,
172-
);
172+
).data;
173173
expect(adminCount).toBe(1);
174174
if (typeof totalCount === 'symbol') return;
175175

@@ -209,7 +209,7 @@ describe('top level schema', () => {
209209
},
210210
},
211211
};
212-
const users = new MemoCache().query(sortedUsers, [], state);
212+
const users = new MemoCache().query(sortedUsers, [], state).data;
213213
expect(users).not.toEqual(expect.any(Symbol));
214214
if (typeof users === 'symbol') return;
215215
expect(users && users[0].name).toBe('Zeta');
@@ -228,7 +228,7 @@ describe('top level schema', () => {
228228
},
229229
},
230230
};
231-
const users = new MemoCache().query(sortedUsers, [], state);
231+
const users = new MemoCache().query(sortedUsers, [], state).data;
232232
expect(users).toBeUndefined();
233233
});
234234

@@ -243,8 +243,8 @@ describe('top level schema', () => {
243243
return sorted.reverse();
244244
},
245245
);
246-
const users = new MemoCache().query(allSortedUsers, [], initialState);
247-
expect(users).toBeUndefined();
246+
const users = new MemoCache().query(allSortedUsers, [], initialState).data;
247+
expect(users).toEqual(expect.any(Symbol));
248248
});
249249

250250
test('works with nested schemas', () => {
@@ -258,8 +258,8 @@ describe('top level schema', () => {
258258
return sorted.reverse();
259259
},
260260
);
261-
const users = new MemoCache().query(allSortedUsers, [], initialState);
262-
expect(users).toBeUndefined();
261+
const users = new MemoCache().query(allSortedUsers, [], initialState).data;
262+
expect(users).toEqual(expect.any(Symbol));
263263
});
264264

265265
test('denormalizes should not be found when no entities are present', () => {
@@ -273,7 +273,7 @@ describe('top level schema', () => {
273273
},
274274
};
275275

276-
const value = new MemoCache().query(sortedUsers, [], state);
276+
const value = new MemoCache().query(sortedUsers, [], state).data;
277277

278278
expect(value).toEqual(undefined);
279279
});

packages/normalizr/README.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,14 +204,13 @@ const memo = new MemoCache();
204204

205205
const { data, paths } = memo.denormalize(schema, input, state.entities, args);
206206

207-
const data = memo.query(schema, args, state.entities, state.indexes);
207+
({ data, paths } = memo.query(schema, args, state));
208208

209209
function query(schema, args, state, key) {
210210
const queryKey = memo.buildQueryKey(
211211
schema,
212212
args,
213-
state.entities,
214-
state.indexes,
213+
state,
215214
key,
216215
);
217216
const { data } = this.denormalize(schema, queryKey, state.entities, args);

packages/normalizr/src/__tests__/MemoCache.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1038,11 +1038,11 @@ describe('MemoCache', () => {
10381038
});
10391039

10401040
test('works with indexes', () => {
1041-
const m = new MemoCache().query(Cat, [{ username: 'm' }], state);
1041+
const m = new MemoCache().query(Cat, [{ username: 'm' }], state).data;
10421042
expect(m).toBeDefined();
10431043
expect(m).toMatchSnapshot();
10441044
expect(
1045-
new MemoCache().query(Cat, [{ username: 'doesnotexist' }], state),
1045+
new MemoCache().query(Cat, [{ username: 'doesnotexist' }], state).data,
10461046
).toBeUndefined();
10471047
});
10481048

@@ -1051,7 +1051,7 @@ describe('MemoCache', () => {
10511051
expect(m).toBeDefined();
10521052
expect(m).toMatchSnapshot();
10531053
expect(
1054-
new MemoCache().query(Cat, [{ id: 'doesnotexist' }], state),
1054+
new MemoCache().query(Cat, [{ id: 'doesnotexist' }], state).data,
10551055
).toBeUndefined();
10561056
});
10571057
});

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

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,18 @@ Cat {
99
`;
1010

1111
exports[`MemoCache query (direct) works with pk 1`] = `
12-
Cat {
13-
"id": "1",
14-
"name": "Milo",
15-
"username": "m",
12+
{
13+
"data": Cat {
14+
"id": "1",
15+
"name": "Milo",
16+
"username": "m",
17+
},
18+
"paths": [
19+
{
20+
"key": "Cat",
21+
"pk": "1",
22+
},
23+
],
1624
}
1725
`;
1826

@@ -25,10 +33,18 @@ Cat {
2533
`;
2634

2735
exports[`MemoCache query (immutable) works with pk 1`] = `
28-
Cat {
29-
"id": "1",
30-
"name": "Milo",
31-
"username": "m",
36+
{
37+
"data": Cat {
38+
"id": "1",
39+
"name": "Milo",
40+
"username": "m",
41+
},
42+
"paths": [
43+
{
44+
"key": "Cat",
45+
"pk": "1",
46+
},
47+
],
3248
}
3349
`;
3450

packages/normalizr/src/memo/MemoCache.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,17 @@ export default class MemoCache {
7171
state: StateInterface,
7272
// NOTE: different orders can result in cache busting here; but since it's just a perf penalty we will allow for now
7373
argsKey: string = JSON.stringify(args),
74-
): DenormalizeNullable<S> | undefined {
74+
): {
75+
data: DenormalizeNullable<S> | symbol;
76+
paths: EntityPath[];
77+
} {
7578
const input = this.buildQueryKey(schema, args, state, argsKey);
7679

7780
if (!input) {
78-
return;
81+
return { data: undefined as any, paths: [] };
7982
}
8083

81-
const { data } = this.denormalize(schema, input, state.entities, args);
82-
return typeof data === 'symbol' ? undefined : (data as any);
84+
return this.denormalize(schema, input, state.entities, args);
8385
}
8486

8587
buildQueryKey<S extends Schema>(

website/src/components/Playground/editor-types/@data-client/core.d.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -224,17 +224,20 @@ declare class MemoCache {
224224
paths: EntityPath[];
225225
};
226226
/** Compute denormalized form maintaining referential equality for same inputs */
227-
query<S extends Schema>(schema: S, args: readonly any[], entities: Record<string, Record<string, any> | undefined> | {
228-
getIn(k: string[]): any;
229-
}, indexes: NormalizedIndex | {
230-
getIn(k: string[]): any;
231-
}, argsKey?: string): DenormalizeNullable<S> | undefined;
232-
buildQueryKey<S extends Schema>(schema: S, args: readonly any[], entities: Record<string, Record<string, any> | undefined> | {
227+
query<S extends Schema>(schema: S, args: readonly any[], state: StateInterface, argsKey?: string): {
228+
data: DenormalizeNullable<S> | symbol;
229+
paths: EntityPath[];
230+
};
231+
buildQueryKey<S extends Schema>(schema: S, args: readonly any[], state: StateInterface, argsKey?: string): NormalizeNullable<S>;
232+
}
233+
type StateInterface = {
234+
entities: Record<string, Record<string, any> | undefined> | {
233235
getIn(k: string[]): any;
234-
}, indexes: NormalizedIndex | {
236+
};
237+
indexes: NormalizedIndex | {
235238
getIn(k: string[]): any;
236-
}, argsKey?: string): NormalizeNullable<S>;
237-
}
239+
};
240+
};
238241

239242
/** https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-4.html#the-noinfer-utility-type */
240243
type NI<T> = NoInfer<T>;

0 commit comments

Comments
 (0)