houdini 0.13.6 → 0.13.7-alpha.0

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.
package/build/cmd.js CHANGED
File without changes
@@ -14,7 +14,7 @@ export declare class Cache {
14
14
  selection: SubscriptionSelection;
15
15
  variables?: {};
16
16
  parent?: string;
17
- layer?: LayerID;
17
+ layer?: LayerID | null;
18
18
  applyUpdates?: boolean;
19
19
  }): LayerID;
20
20
  read(...args: Parameters<CacheInternal['getSelection']>): {
@@ -210,7 +210,7 @@ var CacheInternal = /** @class */ (function () {
210
210
  // look up the previous value
211
211
  var _h = this_1.storage.get(parent, key), previousValue = _h.value, displayLayers = _h.displayLayers;
212
212
  // if the layer we are updating is the top most layer for the field
213
- // then its value is "live", it is providing the current value and
213
+ // then its value is "live". It is providing the current value and
214
214
  // subscribers need to know if the value changed
215
215
  var displayLayer = displayLayers.length === 0 || displayLayers.includes(layer.id);
216
216
  // if we are writing to the display layer we need to refresh the lifetime of the value
@@ -1,2 +1,5 @@
1
1
  import { Operation, GraphQLTagResult } from './types';
2
- export declare function mutation<_Mutation extends Operation<any, any>>(document: GraphQLTagResult): (_input: _Mutation['input']) => Promise<_Mutation['result']>;
2
+ export declare type MutationConfig<_Mutation extends Operation<any, any>> = {
3
+ optimisticResponse: _Mutation['result'];
4
+ };
5
+ export declare function mutation<_Mutation extends Operation<any, any>>(document: GraphQLTagResult): (_input: _Mutation['input'], config: MutationConfig<_Mutation>) => Promise<_Mutation['result']>;
@@ -62,30 +62,61 @@ function mutation(document) {
62
62
  // grab the session from the adapter
63
63
  var sessionStore = adapter_mjs_1.getSession();
64
64
  // return an async function that sends the mutation go the server
65
- return function (variables) { return __awaiter(_this, void 0, void 0, function () {
66
- var result, error_1;
65
+ return function (variables, mutationConfig) { return __awaiter(_this, void 0, void 0, function () {
66
+ var optimisticResponse, layer, result, error_1;
67
67
  return __generator(this, function (_a) {
68
68
  switch (_a.label) {
69
69
  case 0:
70
- _a.trys.push([0, 2, , 3]);
70
+ optimisticResponse = mutationConfig === null || mutationConfig === void 0 ? void 0 : mutationConfig.optimisticResponse;
71
+ layer = cache_1.default._internal_unstable.storage.createLayer(true);
72
+ // if there is an optimistic response then we need to write the value immediately
73
+ if (optimisticResponse) {
74
+ cache_1.default.write({
75
+ selection: artifact.selection,
76
+ // make sure that any scalar values get processed into something we can cache
77
+ data: scalars_1.marshalSelection({
78
+ config: config,
79
+ selection: artifact.selection,
80
+ data: optimisticResponse,
81
+ }),
82
+ variables: variables,
83
+ layer: layer.id,
84
+ });
85
+ }
86
+ _a.label = 1;
87
+ case 1:
88
+ _a.trys.push([1, 3, , 4]);
71
89
  return [4 /*yield*/, network_1.executeQuery(artifact, scalars_1.marshalInputs({
72
90
  input: variables,
73
91
  artifact: document.artifact,
74
92
  config: config,
75
- }), sessionStore, false)];
76
- case 1:
93
+ }), sessionStore, false)
94
+ // clear the layer holding any mutation results
95
+ ];
96
+ case 2:
77
97
  result = (_a.sent()).result;
98
+ // clear the layer holding any mutation results
99
+ layer.clear();
100
+ // write the result of the mutation to the cache
78
101
  cache_1.default.write({
79
102
  selection: artifact.selection,
80
103
  data: result.data,
81
104
  variables: variables,
105
+ // if we had an optimistic response we need to write to the appropriate layer
106
+ layer: layer.id,
82
107
  });
83
- // unmarshal any scalars on the body
108
+ // merge the layer back into the cache
109
+ cache_1.default._internal_unstable.storage.resolveLayer(layer.id);
110
+ // turn any scalars in the response into their complex form
84
111
  return [2 /*return*/, scalars_1.unmarshalSelection(config, artifact.selection, result.data)];
85
- case 2:
112
+ case 3:
86
113
  error_1 = _a.sent();
114
+ // if the mutation failed, roll the layer back and delete it
115
+ layer.clear();
116
+ cache_1.default._internal_unstable.storage.resolveLayer(layer.id);
117
+ // bubble the mutation error up to the caller
87
118
  throw error_1;
88
- case 3: return [2 /*return*/];
119
+ case 4: return [2 /*return*/];
89
120
  }
90
121
  });
91
122
  }); };
@@ -1,5 +1,10 @@
1
1
  import type { Config } from 'houdini-common';
2
2
  import { MutationArtifact, QueryArtifact, SubscriptionArtifact, SubscriptionSelection } from './types';
3
+ export declare function marshalSelection({ config, selection, data, }: {
4
+ config: Config;
5
+ selection: SubscriptionSelection;
6
+ data: unknown;
7
+ }): {} | null | undefined;
3
8
  export declare function marshalInputs<T>({ artifact, config, input, rootType, }: {
4
9
  artifact: QueryArtifact | MutationArtifact | SubscriptionArtifact;
5
10
  config: Config;
@@ -16,7 +16,49 @@ var __read = (this && this.__read) || function (o, n) {
16
16
  return ar;
17
17
  };
18
18
  Object.defineProperty(exports, "__esModule", { value: true });
19
- exports.isScalar = exports.unmarshalSelection = exports.marshalInputs = void 0;
19
+ exports.isScalar = exports.unmarshalSelection = exports.marshalInputs = exports.marshalSelection = void 0;
20
+ function marshalSelection(_a) {
21
+ var config = _a.config, selection = _a.selection, data = _a.data;
22
+ if (data === null || typeof data === 'undefined') {
23
+ return data;
24
+ }
25
+ // if we are looking at a list
26
+ if (Array.isArray(data)) {
27
+ // unmarshal every entry in the list
28
+ return data.map(function (val) { return marshalSelection({ config: config, selection: selection, data: val }); });
29
+ }
30
+ // we're looking at an object, build it up from the current input
31
+ return Object.fromEntries(Object.entries(data).map(function (_a) {
32
+ var _b;
33
+ var _c = __read(_a, 2), fieldName = _c[0], value = _c[1];
34
+ // look up the type for the field
35
+ var _d = selection[fieldName], type = _d.type, fields = _d.fields;
36
+ // if we don't have type information for this field, just use it directly
37
+ // it's most likely a non-custom scalars or enums
38
+ if (!type) {
39
+ return [fieldName, value];
40
+ }
41
+ // if there is a sub selection, walk down the selection
42
+ if (fields) {
43
+ return [fieldName, marshalSelection({ config: config, selection: fields, data: value })];
44
+ }
45
+ // is the type something that requires marshaling
46
+ if ((_b = config.scalars) === null || _b === void 0 ? void 0 : _b[type]) {
47
+ var marshalFn = config.scalars[type].marshal;
48
+ if (!marshalFn) {
49
+ throw new Error("scalar type " + type + " is missing a `marshal` function. see https://github.com/AlecAivazis/houdini#%EF%B8%8Fcustom-scalars");
50
+ }
51
+ if (Array.isArray(value)) {
52
+ return [fieldName, value.map(marshalFn)];
53
+ }
54
+ return [fieldName, marshalFn(value)];
55
+ }
56
+ // if the type doesn't require marshaling and isn't a referenced type
57
+ // then the type is a scalar that doesn't require marshaling
58
+ return [fieldName, value];
59
+ }));
60
+ }
61
+ exports.marshalSelection = marshalSelection;
20
62
  function marshalInputs(_a) {
21
63
  var artifact = _a.artifact, config = _a.config, input = _a.input, _b = _a.rootType, rootType = _b === void 0 ? '@root' : _b;
22
64
  if (input === null || typeof input === 'undefined') {
@@ -14,7 +14,7 @@ export declare class Cache {
14
14
  selection: SubscriptionSelection;
15
15
  variables?: {};
16
16
  parent?: string;
17
- layer?: LayerID;
17
+ layer?: LayerID | null;
18
18
  applyUpdates?: boolean;
19
19
  }): LayerID;
20
20
  read(...args: Parameters<CacheInternal['getSelection']>): {
@@ -210,7 +210,7 @@ var CacheInternal = /** @class */ (function () {
210
210
  // look up the previous value
211
211
  var _h = this_1.storage.get(parent, key), previousValue = _h.value, displayLayers = _h.displayLayers;
212
212
  // if the layer we are updating is the top most layer for the field
213
- // then its value is "live", it is providing the current value and
213
+ // then its value is "live". It is providing the current value and
214
214
  // subscribers need to know if the value changed
215
215
  var displayLayer = displayLayers.length === 0 || displayLayers.includes(layer.id);
216
216
  // if we are writing to the display layer we need to refresh the lifetime of the value
@@ -1,2 +1,5 @@
1
1
  import { Operation, GraphQLTagResult } from './types';
2
- export declare function mutation<_Mutation extends Operation<any, any>>(document: GraphQLTagResult): (_input: _Mutation['input']) => Promise<_Mutation['result']>;
2
+ export declare type MutationConfig<_Mutation extends Operation<any, any>> = {
3
+ optimisticResponse: _Mutation['result'];
4
+ };
5
+ export declare function mutation<_Mutation extends Operation<any, any>>(document: GraphQLTagResult): (_input: _Mutation['input'], config: MutationConfig<_Mutation>) => Promise<_Mutation['result']>;
@@ -62,30 +62,61 @@ function mutation(document) {
62
62
  // grab the session from the adapter
63
63
  var sessionStore = adapter_mjs_1.getSession();
64
64
  // return an async function that sends the mutation go the server
65
- return function (variables) { return __awaiter(_this, void 0, void 0, function () {
66
- var result, error_1;
65
+ return function (variables, mutationConfig) { return __awaiter(_this, void 0, void 0, function () {
66
+ var optimisticResponse, layer, result, error_1;
67
67
  return __generator(this, function (_a) {
68
68
  switch (_a.label) {
69
69
  case 0:
70
- _a.trys.push([0, 2, , 3]);
70
+ optimisticResponse = mutationConfig === null || mutationConfig === void 0 ? void 0 : mutationConfig.optimisticResponse;
71
+ layer = cache_1.default._internal_unstable.storage.createLayer(true);
72
+ // if there is an optimistic response then we need to write the value immediately
73
+ if (optimisticResponse) {
74
+ cache_1.default.write({
75
+ selection: artifact.selection,
76
+ // make sure that any scalar values get processed into something we can cache
77
+ data: scalars_1.marshalSelection({
78
+ config: config,
79
+ selection: artifact.selection,
80
+ data: optimisticResponse,
81
+ }),
82
+ variables: variables,
83
+ layer: layer.id,
84
+ });
85
+ }
86
+ _a.label = 1;
87
+ case 1:
88
+ _a.trys.push([1, 3, , 4]);
71
89
  return [4 /*yield*/, network_1.executeQuery(artifact, scalars_1.marshalInputs({
72
90
  input: variables,
73
91
  artifact: document.artifact,
74
92
  config: config,
75
- }), sessionStore, false)];
76
- case 1:
93
+ }), sessionStore, false)
94
+ // clear the layer holding any mutation results
95
+ ];
96
+ case 2:
77
97
  result = (_a.sent()).result;
98
+ // clear the layer holding any mutation results
99
+ layer.clear();
100
+ // write the result of the mutation to the cache
78
101
  cache_1.default.write({
79
102
  selection: artifact.selection,
80
103
  data: result.data,
81
104
  variables: variables,
105
+ // if we had an optimistic response we need to write to the appropriate layer
106
+ layer: layer.id,
82
107
  });
83
- // unmarshal any scalars on the body
108
+ // merge the layer back into the cache
109
+ cache_1.default._internal_unstable.storage.resolveLayer(layer.id);
110
+ // turn any scalars in the response into their complex form
84
111
  return [2 /*return*/, scalars_1.unmarshalSelection(config, artifact.selection, result.data)];
85
- case 2:
112
+ case 3:
86
113
  error_1 = _a.sent();
114
+ // if the mutation failed, roll the layer back and delete it
115
+ layer.clear();
116
+ cache_1.default._internal_unstable.storage.resolveLayer(layer.id);
117
+ // bubble the mutation error up to the caller
87
118
  throw error_1;
88
- case 3: return [2 /*return*/];
119
+ case 4: return [2 /*return*/];
89
120
  }
90
121
  });
91
122
  }); };
@@ -1,5 +1,10 @@
1
1
  import type { Config } from 'houdini-common';
2
2
  import { MutationArtifact, QueryArtifact, SubscriptionArtifact, SubscriptionSelection } from './types';
3
+ export declare function marshalSelection({ config, selection, data, }: {
4
+ config: Config;
5
+ selection: SubscriptionSelection;
6
+ data: unknown;
7
+ }): {} | null | undefined;
3
8
  export declare function marshalInputs<T>({ artifact, config, input, rootType, }: {
4
9
  artifact: QueryArtifact | MutationArtifact | SubscriptionArtifact;
5
10
  config: Config;
@@ -16,7 +16,49 @@ var __read = (this && this.__read) || function (o, n) {
16
16
  return ar;
17
17
  };
18
18
  Object.defineProperty(exports, "__esModule", { value: true });
19
- exports.isScalar = exports.unmarshalSelection = exports.marshalInputs = void 0;
19
+ exports.isScalar = exports.unmarshalSelection = exports.marshalInputs = exports.marshalSelection = void 0;
20
+ function marshalSelection(_a) {
21
+ var config = _a.config, selection = _a.selection, data = _a.data;
22
+ if (data === null || typeof data === 'undefined') {
23
+ return data;
24
+ }
25
+ // if we are looking at a list
26
+ if (Array.isArray(data)) {
27
+ // unmarshal every entry in the list
28
+ return data.map(function (val) { return marshalSelection({ config: config, selection: selection, data: val }); });
29
+ }
30
+ // we're looking at an object, build it up from the current input
31
+ return Object.fromEntries(Object.entries(data).map(function (_a) {
32
+ var _b;
33
+ var _c = __read(_a, 2), fieldName = _c[0], value = _c[1];
34
+ // look up the type for the field
35
+ var _d = selection[fieldName], type = _d.type, fields = _d.fields;
36
+ // if we don't have type information for this field, just use it directly
37
+ // it's most likely a non-custom scalars or enums
38
+ if (!type) {
39
+ return [fieldName, value];
40
+ }
41
+ // if there is a sub selection, walk down the selection
42
+ if (fields) {
43
+ return [fieldName, marshalSelection({ config: config, selection: fields, data: value })];
44
+ }
45
+ // is the type something that requires marshaling
46
+ if ((_b = config.scalars) === null || _b === void 0 ? void 0 : _b[type]) {
47
+ var marshalFn = config.scalars[type].marshal;
48
+ if (!marshalFn) {
49
+ throw new Error("scalar type " + type + " is missing a `marshal` function. see https://github.com/AlecAivazis/houdini#%EF%B8%8Fcustom-scalars");
50
+ }
51
+ if (Array.isArray(value)) {
52
+ return [fieldName, value.map(marshalFn)];
53
+ }
54
+ return [fieldName, marshalFn(value)];
55
+ }
56
+ // if the type doesn't require marshaling and isn't a referenced type
57
+ // then the type is a scalar that doesn't require marshaling
58
+ return [fieldName, value];
59
+ }));
60
+ }
61
+ exports.marshalSelection = marshalSelection;
20
62
  function marshalInputs(_a) {
21
63
  var artifact = _a.artifact, config = _a.config, input = _a.input, _b = _a.rootType, rootType = _b === void 0 ? '@root' : _b;
22
64
  if (input === null || typeof input === 'undefined') {
@@ -14,7 +14,7 @@ export declare class Cache {
14
14
  selection: SubscriptionSelection;
15
15
  variables?: {};
16
16
  parent?: string;
17
- layer?: LayerID;
17
+ layer?: LayerID | null;
18
18
  applyUpdates?: boolean;
19
19
  }): LayerID;
20
20
  read(...args: Parameters<CacheInternal['getSelection']>): {
@@ -129,7 +129,7 @@ class CacheInternal {
129
129
  // look up the previous value
130
130
  const { value: previousValue, displayLayers } = this.storage.get(parent, key);
131
131
  // if the layer we are updating is the top most layer for the field
132
- // then its value is "live", it is providing the current value and
132
+ // then its value is "live". It is providing the current value and
133
133
  // subscribers need to know if the value changed
134
134
  const displayLayer = displayLayers.length === 0 || displayLayers.includes(layer.id);
135
135
  // if we are writing to the display layer we need to refresh the lifetime of the value
@@ -0,0 +1,35 @@
1
+ import { SubscriptionSelection, ListWhen, SubscriptionSpec } from '../types';
2
+ import { Cache } from './cache';
3
+ import { Record } from './record';
4
+ export declare class ListHandler {
5
+ readonly record: Record;
6
+ readonly key: string;
7
+ readonly listType: string;
8
+ private cache;
9
+ readonly selection: SubscriptionSelection;
10
+ private _when?;
11
+ private filters?;
12
+ readonly name: string;
13
+ readonly parentID: SubscriptionSpec['parentID'];
14
+ private connection;
15
+ constructor({ name, cache, record, key, listType, selection, when, filters, parentID, connection, }: {
16
+ name: string;
17
+ connection: boolean;
18
+ cache: Cache;
19
+ record: Record;
20
+ key: string;
21
+ listType: string;
22
+ selection: SubscriptionSelection;
23
+ when?: ListWhen;
24
+ filters?: ListHandler['filters'];
25
+ parentID?: SubscriptionSpec['parentID'];
26
+ });
27
+ when(when?: ListWhen): ListHandler;
28
+ append(selection: SubscriptionSelection, data: {}, variables?: {}): void;
29
+ prepend(selection: SubscriptionSelection, data: {}, variables?: {}): void;
30
+ addToList(selection: SubscriptionSelection, data: {}, variables: {}, where: 'first' | 'last'): void;
31
+ removeID(id: string, variables?: {}): void;
32
+ remove(data: {}, variables?: {}): void;
33
+ private validateWhen;
34
+ [Symbol.iterator](): Generator<Record, void, unknown>;
35
+ }
@@ -0,0 +1,203 @@
1
+ export class ListHandler {
2
+ constructor({ name, cache, record, key, listType, selection, when, filters, parentID, connection, }) {
3
+ this.record = record;
4
+ this.key = key;
5
+ this.listType = listType;
6
+ this.cache = cache;
7
+ this.selection = selection;
8
+ this._when = when;
9
+ this.filters = filters;
10
+ this.name = name;
11
+ this.parentID = parentID;
12
+ this.connection = connection;
13
+ }
14
+ // when applies a when condition to a new list pointing to the same spot
15
+ when(when) {
16
+ return new ListHandler({
17
+ cache: this.cache,
18
+ record: this.record,
19
+ key: this.key,
20
+ listType: this.listType,
21
+ selection: this.selection,
22
+ when,
23
+ filters: this.filters,
24
+ parentID: this.parentID,
25
+ name: this.name,
26
+ connection: this.connection,
27
+ });
28
+ }
29
+ append(selection, data, variables = {}) {
30
+ return this.addToList(selection, data, variables, 'last');
31
+ }
32
+ prepend(selection, data, variables = {}) {
33
+ return this.addToList(selection, data, variables, 'first');
34
+ }
35
+ addToList(selection, data, variables = {}, where) {
36
+ // figure out the id of the type we are adding
37
+ const dataID = this.cache.id(this.listType, data);
38
+ // if there are conditions for this operation
39
+ if (!this.validateWhen() || !dataID) {
40
+ return;
41
+ }
42
+ // we are going to implement the insert as a write with an update flag on a field
43
+ // that matches the key of the list. We'll have to embed the lists data and selection
44
+ // in the appropriate objects
45
+ let insertSelection = selection;
46
+ let insertData = data;
47
+ // if we are wrapping a connection, we have to embed the data under edges > node
48
+ if (this.connection) {
49
+ insertSelection = {
50
+ newEntry: {
51
+ keyRaw: this.key,
52
+ type: 'Connection',
53
+ fields: {
54
+ edges: {
55
+ keyRaw: 'edges',
56
+ type: 'ConnectionEdge',
57
+ update: (where === 'first' ? 'prepend' : 'append'),
58
+ fields: {
59
+ node: {
60
+ type: this.listType,
61
+ keyRaw: 'node',
62
+ fields: {
63
+ ...selection,
64
+ __typename: {
65
+ keyRaw: '__typename',
66
+ type: 'String',
67
+ },
68
+ },
69
+ },
70
+ },
71
+ },
72
+ },
73
+ },
74
+ };
75
+ insertData = {
76
+ newEntry: {
77
+ edges: [{ node: { ...data, __typename: this.listType } }],
78
+ },
79
+ };
80
+ }
81
+ else {
82
+ insertSelection = {
83
+ newEntries: {
84
+ keyRaw: this.key,
85
+ type: this.listType,
86
+ update: (where === 'first' ? 'prepend' : 'append'),
87
+ fields: {
88
+ ...selection,
89
+ __typename: {
90
+ keyRaw: '__typename',
91
+ type: 'String',
92
+ },
93
+ },
94
+ },
95
+ };
96
+ insertData = {
97
+ newEntries: [{ ...data, __typename: this.listType }],
98
+ };
99
+ }
100
+ // get the list of specs that are subscribing to the list
101
+ const subscribers = this.record.getSubscribers(this.key);
102
+ // look up the new record in the cache
103
+ const newRecord = this.cache.internal.record(dataID);
104
+ // walk down the list fields relative to the new record
105
+ // and make sure all of the list's subscribers are listening
106
+ // to that object
107
+ this.cache.internal.insertSubscribers(newRecord, selection, variables, ...subscribers);
108
+ // update the cache with the data we just found
109
+ this.cache.write({
110
+ selection: insertSelection,
111
+ data: insertData,
112
+ variables,
113
+ parent: this.record.id,
114
+ applyUpdates: true,
115
+ });
116
+ }
117
+ removeID(id, variables = {}) {
118
+ // if there are conditions for this operation
119
+ if (!this.validateWhen()) {
120
+ return;
121
+ }
122
+ // if we are removing from a connection, the id we are removing from
123
+ // has to be computed
124
+ let parentID = this.record.id;
125
+ let targetID = id;
126
+ let targetKey = this.key;
127
+ // if we are removing a record from a connection we have to walk through
128
+ // some embedded references first
129
+ if (this.connection) {
130
+ const embeddedConnection = this.record.linkedRecord(this.key);
131
+ if (!embeddedConnection) {
132
+ return;
133
+ }
134
+ // look at every embedded edge for the one with a node corresponding to the element
135
+ // we want to delete
136
+ for (const edge of embeddedConnection.flatLinkedList('edges') || []) {
137
+ if (!edge) {
138
+ continue;
139
+ }
140
+ // look at the edge's node
141
+ const node = edge.linkedRecord('node');
142
+ if (!node) {
143
+ continue;
144
+ }
145
+ // if we found the node
146
+ if (node.id === id) {
147
+ targetID = edge.id;
148
+ }
149
+ }
150
+ parentID = embeddedConnection.id;
151
+ targetKey = 'edges';
152
+ }
153
+ // get the list of specs that are subscribing to the list
154
+ const subscribers = this.record.getSubscribers(this.key);
155
+ // disconnect record from any subscriptions associated with the list
156
+ this.cache.internal.unsubscribeSelection(this.cache.internal.record(targetID),
157
+ // if we're unsubscribing from a connection, only unsubscribe from the target
158
+ this.connection ? this.selection.edges.fields : this.selection, variables, ...subscribers.map(({ set }) => set));
159
+ // remove the target from the parent
160
+ this.cache.internal.record(parentID).removeFromLinkedList(targetKey, targetID);
161
+ // notify the subscribers about the change
162
+ this.cache.internal.notifySubscribers(subscribers, variables);
163
+ // if we are removing from a connection, delete the embedded edge holding the record
164
+ if (this.connection) {
165
+ this.cache.internal.deleteID(targetID);
166
+ }
167
+ }
168
+ remove(data, variables = {}) {
169
+ const targetID = this.cache.id(this.listType, data);
170
+ if (!targetID) {
171
+ return;
172
+ }
173
+ // figure out the id of the type we are adding
174
+ this.removeID(targetID, variables);
175
+ }
176
+ validateWhen() {
177
+ // if this when doesn't apply, we should look at others to see if we should update those behind the scenes
178
+ let ok = true;
179
+ // if there are conditions for this operation
180
+ if (this._when) {
181
+ // we only NEED there to be target filters for must's
182
+ const targets = this.filters;
183
+ // check must's first
184
+ if (this._when.must && targets) {
185
+ ok = Object.entries(this._when.must).reduce((prev, [key, value]) => Boolean(prev && targets[key] == value), ok);
186
+ }
187
+ // if there are no targets, nothing could be true that can we compare against
188
+ if (this._when.must_not) {
189
+ ok =
190
+ !targets ||
191
+ Object.entries(this._when.must_not).reduce((prev, [key, value]) => Boolean(prev && targets[key] != value), ok);
192
+ }
193
+ }
194
+ return ok;
195
+ }
196
+ // iterating over the list handler should be the same as iterating over
197
+ // the underlying linked list
198
+ *[Symbol.iterator]() {
199
+ for (let record of this.record.flatLinkedList(this.key)) {
200
+ yield record;
201
+ }
202
+ }
203
+ }
@@ -0,0 +1,40 @@
1
+ import { GraphQLValue, Maybe, SubscriptionSpec } from '../types';
2
+ import { Cache, LinkedList } from './cache';
3
+ export declare class Record {
4
+ fields: {
5
+ [key: string]: GraphQLValue;
6
+ };
7
+ keyVersions: {
8
+ [key: string]: Set<string>;
9
+ };
10
+ readonly id: string;
11
+ private subscribers;
12
+ private recordLinks;
13
+ listLinks: {
14
+ [key: string]: LinkedList;
15
+ };
16
+ private cache;
17
+ private referenceCounts;
18
+ private lifetimes;
19
+ constructor(cache: Cache, id: string);
20
+ allSubscribers(): SubscriptionSpec[];
21
+ getField(fieldName: string): GraphQLValue;
22
+ writeField(fieldName: string, value: GraphQLValue): void;
23
+ writeRecordLink(fieldName: string, value: string | null): void;
24
+ writeListLink(fieldName: string, value: LinkedList): void;
25
+ linkedRecord(fieldName: string): Record;
26
+ linkedRecordID(fieldName: string): string;
27
+ linkedListIDs(fieldName: string): (string | null)[];
28
+ flatLinkedList(fieldName: string): Maybe<Record>[];
29
+ appendLinkedList(fieldName: string, id: string): void;
30
+ prependLinkedList(fieldName: string, id: string): void;
31
+ removeFromLinkedList(fieldName: string, id: string): void;
32
+ addSubscriber(rawKey: string, key: string, ...specs: SubscriptionSpec[]): void;
33
+ getSubscribers(fieldName: string): SubscriptionSpec[];
34
+ forgetSubscribers(...targets: SubscriptionSpec[]): void;
35
+ removeAllSubscribers(): void;
36
+ removeAllSubscriptionVersions(keyRaw: string, spec: SubscriptionSpec): void;
37
+ private forgetSubscribers_walk;
38
+ removeSubscribers(fields: string[], sets: SubscriptionSpec['set'][]): void;
39
+ onGcTick(): void;
40
+ }