Skip to content

Commit

Permalink
Use weakMap for private parts
Browse files Browse the repository at this point in the history
  • Loading branch information
msand committed Aug 29, 2024
1 parent 475ff2f commit 014770f
Show file tree
Hide file tree
Showing 10 changed files with 349 additions and 209 deletions.
8 changes: 5 additions & 3 deletions src/__tests__/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import {
} from "../testing";
import { spyOnConsole } from "../testing/internal";
import { waitFor } from "@testing-library/react";
import { $ } from "../cache/inmemory/privates";

describe("client", () => {
it("can be loaded via require", () => {
Expand Down Expand Up @@ -3525,7 +3526,8 @@ describe("@connection", () => {
const aResults = watch(aQuery);
const bResults = watch(bQuery);

expect(cache["watches"].size).toBe(2);
const watches = $(cache)["watches"];
expect(watches.size).toBe(2);

expect(aResults).toEqual([]);
expect(bResults).toEqual([]);
Expand All @@ -3543,10 +3545,10 @@ describe("@connection", () => {
expect(aResults).toEqual([]);
expect(bResults).toEqual([]);

expect(cache["watches"].size).toBe(0);
expect(watches.size).toBe(0);
const abResults = watch(abQuery);
expect(abResults).toEqual([]);
expect(cache["watches"].size).toBe(1);
expect(watches.size).toBe(1);

await wait();

Expand Down
3 changes: 2 additions & 1 deletion src/__tests__/resultCacheCleaning.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { makeExecutableSchema } from "@graphql-tools/schema";
import { ApolloClient, Resolvers, gql } from "../core";
import { InMemoryCache, NormalizedCacheObject } from "../cache";
import { SchemaLink } from "../link/schema";
import { $ } from "../cache/inmemory/privates";

describe("resultCache cleaning", () => {
const fragments = gql`
Expand Down Expand Up @@ -150,7 +151,7 @@ describe("resultCache cleaning", () => {
});

afterEach(() => {
const storeReader = (client.cache as InMemoryCache)["storeReader"];
const { storeReader } = $(client.cache);
expect(storeReader["executeSubSelectedArray"].size).toBeGreaterThan(0);
expect(storeReader["executeSelectionSet"].size).toBeGreaterThan(0);
client.cache.evict({
Expand Down
2 changes: 1 addition & 1 deletion src/cache/core/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ export abstract class ApolloCache<TSerialized> implements DataProxy {

// Make sure we compute the same (===) fragment query document every
// time we receive the same fragment in readFragment.
private getFragmentDoc = wrap(getFragmentQueryDocument, {
getFragmentDoc = wrap(getFragmentQueryDocument, {
max:
cacheSizes["cache.fragmentQueryDocuments"] ||
defaultCacheSizes["cache.fragmentQueryDocuments"],
Expand Down
64 changes: 36 additions & 28 deletions src/cache/inmemory/__tests__/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { ObjectCanon } from "../object-canon";
import { TypePolicies } from "../policies";
import { spyOnConsole } from "../../../testing/internal";
import { defaultCacheSizes } from "../../../utilities";
import { $ } from "../privates";

disableFragmentWarnings();

Expand Down Expand Up @@ -1498,13 +1499,15 @@ describe("Cache", () => {
}
`;

const originalReader = cache["storeReader"];
const privates = $(cache);

const originalReader = privates.storeReader;
expect(originalReader).toBeInstanceOf(StoreReader);

const originalWriter = cache["storeWriter"];
const originalWriter = privates.storeWriter;
expect(originalWriter).toBeInstanceOf(StoreWriter);

const originalMBW = cache["maybeBroadcastWatch"];
const originalMBW = privates.maybeBroadcastWatch;
expect(typeof originalMBW).toBe("function");

const originalCanon = originalReader.canon;
Expand Down Expand Up @@ -1534,12 +1537,12 @@ describe("Cache", () => {
c: "see",
});

expect(originalReader).not.toBe(cache["storeReader"]);
expect(originalWriter).not.toBe(cache["storeWriter"]);
expect(originalMBW).not.toBe(cache["maybeBroadcastWatch"]);
expect(originalReader).not.toBe(privates.storeReader);
expect(originalWriter).not.toBe(privates.storeWriter);
expect(originalMBW).not.toBe(privates.maybeBroadcastWatch);
// The cache.storeReader.canon is preserved by default, but can be dropped
// by passing resetResultIdentities:true to cache.gc.
expect(originalCanon).toBe(cache["storeReader"].canon);
expect(originalCanon).toBe(privates.storeReader.canon);
});
});

Expand Down Expand Up @@ -2122,10 +2125,11 @@ describe("Cache", () => {
describe("resultCacheMaxSize", () => {
it("uses default max size on caches if resultCacheMaxSize is not configured", () => {
const cache = new InMemoryCache();
expect(cache["maybeBroadcastWatch"].options.max).toBe(
const privates = $(cache);
expect(privates.maybeBroadcastWatch.options.max).toBe(
defaultCacheSizes["inMemoryCache.maybeBroadcastWatch"]
);
expect(cache["storeReader"]["executeSelectionSet"].options.max).toBe(
expect(privates.storeReader["executeSelectionSet"].options.max).toBe(
defaultCacheSizes["inMemoryCache.executeSelectionSet"]
);
expect(cache["getFragmentDoc"].options.max).toBe(
Expand All @@ -2136,8 +2140,9 @@ describe("resultCacheMaxSize", () => {
it("configures max size on caches when resultCacheMaxSize is set", () => {
const resultCacheMaxSize = 12345;
const cache = new InMemoryCache({ resultCacheMaxSize });
expect(cache["maybeBroadcastWatch"].options.max).toBe(resultCacheMaxSize);
expect(cache["storeReader"]["executeSelectionSet"].options.max).toBe(
const privates = $(cache);
expect(privates.maybeBroadcastWatch.options.max).toBe(resultCacheMaxSize);
expect(privates.storeReader["executeSelectionSet"].options.max).toBe(
resultCacheMaxSize
);
expect(cache["getFragmentDoc"].options.max).toBe(
Expand Down Expand Up @@ -2400,7 +2405,7 @@ describe("InMemoryCache#broadcastWatches", function () {
[canonicalCache, nonCanonicalCache].forEach((cache) => {
// Hack: delete every watch.lastDiff, so subsequent results will be
// broadcast, even though they are deeply equal to the previous results.
cache["watches"].forEach((watch) => {
$(cache)["watches"].forEach((watch) => {
delete watch.lastDiff;
});
});
Expand Down Expand Up @@ -3813,19 +3818,20 @@ describe("ReactiveVar and makeVar", () => {

expect(diffs.length).toBe(5);

expect(cache["watches"].size).toBe(5);
const watches = $(cache)["watches"];
expect(watches.size).toBe(5);
expect(spy).not.toBeCalled();

unwatchers.pop()!();
expect(cache["watches"].size).toBe(4);
expect(watches.size).toBe(4);
expect(spy).not.toBeCalled();

unwatchers.shift()!();
expect(cache["watches"].size).toBe(3);
expect(watches.size).toBe(3);
expect(spy).not.toBeCalled();

unwatchers.pop()!();
expect(cache["watches"].size).toBe(2);
expect(watches.size).toBe(2);
expect(spy).not.toBeCalled();

expect(diffs.length).toBe(5);
Expand All @@ -3835,7 +3841,7 @@ describe("ReactiveVar and makeVar", () => {
expect(unwatchers.length).toBe(3);
unwatchers.forEach((unwatch) => unwatch());

expect(cache["watches"].size).toBe(0);
expect(watches.size).toBe(0);
expect(spy).toBeCalledTimes(1);
expect(spy).toBeCalledWith(cache);
});
Expand Down Expand Up @@ -3865,7 +3871,8 @@ describe("ReactiveVar and makeVar", () => {
watch("a");
watch("d");

expect(cache["watches"].size).toBe(5);
const watches = $(cache)["watches"];
expect(watches.size).toBe(5);
expect(diffCounts).toEqual({
a: 2,
b: 1,
Expand All @@ -3875,7 +3882,7 @@ describe("ReactiveVar and makeVar", () => {

unwatchers.a.forEach((unwatch) => unwatch());
unwatchers.a.length = 0;
expect(cache["watches"].size).toBe(3);
expect(watches.size).toBe(3);

nameVar("Hugh");
expect(diffCounts).toEqual({
Expand All @@ -3886,7 +3893,7 @@ describe("ReactiveVar and makeVar", () => {
});

cache.reset({ discardWatches: true });
expect(cache["watches"].size).toBe(0);
expect(watches.size).toBe(0);

expect(diffCounts).toEqual({
a: 2,
Expand Down Expand Up @@ -3926,7 +3933,7 @@ describe("ReactiveVar and makeVar", () => {
});

nameVar("Trevor");
expect(cache["watches"].size).toBe(2);
expect(watches.size).toBe(2);
expect(diffCounts).toEqual({
a: 2,
b: 2,
Expand All @@ -3937,7 +3944,7 @@ describe("ReactiveVar and makeVar", () => {
});

cache.reset({ discardWatches: true });
expect(cache["watches"].size).toBe(0);
expect(watches.size).toBe(0);

nameVar("Danielle");
expect(diffCounts).toEqual({
Expand All @@ -3949,7 +3956,7 @@ describe("ReactiveVar and makeVar", () => {
f: 2,
});

expect(cache["watches"].size).toBe(0);
expect(watches.size).toBe(0);
});

it("should recall forgotten vars once cache has watches again", () => {
Expand All @@ -3974,22 +3981,23 @@ describe("ReactiveVar and makeVar", () => {
expect(diffs.length).toBe(3);
expect(names()).toEqual(["Ben", "Ben", "Ben"]);

expect(cache["watches"].size).toBe(3);
const watches = $(cache)["watches"];
expect(watches.size).toBe(3);
expect(spy).not.toBeCalled();

unwatchers.pop()!();
expect(cache["watches"].size).toBe(2);
expect(watches.size).toBe(2);
expect(spy).not.toBeCalled();

unwatchers.shift()!();
expect(cache["watches"].size).toBe(1);
expect(watches.size).toBe(1);
expect(spy).not.toBeCalled();

nameVar("Hugh");
expect(names()).toEqual(["Ben", "Ben", "Ben", "Hugh"]);

unwatchers.pop()!();
expect(cache["watches"].size).toBe(0);
expect(watches.size).toBe(0);
expect(spy).toBeCalledTimes(1);
expect(spy).toBeCalledWith(cache);

Expand All @@ -3999,7 +4007,7 @@ describe("ReactiveVar and makeVar", () => {

// Call watch(false) to avoid immediate delivery of the "ignored" name.
unwatchers.push(watch(false));
expect(cache["watches"].size).toBe(1);
expect(watches.size).toBe(1);
expect(names()).toEqual(["Ben", "Ben", "Ben", "Hugh"]);

// This is the test that would fail if cache.watch did not call
Expand Down
10 changes: 6 additions & 4 deletions src/cache/inmemory/__tests__/entityStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { TypedDocumentNode } from "@graphql-typed-document-node/core";
import { stringifyForDisplay } from "../../../utilities";
import { InvariantError } from "../../../utilities/globals";
import { spyOnConsole } from "../../../testing/internal";
import { $ } from "../privates";

describe("EntityStore", () => {
it("should support result caching if so configured", () => {
Expand Down Expand Up @@ -220,13 +221,14 @@ describe("EntityStore", () => {

// Nothing left to collect, but let's also reset the result cache to
// demonstrate that the recomputed cache results are unchanged.
const originalReader = cache["storeReader"];
const { storeReader } = $(cache);
const originalReader = storeReader;
expect(
cache.gc({
resetResultCache: true,
})
).toEqual([]);
expect(cache["storeReader"]).not.toBe(originalReader);
expect(storeReader).not.toBe(originalReader);
const resultAfterResetResultCache = read();
expect(resultAfterResetResultCache).toBe(resultBeforeGC);
expect(resultAfterResetResultCache).toBe(resultAfterGC);
Expand Down Expand Up @@ -1000,7 +1002,7 @@ describe("EntityStore", () => {
expect(cache.gc()).toEqual([]);

const willId = cache.identify(data.parent)!;
const store = cache["data"];
const { data: store } = $(cache);
const storeRootData = store["data"];
// Hacky way of injecting a stray __ref field into the Will Smith Person
// object, clearing store.refs (which was populated by the previous GC).
Expand Down Expand Up @@ -2675,7 +2677,7 @@ describe("EntityStore", () => {
},
});

const store = cache["data"];
const { data: store } = $(cache);

const query = gql`
query Book($isbn: string) {
Expand Down
7 changes: 5 additions & 2 deletions src/cache/inmemory/__tests__/readFromStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
TypedDocumentNode,
} from "../../../core";
import { defaultCacheSizes } from "../../../utilities";
import { $ } from "../privates";

describe("resultCacheMaxSize", () => {
const cache = new InMemoryCache();
Expand Down Expand Up @@ -2207,7 +2208,8 @@ describe("reading from the store", () => {
},
});

const canon = cache["storeReader"].canon;
const { storeReader } = $(cache);
const canon = storeReader.canon;

const query = gql`
query {
Expand Down Expand Up @@ -2263,7 +2265,8 @@ describe("reading from the store", () => {
},
});

const canon = cache["storeReader"].canon;
const { storeReader } = $(cache);
const canon = storeReader.canon;

const fragment = gql`
fragment CountFragment on Query {
Expand Down
Loading

0 comments on commit 014770f

Please sign in to comment.