@isograph/react 0.0.0-main-3779371d → 0.0.0-main-adc27d88

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/IsographEnvironment.d.ts +6 -1
  2. package/dist/IsographEnvironment.js +11 -1
  3. package/dist/cache.d.ts +2 -2
  4. package/dist/cache.js +66 -12
  5. package/dist/componentCache.d.ts +1 -1
  6. package/dist/componentCache.js +11 -6
  7. package/dist/index.d.ts +1 -0
  8. package/dist/index.js +3 -1
  9. package/dist/read.d.ts +7 -3
  10. package/dist/read.js +40 -17
  11. package/dist/useRerenderWhenEncounteredRecordChanges.d.ts +2 -0
  12. package/dist/useRerenderWhenEncounteredRecordChanges.js +14 -0
  13. package/dist/useResult.js +4 -9
  14. package/package.json +4 -4
  15. package/src/IsographEnvironment.tsx +17 -1
  16. package/src/cache.ts +78 -13
  17. package/src/componentCache.ts +24 -11
  18. package/src/index.ts +1 -0
  19. package/src/read.ts +55 -18
  20. package/src/tests/__isograph/Query/meName/entrypoint.ts +43 -0
  21. package/src/tests/__isograph/Query/meName/reader.ts +40 -0
  22. package/src/tests/__isograph/Query/meNameSuccessor/entrypoint.ts +79 -0
  23. package/src/tests/__isograph/Query/meNameSuccessor/reader.ts +67 -0
  24. package/src/tests/__isograph/Query/nodeField/entrypoint.ts +42 -0
  25. package/src/tests/__isograph/Query/nodeField/reader.ts +45 -0
  26. package/src/tests/__isograph/iso.ts +60 -0
  27. package/src/tests/garbageCollection.test.ts +130 -0
  28. package/src/tests/isograph.config.json +7 -0
  29. package/src/tests/meNameSuccessor.ts +20 -0
  30. package/src/tests/nodeQuery.ts +17 -0
  31. package/src/tests/schema.graphql +16 -0
  32. package/src/tests/tsconfig.json +21 -0
  33. package/src/useRerenderWhenEncounteredRecordChanges.ts +15 -0
  34. package/src/useResult.ts +8 -9
  35. package/tsconfig.pkg.json +2 -1
@@ -0,0 +1,42 @@
1
+ import type {IsographEntrypoint, NormalizationAst, RefetchQueryArtifactWrapper} from '@isograph/react';
2
+ import type {Query__nodeField__param, Query__nodeField__outputType} from './reader';
3
+ import readerResolver from './reader';
4
+ const nestedRefetchQueries: RefetchQueryArtifactWrapper[] = [];
5
+
6
+ const queryText = 'query nodeField ($id: ID!) {\
7
+ node____id___v_id: node(id: $id) {\
8
+ id,\
9
+ },\
10
+ }';
11
+
12
+ const normalizationAst: NormalizationAst = [
13
+ {
14
+ kind: "Linked",
15
+ fieldName: "node",
16
+ arguments: [
17
+ [
18
+ "id",
19
+ { kind: "Variable", name: "id" },
20
+ ],
21
+ ],
22
+ selections: [
23
+ {
24
+ kind: "Scalar",
25
+ fieldName: "id",
26
+ arguments: null,
27
+ },
28
+ ],
29
+ },
30
+ ];
31
+ const artifact: IsographEntrypoint<
32
+ Query__nodeField__param,
33
+ Query__nodeField__outputType
34
+ > = {
35
+ kind: "Entrypoint",
36
+ queryText,
37
+ normalizationAst,
38
+ nestedRefetchQueries,
39
+ readerArtifact: readerResolver,
40
+ };
41
+
42
+ export default artifact;
@@ -0,0 +1,45 @@
1
+ import type {ReaderArtifact, ReaderAst, ExtractSecondParam} from '@isograph/react';
2
+ import { nodeField as resolver } from '../../../nodeQuery.ts';
3
+
4
+ // the type, when read out (either via useLazyReference or via graph)
5
+ export type Query__nodeField__outputType = ReturnType<typeof resolver>;
6
+
7
+ const readerAst: ReaderAst<Query__nodeField__param> = [
8
+ {
9
+ kind: "Linked",
10
+ fieldName: "node",
11
+ alias: null,
12
+ arguments: [
13
+ [
14
+ "id",
15
+ { kind: "Variable", name: "id" },
16
+ ],
17
+ ],
18
+ selections: [
19
+ {
20
+ kind: "Scalar",
21
+ fieldName: "id",
22
+ alias: null,
23
+ arguments: null,
24
+ },
25
+ ],
26
+ },
27
+ ];
28
+
29
+ export type Query__nodeField__param = {
30
+ node: ({
31
+ id: string,
32
+ } | null),
33
+ };
34
+
35
+ const artifact: ReaderArtifact<
36
+ Query__nodeField__param,
37
+ Query__nodeField__outputType
38
+ > = {
39
+ kind: "ReaderArtifact",
40
+ resolver: resolver as any,
41
+ readerAst,
42
+ variant: { kind: "Eager" },
43
+ };
44
+
45
+ export default artifact;
@@ -0,0 +1,60 @@
1
+ import type {IsographEntrypoint} from '@isograph/react';
2
+ import { Query__meNameSuccessor__param } from './Query/meNameSuccessor/reader'
3
+ import { Query__meName__param } from './Query/meName/reader'
4
+ import { Query__nodeField__param } from './Query/nodeField/reader'
5
+ import entrypoint_Query__meNameSuccessor from '../__isograph/Query/meNameSuccessor/entrypoint'
6
+ import entrypoint_Query__meName from '../__isograph/Query/meName/entrypoint'
7
+ import entrypoint_Query__nodeField from '../__isograph/Query/nodeField/entrypoint'
8
+
9
+ type IdentityWithParam<TParam> = <TResolverReturn>(
10
+ x: (param: TParam) => TResolverReturn
11
+ ) => (param: TParam) => TResolverReturn;
12
+ type IdentityWithParamComponent<TParam> = <TResolverReturn, TSecondParam = Record<string, never>>(
13
+ x: (data: TParam, secondParam: TSecondParam) => TResolverReturn
14
+ ) => (data: TParam, secondParam: TSecondParam) => TResolverReturn;
15
+
16
+ type WhitespaceCharacter = ' ' | '\t' | '\n';
17
+ type Whitespace<In> = In extends `${WhitespaceCharacter}${infer In}`
18
+ ? Whitespace<In>
19
+ : In;
20
+
21
+ type MatchesWhitespaceAndString<
22
+ TString extends string,
23
+ T
24
+ > = Whitespace<T> extends `${TString}${string}` ? T : never;
25
+
26
+ export function iso<T>(
27
+ param: T & MatchesWhitespaceAndString<'field Query.meNameSuccessor', T>
28
+ ): IdentityWithParam<Query__meNameSuccessor__param>;
29
+
30
+ export function iso<T>(
31
+ param: T & MatchesWhitespaceAndString<'field Query.meName', T>
32
+ ): IdentityWithParam<Query__meName__param>;
33
+
34
+ export function iso<T>(
35
+ param: T & MatchesWhitespaceAndString<'field Query.nodeField', T>
36
+ ): IdentityWithParam<Query__nodeField__param>;
37
+
38
+ export function iso<T>(
39
+ param: T & MatchesWhitespaceAndString<'entrypoint Query.meNameSuccessor', T>
40
+ ): typeof entrypoint_Query__meNameSuccessor;
41
+
42
+ export function iso<T>(
43
+ param: T & MatchesWhitespaceAndString<'entrypoint Query.meName', T>
44
+ ): typeof entrypoint_Query__meName;
45
+
46
+ export function iso<T>(
47
+ param: T & MatchesWhitespaceAndString<'entrypoint Query.nodeField', T>
48
+ ): typeof entrypoint_Query__nodeField;
49
+
50
+ export function iso(_isographLiteralText: string):
51
+ | IdentityWithParam<any>
52
+ | IdentityWithParamComponent<any>
53
+ | IsographEntrypoint<any, any>
54
+ {
55
+ return function identity<TResolverReturn>(
56
+ clientFieldOrEntrypoint: (param: any) => TResolverReturn,
57
+ ): (param: any) => TResolverReturn {
58
+ return clientFieldOrEntrypoint;
59
+ };
60
+ }
@@ -0,0 +1,130 @@
1
+ import { describe, test, expect } from 'vitest';
2
+ import { ROOT_ID, createIsographEnvironment } from '../IsographEnvironment';
3
+ import { garbageCollectEnvironment, retainQuery } from '../garbageCollection';
4
+ import { iso } from './__isograph/iso';
5
+ import { nodeFieldRetainedQuery } from './nodeQuery';
6
+
7
+ const getDefaultStore = () => ({
8
+ [ROOT_ID]: {
9
+ me: { __link: '0' },
10
+ you: { __link: '1' },
11
+ node____id___0: {
12
+ __link: '0',
13
+ },
14
+ },
15
+ 0: {
16
+ __typename: 'Economist',
17
+ id: '0',
18
+ name: 'Jeremy Bentham',
19
+ successor: { __link: '1' },
20
+ },
21
+ 1: {
22
+ __typename: 'Economist',
23
+ id: '1',
24
+ name: 'John Stuart Mill',
25
+ predecessor: { __link: '0' },
26
+ successor: { __link: '2' },
27
+ },
28
+ 2: {
29
+ __typename: 'Economist',
30
+ id: '2',
31
+ name: 'Henry Sidgwick',
32
+ predecessor: { __link: '1' },
33
+ },
34
+ });
35
+
36
+ export const meNameField = iso(`
37
+ field Query.meName {
38
+ me {
39
+ name
40
+ }
41
+ }
42
+ `)(() => {});
43
+ import meNameEntrypoint from './__isograph/Query/meName/entrypoint';
44
+ import { meNameSuccessorRetainedQuery } from './meNameSuccessor';
45
+ iso(`entrypoint Query.meName`);
46
+ const meNameRetainedQuery = {
47
+ normalizationAst: meNameEntrypoint.normalizationAst,
48
+ variables: {},
49
+ };
50
+
51
+ describe('garbage collection', () => {
52
+ test('Unreferenced records should be garbage collected', () => {
53
+ const store = getDefaultStore();
54
+ const environment = createIsographEnvironment(
55
+ store,
56
+ null as any,
57
+ null as any,
58
+ );
59
+
60
+ expect(store[1]).not.toBe(undefined);
61
+
62
+ // TODO enable babel so we don't have to do this
63
+ retainQuery(environment, meNameRetainedQuery);
64
+ garbageCollectEnvironment(environment);
65
+
66
+ expect(store[1]).toBe(undefined);
67
+ });
68
+
69
+ test('Referenced records should not be garbage collected', () => {
70
+ const store = getDefaultStore();
71
+ const environment = createIsographEnvironment(
72
+ store,
73
+ null as any,
74
+ null as any,
75
+ );
76
+
77
+ expect(store[0]).not.toBe(undefined);
78
+
79
+ // TODO enable babel so we don't have to do this
80
+ retainQuery(environment, meNameRetainedQuery);
81
+ garbageCollectEnvironment(environment);
82
+
83
+ expect(store[0]).not.toBe(undefined);
84
+ });
85
+
86
+ test('Referenced records should not be garbage collected, and this should work with variables', () => {
87
+ const store = getDefaultStore();
88
+ const environment = createIsographEnvironment(
89
+ store,
90
+ null as any,
91
+ null as any,
92
+ );
93
+
94
+ expect(store[0]).not.toBe(undefined);
95
+
96
+ retainQuery(environment, nodeFieldRetainedQuery);
97
+ garbageCollectEnvironment(environment);
98
+
99
+ expect(store[0]).not.toBe(undefined);
100
+ });
101
+
102
+ test('Referenced records should not be garbage collected, and this should work through multiple levels', () => {
103
+ const store = getDefaultStore();
104
+ const environment = createIsographEnvironment(
105
+ store,
106
+ null as any,
107
+ null as any,
108
+ );
109
+
110
+ retainQuery(environment, meNameSuccessorRetainedQuery);
111
+ garbageCollectEnvironment(environment);
112
+
113
+ expect(store[0]).not.toBe(undefined);
114
+ expect(store[1]).not.toBe(undefined);
115
+ expect(store[2]).not.toBe(undefined);
116
+ });
117
+
118
+ test('ROOT_ID should not be garbage collected, even if there are no retained queries', () => {
119
+ const store = getDefaultStore();
120
+ const environment = createIsographEnvironment(
121
+ store,
122
+ null as any,
123
+ null as any,
124
+ );
125
+ garbageCollectEnvironment(environment);
126
+
127
+ expect(store[ROOT_ID]).not.toBe(undefined);
128
+ expect(store[0]).toBe(undefined);
129
+ });
130
+ });
@@ -0,0 +1,7 @@
1
+ {
2
+ "project_root": ".",
3
+ "schema": "./schema.graphql",
4
+ "options": {
5
+ "on_invalid_id_type": "error"
6
+ }
7
+ }
@@ -0,0 +1,20 @@
1
+ import { iso } from './__isograph/iso';
2
+
3
+ export const meNameField = iso(`
4
+ field Query.meNameSuccessor {
5
+ me {
6
+ name
7
+ successor {
8
+ successor {
9
+ name
10
+ }
11
+ }
12
+ }
13
+ }
14
+ `)(() => {});
15
+ import meNameSuccessorEntrypoint from './__isograph/Query/meNameSuccessor/entrypoint';
16
+ iso(`entrypoint Query.meNameSuccessor`);
17
+ export const meNameSuccessorRetainedQuery = {
18
+ normalizationAst: meNameSuccessorEntrypoint.normalizationAst,
19
+ variables: {},
20
+ };
@@ -0,0 +1,17 @@
1
+ import { iso } from './__isograph/iso';
2
+
3
+ // TODO investigate why this can't be in garbageCollection.test.ts without
4
+ // typescript incorrectly thinking it is referenced in its own initializer
5
+ export const nodeField = iso(`
6
+ field Query.nodeField($id: ID!) {
7
+ node(id: $id) {
8
+ id
9
+ }
10
+ }
11
+ `)(() => {});
12
+ import nodeFieldEntrypoint from './__isograph/Query/nodeField/entrypoint';
13
+ iso(`entrypoint Query.nodeField`);
14
+ export const nodeFieldRetainedQuery = {
15
+ normalizationAst: nodeFieldEntrypoint.normalizationAst,
16
+ variables: { id: 0 },
17
+ };
@@ -0,0 +1,16 @@
1
+ type Query {
2
+ me: Economist!
3
+ you: Economist!
4
+ node(id: ID!): Node
5
+ }
6
+
7
+ type Economist implements Node {
8
+ id: ID!
9
+ name: String!
10
+ predecessor: Economist
11
+ successor: Economist
12
+ }
13
+
14
+ interface Node {
15
+ id: ID!
16
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "es5",
4
+ "lib": ["dom", "dom.iterable", "esnext"],
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "esModuleInterop": true,
10
+ "module": "esnext",
11
+ "moduleResolution": "bundler",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "jsx": "preserve",
15
+ "incremental": true,
16
+ "allowImportingTsExtensions": true,
17
+ "paths": {
18
+ "@isograph/react": ["../index.ts"],
19
+ },
20
+ },
21
+ }
@@ -0,0 +1,15 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { DataId, IsographEnvironment } from './IsographEnvironment';
3
+ import { subscribe } from './cache';
4
+
5
+ export function useRerenderWhenEncounteredRecordChanges(
6
+ environment: IsographEnvironment,
7
+ encounteredRecords: Set<DataId>,
8
+ ) {
9
+ const [, setState] = useState<object | void>();
10
+ useEffect(() => {
11
+ return subscribe(environment, encounteredRecords, () => {
12
+ return setState({});
13
+ });
14
+ }, []);
15
+ }
package/src/useResult.ts CHANGED
@@ -1,20 +1,19 @@
1
- import { useEffect, useState } from 'react';
2
1
  import { useIsographEnvironment } from './IsographEnvironmentProvider';
3
- import { subscribe } from './cache';
4
2
  import { read } from './read';
5
3
  import { FragmentReference } from './FragmentReference';
4
+ import { useRerenderWhenEncounteredRecordChanges } from './useRerenderWhenEncounteredRecordChanges';
6
5
 
7
6
  export function useResult<TReadFromStore extends Object, TClientFieldValue>(
8
7
  fragmentReference: FragmentReference<TReadFromStore, TClientFieldValue>,
9
8
  ): TClientFieldValue {
10
9
  const environment = useIsographEnvironment();
11
10
 
12
- const [, setState] = useState<object | void>();
13
- useEffect(() => {
14
- return subscribe(environment, () => {
15
- return setState({});
16
- });
17
- }, []);
11
+ const { item: data, encounteredRecords } = read(
12
+ environment,
13
+ fragmentReference,
14
+ );
18
15
 
19
- return read(environment, fragmentReference);
16
+ useRerenderWhenEncounteredRecordChanges(environment, encounteredRecords);
17
+
18
+ return data;
20
19
  }
package/tsconfig.pkg.json CHANGED
@@ -7,5 +7,6 @@
7
7
  "jsx": "react",
8
8
  "lib": ["es2017", "DOM"]
9
9
  },
10
- "include": ["./**/*.ts", "./**/*.tsx"]
10
+ "include": ["./**/*.ts", "./**/*.tsx"],
11
+ "exclude": ["./src/tests/**/*"]
11
12
  }