diff --git a/.api-reports/api-report-cache.api.md b/.api-reports/api-report-cache.api.md index 80b2a3e3024..4bf3edb6bba 100644 --- a/.api-reports/api-report-cache.api.md +++ b/.api-reports/api-report-cache.api.md @@ -356,7 +356,7 @@ export abstract class EntityStore implements NormalizedCache { // (undocumented) merge(older: string | StoreObject, newer: StoreObject | string): void; // (undocumented) - modify(dataId: string, fields: Modifier | Modifiers>): boolean; + modify(dataId: string, fields: Modifier | Modifiers>, exact: boolean): boolean; // (undocumented) readonly policies: Policies; // (undocumented) @@ -729,7 +729,7 @@ export interface NormalizedCache { // (undocumented) merge(olderObject: StoreObject, newerId: string): void; // (undocumented) - modify>(dataId: string, fields: Modifiers | AllFieldsModifier): boolean; + modify>(dataId: string, fields: Modifiers | AllFieldsModifier, exact: boolean): boolean; // (undocumented) release(rootId: string): number; replace(newData: NormalizedCacheObject): void; @@ -953,7 +953,7 @@ interface WriteContext extends ReadMergeModifyContext { // // src/cache/inmemory/policies.ts:166:3 - (ae-forgotten-export) The symbol "KeySpecifier" needs to be exported by the entry point index.d.ts // src/cache/inmemory/policies.ts:166:3 - (ae-forgotten-export) The symbol "KeyArgsFunction" needs to be exported by the entry point index.d.ts -// src/cache/inmemory/types.ts:133:3 - (ae-forgotten-export) The symbol "KeyFieldsFunction" needs to be exported by the entry point index.d.ts +// src/cache/inmemory/types.ts:134:3 - (ae-forgotten-export) The symbol "KeyFieldsFunction" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) diff --git a/.api-reports/api-report-utilities_internal.api.md b/.api-reports/api-report-utilities_internal.api.md index 7b6d13748a3..653b987df5b 100644 --- a/.api-reports/api-report-utilities_internal.api.md +++ b/.api-reports/api-report-utilities_internal.api.md @@ -440,7 +440,7 @@ export type VariablesOption = {} extends // Warnings were encountered during analysis: // -// src/utilities/internal/getStoreKeyName.ts:87:1 - (ae-forgotten-export) The symbol "storeKeyNameStringify" needs to be exported by the entry point index.d.ts +// src/utilities/internal/getStoreKeyName.ts:89:1 - (ae-forgotten-export) The symbol "storeKeyNameStringify" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) diff --git a/.api-reports/api-report.api.md b/.api-reports/api-report.api.md index e183f9da8f0..c02e09d149c 100644 --- a/.api-reports/api-report.api.md +++ b/.api-reports/api-report.api.md @@ -761,7 +761,7 @@ abstract class EntityStore implements NormalizedCache { // (undocumented) merge(older: string | StoreObject, newer: StoreObject | string): void; // (undocumented) - modify(dataId: string, fields: Modifier | Modifiers>): boolean; + modify(dataId: string, fields: Modifier | Modifiers>, exact: boolean): boolean; // Warning: (ae-forgotten-export) The symbol "Policies" needs to be exported by the entry point index.d.ts // // (undocumented) @@ -1831,7 +1831,7 @@ export interface NormalizedCache { // (undocumented) merge(olderObject: StoreObject, newerId: string): void; // (undocumented) - modify>(dataId: string, fields: Modifiers | AllFieldsModifier): boolean; + modify>(dataId: string, fields: Modifiers | AllFieldsModifier, exact: boolean): boolean; // (undocumented) release(rootId: string): number; replace(newData: NormalizedCacheObject): void; @@ -2718,7 +2718,7 @@ interface WriteContext extends ReadMergeModifyContext { // src/cache/inmemory/policies.ts:97:3 - (ae-forgotten-export) The symbol "FragmentMap" needs to be exported by the entry point index.d.ts // src/cache/inmemory/policies.ts:166:3 - (ae-forgotten-export) The symbol "KeySpecifier" needs to be exported by the entry point index.d.ts // src/cache/inmemory/policies.ts:166:3 - (ae-forgotten-export) The symbol "KeyArgsFunction" needs to be exported by the entry point index.d.ts -// src/cache/inmemory/types.ts:133:3 - (ae-forgotten-export) The symbol "KeyFieldsFunction" needs to be exported by the entry point index.d.ts +// src/cache/inmemory/types.ts:134:3 - (ae-forgotten-export) The symbol "KeyFieldsFunction" needs to be exported by the entry point index.d.ts // src/core/ObservableQuery.ts:145:5 - (ae-forgotten-export) The symbol "NextFetchPolicyContext" needs to be exported by the entry point index.d.ts // src/core/ObservableQuery.ts:325:5 - (ae-forgotten-export) The symbol "QueryManager" needs to be exported by the entry point index.d.ts // src/core/QueryManager.ts:187:5 - (ae-forgotten-export) The symbol "MutationStoreValue" needs to be exported by the entry point index.d.ts diff --git a/.changeset/late-bottles-add.md b/.changeset/late-bottles-add.md new file mode 100644 index 00000000000..72c0786399d --- /dev/null +++ b/.changeset/late-bottles-add.md @@ -0,0 +1,23 @@ +--- +"@apollo/client": patch +--- + +`InMemoryCache`: Fields with an empty argument object are now saved the same way as fields without arguments. + +Previously, it was possible that the reponses for these two queries would be stored differently in the cache: + +```gql +query PlainAccess { + myField +} +``` +would be stored as `myField` +and +```gql +query AccessWithoutOptionalArgument($optional: String) { + myField(optional: $optional) +} +``` +would be stored as `myField({"optional":"Foo"})` if called with `{optional: "Foo"}` and as `myField({})` if called without the optional argument. + +The cases `myField` and `myField({})` are equivalent from the perspective of a GraphQL server, and so in the future both of these will be stored as `myField` in the cache. diff --git a/.size-limits.json b/.size-limits.json index 82dc923d86d..38539ad5859 100644 --- a/.size-limits.json +++ b/.size-limits.json @@ -1,6 +1,6 @@ { - "import { ApolloClient, InMemoryCache, HttpLink } from \"@apollo/client\" (CJS)": 43792, - "import { ApolloClient, InMemoryCache, HttpLink } from \"@apollo/client\" (production) (CJS)": 38852, - "import { ApolloClient, InMemoryCache, HttpLink } from \"@apollo/client\"": 33427, - "import { ApolloClient, InMemoryCache, HttpLink } from \"@apollo/client\" (production)": 27671 + "import { ApolloClient, InMemoryCache, HttpLink } from \"@apollo/client\" (CJS)": 43837, + "import { ApolloClient, InMemoryCache, HttpLink } from \"@apollo/client\" (production) (CJS)": 38833, + "import { ApolloClient, InMemoryCache, HttpLink } from \"@apollo/client\"": 33457, + "import { ApolloClient, InMemoryCache, HttpLink } from \"@apollo/client\" (production)": 27750 } diff --git a/src/cache/inmemory/__tests__/entityStore.ts b/src/cache/inmemory/__tests__/entityStore.ts index 4ed05b6ffe8..9c9315c07f7 100644 --- a/src/cache/inmemory/__tests__/entityStore.ts +++ b/src/cache/inmemory/__tests__/entityStore.ts @@ -1212,7 +1212,7 @@ describe("EntityStore", () => { name: "Isaac Asimov", hobby: "chemistry", }, - "authorOfBook({})": { + authorOfBook: { __typename: "Author", name: "James S.A. Corey", hobby: "tabletop games", @@ -1233,7 +1233,7 @@ describe("EntityStore", () => { name: "Isaac Asimov", hobby: "chemistry", }, - "authorOfBook({})": { + authorOfBook: { __typename: "Author", name: "James S.A. Corey", hobby: "tabletop games", @@ -1254,7 +1254,7 @@ describe("EntityStore", () => { name: "Isaac Asimov", hobby: "chemistry", }, - "authorOfBook({})": { + authorOfBook: { __typename: "Author", name: "James S.A. Corey", hobby: "tabletop games", @@ -1360,7 +1360,7 @@ describe("EntityStore", () => { name: "Isaac Asimov", hobby: "chemistry", }, - "authorOfBook({})": { + authorOfBook: { __typename: "Author", name: "James S.A. Corey", hobby: "tabletop games", @@ -1382,7 +1382,7 @@ describe("EntityStore", () => { name: "Isaac Asimov", hobby: "chemistry", }, - "authorOfBook({})": { + authorOfBook: { __typename: "Author", name: "James S.A. Corey", hobby: "tabletop games", @@ -1404,7 +1404,7 @@ describe("EntityStore", () => { name: "Isaac Asimov", hobby: "chemistry", }, - "authorOfBook({})": { + authorOfBook: { __typename: "Author", name: "James S.A. Corey", hobby: "tabletop games", diff --git a/src/cache/inmemory/entityStore.ts b/src/cache/inmemory/entityStore.ts index 49673c4d3a4..80f47bb444a 100644 --- a/src/cache/inmemory/entityStore.ts +++ b/src/cache/inmemory/entityStore.ts @@ -204,7 +204,8 @@ export abstract class EntityStore implements NormalizedCache { public modify( dataId: string, - fields: Modifier | Modifiers> + fields: Modifier | Modifiers>, + exact: boolean ): boolean { const storeObject = this.lookup(dataId); @@ -240,7 +241,7 @@ export abstract class EntityStore implements NormalizedCache { if (fieldValue === void 0) return; const modify: Modifier | undefined = typeof fields === "function" ? fields : ( - fields[storeFieldName] || fields[fieldName] + fields[storeFieldName] || (exact ? undefined : fields[fieldName]) ); if (modify) { let newValue = @@ -356,7 +357,8 @@ export abstract class EntityStore implements NormalizedCache { { [storeFieldName]: delModifier, } - : delModifier + : delModifier, + !!args ); } return false; diff --git a/src/cache/inmemory/inMemoryCache.ts b/src/cache/inmemory/inMemoryCache.ts index 5cded6eefc0..27a0d200cb3 100644 --- a/src/cache/inmemory/inMemoryCache.ts +++ b/src/cache/inmemory/inMemoryCache.ts @@ -234,7 +234,7 @@ export class InMemoryCache extends ApolloCache { : this.data; try { ++this.txCount; - return store.modify(options.id || "ROOT_QUERY", options.fields); + return store.modify(options.id || "ROOT_QUERY", options.fields, false); } finally { if (!--this.txCount && options.broadcast !== false) { this.broadcastWatches(); diff --git a/src/cache/inmemory/types.ts b/src/cache/inmemory/types.ts index c197455e42b..81f48524341 100644 --- a/src/cache/inmemory/types.ts +++ b/src/cache/inmemory/types.ts @@ -51,7 +51,8 @@ export interface NormalizedCache { modify>( dataId: string, - fields: Modifiers | AllFieldsModifier + fields: Modifiers | AllFieldsModifier, + exact: boolean ): boolean; delete(dataId: string, fieldName?: string): boolean; clear(): void; diff --git a/src/utilities/internal/getStoreKeyName.ts b/src/utilities/internal/getStoreKeyName.ts index 69d6c70a986..f5b10113881 100644 --- a/src/utilities/internal/getStoreKeyName.ts +++ b/src/utilities/internal/getStoreKeyName.ts @@ -50,12 +50,12 @@ export const getStoreKeyName = Object.assign( filteredArgs[key] = args[key]; }); - return `${directives["connection"]["key"]}(${storeKeyNameStringify( - filteredArgs - )})`; - } else { - return directives["connection"]["key"]; + const stringifiedArgs: string = storeKeyNameStringify(filteredArgs); + if (stringifiedArgs !== "{}") { + return `${directives["connection"]["key"]}(${stringifiedArgs})`; + } } + return directives["connection"]["key"]; } let completeFieldName: string = fieldName; @@ -65,7 +65,9 @@ export const getStoreKeyName = Object.assign( // and can lead to different store key names being created even though // the `args` object used during creation has the same properties/values. const stringifiedArgs: string = storeKeyNameStringify(args); - completeFieldName += `(${stringifiedArgs})`; + if (stringifiedArgs !== "{}") { + completeFieldName += `(${stringifiedArgs})`; + } } if (directives) {