Skip to content

Commit

Permalink
bail out of executeSubSelectedArray calls for empty arrays (#11670)
Browse files Browse the repository at this point in the history
* potential optimization - bail out of `executeSubSelectedArray` calls

* simplify logic, add test

* update size-limits

* Clean up Prettier, Size-limit, and Api-Extractor

---------

Co-authored-by: phryneas <phryneas@users.noreply.github.com>
  • Loading branch information
phryneas and phryneas authored Mar 26, 2024
1 parent 6393537 commit cc5c03b
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 11 deletions.
5 changes: 5 additions & 0 deletions .changeset/mean-singers-cheer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@apollo/client": patch
---

Bail out of `executeSubSelectedArray` calls if the array has 0 elements.
4 changes: 2 additions & 2 deletions .size-limits.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"dist/apollo-client.min.cjs": 39319,
"import { ApolloClient, InMemoryCache, HttpLink } from \"dist/index.js\" (production)": 32630
"dist/apollo-client.min.cjs": 39325,
"import { ApolloClient, InMemoryCache, HttpLink } from \"dist/index.js\" (production)": 32634
}
63 changes: 63 additions & 0 deletions src/cache/inmemory/__tests__/readFromStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,69 @@ describe("reading from the store", () => {
});
});

it("runs a nested query - skips iterating into an empty array", () => {
const reader = new StoreReader({
cache: new InMemoryCache(),
});

const result = {
id: "abcd",
stringField: "This is a string!",
numberField: 5,
nullField: null,
nestedArray: [
{
id: "abcde",
stringField: "This is a string also!",
numberField: 7,
nullField: null,
},
],
emptyArray: [],
} satisfies StoreObject;

const store = defaultNormalizedCacheFactory({
ROOT_QUERY: { ...result, nestedArray: [makeReference("abcde")] },
abcde: result.nestedArray[0],
});

expect(reader["executeSubSelectedArray"].size).toBe(0);

// assumption: cache size does not increase for empty array
readQueryFromStore(reader, {
store,
query: gql`
{
stringField
numberField
emptyArray {
id
stringField
numberField
}
}
`,
});
expect(reader["executeSubSelectedArray"].size).toBe(0);

// assumption: cache size increases for array with content
readQueryFromStore(reader, {
store,
query: gql`
{
stringField
numberField
nestedArray {
id
stringField
numberField
}
}
`,
});
expect(reader["executeSubSelectedArray"].size).toBe(1);
});

it("throws on a missing field", () => {
const result = {
id: "abcd",
Expand Down
20 changes: 11 additions & 9 deletions src/cache/inmemory/readFromStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -403,15 +403,17 @@ export class StoreReader {
});
}
} else if (isArray(fieldValue)) {
fieldValue = handleMissing(
this.executeSubSelectedArray({
field: selection,
array: fieldValue,
enclosingRef,
context,
}),
resultName
);
if (fieldValue.length > 0) {
fieldValue = handleMissing(
this.executeSubSelectedArray({
field: selection,
array: fieldValue,
enclosingRef,
context,
}),
resultName
);
}
} else if (!selection.selectionSet) {
// If the field does not have a selection set, then we handle it
// as a scalar value. To keep this.canon from canonicalizing
Expand Down

0 comments on commit cc5c03b

Please sign in to comment.