@salesforce/lds-adapters-graphql 1.124.1 → 1.124.3
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/dist/es/es2018/graphql-service.js +2098 -2098
- package/dist/{types → es/es2018/types}/src/__mocks__/@salesforce/lds-adapters-uiapi/sfdc/graphqlAdapters.d.ts +1 -1
- package/dist/{types → es/es2018/types}/src/configuration.d.ts +9 -9
- package/dist/{types → es/es2018/types}/src/custom/connection.d.ts +17 -17
- package/dist/{types → es/es2018/types}/src/custom/record.d.ts +46 -46
- package/dist/{types → es/es2018/types}/src/main.d.ts +20 -20
- package/dist/{types → es/es2018/types}/src/sfdc.d.ts +5 -5
- package/dist/{types → es/es2018/types}/src/type/Argument.d.ts +10 -10
- package/dist/{types → es/es2018/types}/src/type/CustomField.d.ts +4 -4
- package/dist/{types → es/es2018/types}/src/type/Document.d.ts +11 -11
- package/dist/{types → es/es2018/types}/src/type/Field.d.ts +4 -4
- package/dist/{types → es/es2018/types}/src/type/ObjectField.d.ts +2 -2
- package/dist/{types → es/es2018/types}/src/type/Operation.d.ts +5 -5
- package/dist/{types → es/es2018/types}/src/type/ScalarField.d.ts +2 -2
- package/dist/{types → es/es2018/types}/src/type/Selection.d.ts +23 -23
- package/dist/{types → es/es2018/types}/src/type/Variable.d.ts +4 -4
- package/dist/{types → es/es2018/types}/src/util/adapter.d.ts +16 -16
- package/dist/{types → es/es2018/types}/src/util/ast-to-string.d.ts +7 -7
- package/dist/{types → es/es2018/types}/src/util/equal.d.ts +7 -7
- package/dist/{types → es/es2018/types}/src/util/ingest.d.ts +18 -18
- package/dist/{types → es/es2018/types}/src/util/language.d.ts +20 -20
- package/dist/{types → es/es2018/types}/src/util/merge.d.ts +1 -1
- package/dist/{types → es/es2018/types}/src/util/read.d.ts +4 -4
- package/dist/{types → es/es2018/types}/src/util/serialize.d.ts +12 -12
- package/dist/{types → es/es2018/types}/src/util/sortUsingKey.d.ts +1 -1
- package/dist/{types → es/es2018/types}/src/util/synthetic-fields.d.ts +15 -15
- package/package.json +5 -5
- package/sfdc/index.d.ts +1 -1
- package/sfdc/index.js +2112 -2112
- package/dist/umd/es2018/graphql-service.js +0 -2164
- package/dist/umd/es5/graphql-service.js +0 -2182
package/sfdc/index.js
CHANGED
|
@@ -19,2162 +19,2162 @@ import { astResolver } from 'force/ldsGraphqlParser';
|
|
|
19
19
|
import { graphqlAdapterFactory } from 'force/ldsAdaptersUiapiGraphql';
|
|
20
20
|
import { createIngestRecordWithFields, keyBuilderRecord } from 'force/ldsAdaptersUiapi';
|
|
21
21
|
|
|
22
|
-
const { isArray } = Array;
|
|
23
|
-
const { keys, freeze, create } = Object;
|
|
24
|
-
const { hasOwnProperty } = Object.prototype;
|
|
22
|
+
const { isArray } = Array;
|
|
23
|
+
const { keys, freeze, create } = Object;
|
|
24
|
+
const { hasOwnProperty } = Object.prototype;
|
|
25
25
|
const { parse, stringify } = JSON;
|
|
26
26
|
|
|
27
|
-
function sortAndCopyUsingObjectKey(arr, key) {
|
|
28
|
-
return [...arr].sort((a, b) => {
|
|
29
|
-
const aKey = a[key];
|
|
30
|
-
const bKey = b[key];
|
|
31
|
-
if (aKey < bKey) {
|
|
32
|
-
return -1;
|
|
33
|
-
}
|
|
34
|
-
if (aKey > bKey) {
|
|
35
|
-
return 1;
|
|
36
|
-
}
|
|
37
|
-
return 0;
|
|
38
|
-
});
|
|
27
|
+
function sortAndCopyUsingObjectKey(arr, key) {
|
|
28
|
+
return [...arr].sort((a, b) => {
|
|
29
|
+
const aKey = a[key];
|
|
30
|
+
const bKey = b[key];
|
|
31
|
+
if (aKey < bKey) {
|
|
32
|
+
return -1;
|
|
33
|
+
}
|
|
34
|
+
if (aKey > bKey) {
|
|
35
|
+
return 1;
|
|
36
|
+
}
|
|
37
|
+
return 0;
|
|
38
|
+
});
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
function untrustedIsObject(untrusted) {
|
|
42
|
-
return typeof untrusted === 'object' && untrusted !== null && isArray(untrusted) === false;
|
|
43
|
-
}
|
|
44
|
-
function deepFreeze(value) {
|
|
45
|
-
// No need to freeze primitives
|
|
46
|
-
if (typeof value !== 'object' || value === null) {
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
if (isArray(value)) {
|
|
50
|
-
for (let i = 0, len = value.length; i < len; i += 1) {
|
|
51
|
-
deepFreeze(value[i]);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
else {
|
|
55
|
-
const keys$1 = keys(value);
|
|
56
|
-
for (let i = 0, len = keys$1.length; i < len; i += 1) {
|
|
57
|
-
const v = value[keys$1[i]];
|
|
58
|
-
deepFreeze(v);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return freeze(value);
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* A deterministic JSON stringify implementation. Heavily adapted from https://github.com/epoberezkin/fast-json-stable-stringify.
|
|
65
|
-
* This is needed because insertion order for JSON.stringify(object) affects output:
|
|
66
|
-
* JSON.stringify({a: 1, b: 2})
|
|
67
|
-
* "{"a":1,"b":2}"
|
|
68
|
-
* JSON.stringify({b: 2, a: 1})
|
|
69
|
-
* "{"b":2,"a":1}"
|
|
70
|
-
* @param data Data to be JSON-stringified.
|
|
71
|
-
* @returns JSON.stringified value with consistent ordering of keys.
|
|
72
|
-
*/
|
|
73
|
-
function stableJSONStringify(node) {
|
|
74
|
-
// This is for Date values.
|
|
75
|
-
if (node && node.toJSON && typeof node.toJSON === 'function') {
|
|
76
|
-
// eslint-disable-next-line no-param-reassign
|
|
77
|
-
node = node.toJSON();
|
|
78
|
-
}
|
|
79
|
-
if (node === undefined) {
|
|
80
|
-
return '';
|
|
81
|
-
}
|
|
82
|
-
if (typeof node === 'number') {
|
|
83
|
-
return isFinite(node) ? '' + node : 'null';
|
|
84
|
-
}
|
|
85
|
-
if (typeof node !== 'object') {
|
|
86
|
-
return stringify(node);
|
|
87
|
-
}
|
|
88
|
-
let i;
|
|
89
|
-
let out;
|
|
90
|
-
if (isArray(node)) {
|
|
91
|
-
node.sort();
|
|
92
|
-
out = '[';
|
|
93
|
-
for (i = 0; i < node.length; i++) {
|
|
94
|
-
if (i) {
|
|
95
|
-
out += ',';
|
|
96
|
-
}
|
|
97
|
-
out += stableJSONStringify(node[i]) || 'null';
|
|
98
|
-
}
|
|
99
|
-
return out + ']';
|
|
100
|
-
}
|
|
101
|
-
if (node === null) {
|
|
102
|
-
return 'null';
|
|
103
|
-
}
|
|
104
|
-
const keys$1 = keys(node).sort();
|
|
105
|
-
out = '';
|
|
106
|
-
for (i = 0; i < keys$1.length; i++) {
|
|
107
|
-
const key = keys$1[i];
|
|
108
|
-
const value = stableJSONStringify(node[key]);
|
|
109
|
-
if (!value) {
|
|
110
|
-
continue;
|
|
111
|
-
}
|
|
112
|
-
if (out) {
|
|
113
|
-
out += ',';
|
|
114
|
-
}
|
|
115
|
-
out += key + ':' + value;
|
|
116
|
-
}
|
|
117
|
-
return '{' + out + '}';
|
|
118
|
-
}
|
|
119
|
-
const namespace = 'GraphQL';
|
|
41
|
+
function untrustedIsObject(untrusted) {
|
|
42
|
+
return typeof untrusted === 'object' && untrusted !== null && isArray(untrusted) === false;
|
|
43
|
+
}
|
|
44
|
+
function deepFreeze(value) {
|
|
45
|
+
// No need to freeze primitives
|
|
46
|
+
if (typeof value !== 'object' || value === null) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (isArray(value)) {
|
|
50
|
+
for (let i = 0, len = value.length; i < len; i += 1) {
|
|
51
|
+
deepFreeze(value[i]);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
const keys$1 = keys(value);
|
|
56
|
+
for (let i = 0, len = keys$1.length; i < len; i += 1) {
|
|
57
|
+
const v = value[keys$1[i]];
|
|
58
|
+
deepFreeze(v);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return freeze(value);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* A deterministic JSON stringify implementation. Heavily adapted from https://github.com/epoberezkin/fast-json-stable-stringify.
|
|
65
|
+
* This is needed because insertion order for JSON.stringify(object) affects output:
|
|
66
|
+
* JSON.stringify({a: 1, b: 2})
|
|
67
|
+
* "{"a":1,"b":2}"
|
|
68
|
+
* JSON.stringify({b: 2, a: 1})
|
|
69
|
+
* "{"b":2,"a":1}"
|
|
70
|
+
* @param data Data to be JSON-stringified.
|
|
71
|
+
* @returns JSON.stringified value with consistent ordering of keys.
|
|
72
|
+
*/
|
|
73
|
+
function stableJSONStringify(node) {
|
|
74
|
+
// This is for Date values.
|
|
75
|
+
if (node && node.toJSON && typeof node.toJSON === 'function') {
|
|
76
|
+
// eslint-disable-next-line no-param-reassign
|
|
77
|
+
node = node.toJSON();
|
|
78
|
+
}
|
|
79
|
+
if (node === undefined) {
|
|
80
|
+
return '';
|
|
81
|
+
}
|
|
82
|
+
if (typeof node === 'number') {
|
|
83
|
+
return isFinite(node) ? '' + node : 'null';
|
|
84
|
+
}
|
|
85
|
+
if (typeof node !== 'object') {
|
|
86
|
+
return stringify(node);
|
|
87
|
+
}
|
|
88
|
+
let i;
|
|
89
|
+
let out;
|
|
90
|
+
if (isArray(node)) {
|
|
91
|
+
node.sort();
|
|
92
|
+
out = '[';
|
|
93
|
+
for (i = 0; i < node.length; i++) {
|
|
94
|
+
if (i) {
|
|
95
|
+
out += ',';
|
|
96
|
+
}
|
|
97
|
+
out += stableJSONStringify(node[i]) || 'null';
|
|
98
|
+
}
|
|
99
|
+
return out + ']';
|
|
100
|
+
}
|
|
101
|
+
if (node === null) {
|
|
102
|
+
return 'null';
|
|
103
|
+
}
|
|
104
|
+
const keys$1 = keys(node).sort();
|
|
105
|
+
out = '';
|
|
106
|
+
for (i = 0; i < keys$1.length; i++) {
|
|
107
|
+
const key = keys$1[i];
|
|
108
|
+
const value = stableJSONStringify(node[key]);
|
|
109
|
+
if (!value) {
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
if (out) {
|
|
113
|
+
out += ',';
|
|
114
|
+
}
|
|
115
|
+
out += key + ':' + value;
|
|
116
|
+
}
|
|
117
|
+
return '{' + out + '}';
|
|
118
|
+
}
|
|
119
|
+
const namespace = 'GraphQL';
|
|
120
120
|
const representationName = 'graphql';
|
|
121
121
|
|
|
122
|
-
function serialize$1(args) {
|
|
123
|
-
return serializeArgs(args, { render: false });
|
|
124
|
-
}
|
|
125
|
-
function render$1(args, variables) {
|
|
126
|
-
return serializeArgs(args, { render: true, variables });
|
|
127
|
-
}
|
|
128
|
-
function serializeArgs(args, option) {
|
|
129
|
-
const sortedArgs = option.render === true ? sortAndCopyUsingObjectKey(args, 'name') : args;
|
|
130
|
-
let str = '';
|
|
131
|
-
for (let i = 0, len = sortedArgs.length; i < len; i += 1) {
|
|
132
|
-
str = `${str}${serializeArgumentNode(sortedArgs[i], option)}`;
|
|
133
|
-
if (len > 1 && i < len - 1) {
|
|
134
|
-
str = `${str},`;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
return str;
|
|
138
|
-
}
|
|
139
|
-
function serializeArgumentValueNode(valueDefinition, option) {
|
|
140
|
-
const { kind } = valueDefinition;
|
|
141
|
-
switch (kind) {
|
|
142
|
-
case 'ObjectValue':
|
|
143
|
-
return serializeAndSortObjectValueNode(valueDefinition, option);
|
|
144
|
-
case 'ListValue':
|
|
145
|
-
return serializeAndSortListValueNode(valueDefinition, option);
|
|
146
|
-
case 'Variable':
|
|
147
|
-
return serializeVariableNode$1(valueDefinition, option);
|
|
148
|
-
default:
|
|
149
|
-
return serializeValueNode(valueDefinition);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
function serializeVariableNode$1(literalValueNode, option) {
|
|
153
|
-
if (option.render === false) {
|
|
154
|
-
return `$${literalValueNode.name}`;
|
|
155
|
-
}
|
|
156
|
-
return `${serializeVariableValue(option.variables[literalValueNode.name])}`;
|
|
157
|
-
}
|
|
158
|
-
function serializeVariableValue(value) {
|
|
159
|
-
return stableJSONStringify(value);
|
|
160
|
-
}
|
|
161
|
-
function serializeAndSortListValueNode(objectValueDefinition, option) {
|
|
162
|
-
const { values } = objectValueDefinition;
|
|
163
|
-
const str = [];
|
|
164
|
-
const sorted = option.render === true ? sortAndCopyUsingObjectKey(values, 'value') : values;
|
|
165
|
-
for (let i = 0, len = sorted.length; i < len; i += 1) {
|
|
166
|
-
str.push(serializeArgumentValueNode(sorted[i], option));
|
|
167
|
-
}
|
|
168
|
-
return `[${str.join(',')}]`;
|
|
169
|
-
}
|
|
170
|
-
function serializeAndSortObjectValueNode(objectValueDefinition, option) {
|
|
171
|
-
const { fields } = objectValueDefinition;
|
|
172
|
-
let str = '';
|
|
173
|
-
const fieldKeys = keys(fields).sort();
|
|
174
|
-
for (let i = 0, len = fieldKeys.length; i < len; i += 1) {
|
|
175
|
-
const fieldKey = fieldKeys[i];
|
|
176
|
-
str = `${str}${fieldKey}:${serializeArgumentValueNode(fields[fieldKey], option)}`;
|
|
177
|
-
if (len > 1 && i < len - 1) {
|
|
178
|
-
str = `${str},`;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
return `{${str}}`;
|
|
182
|
-
}
|
|
183
|
-
function serializeArgumentNode(arg, option) {
|
|
184
|
-
const { name, value } = arg;
|
|
185
|
-
return `${name}:${serializeArgumentValueNode(value, option)}`;
|
|
122
|
+
function serialize$1(args) {
|
|
123
|
+
return serializeArgs(args, { render: false });
|
|
124
|
+
}
|
|
125
|
+
function render$1(args, variables) {
|
|
126
|
+
return serializeArgs(args, { render: true, variables });
|
|
127
|
+
}
|
|
128
|
+
function serializeArgs(args, option) {
|
|
129
|
+
const sortedArgs = option.render === true ? sortAndCopyUsingObjectKey(args, 'name') : args;
|
|
130
|
+
let str = '';
|
|
131
|
+
for (let i = 0, len = sortedArgs.length; i < len; i += 1) {
|
|
132
|
+
str = `${str}${serializeArgumentNode(sortedArgs[i], option)}`;
|
|
133
|
+
if (len > 1 && i < len - 1) {
|
|
134
|
+
str = `${str},`;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return str;
|
|
138
|
+
}
|
|
139
|
+
function serializeArgumentValueNode(valueDefinition, option) {
|
|
140
|
+
const { kind } = valueDefinition;
|
|
141
|
+
switch (kind) {
|
|
142
|
+
case 'ObjectValue':
|
|
143
|
+
return serializeAndSortObjectValueNode(valueDefinition, option);
|
|
144
|
+
case 'ListValue':
|
|
145
|
+
return serializeAndSortListValueNode(valueDefinition, option);
|
|
146
|
+
case 'Variable':
|
|
147
|
+
return serializeVariableNode$1(valueDefinition, option);
|
|
148
|
+
default:
|
|
149
|
+
return serializeValueNode(valueDefinition);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
function serializeVariableNode$1(literalValueNode, option) {
|
|
153
|
+
if (option.render === false) {
|
|
154
|
+
return `$${literalValueNode.name}`;
|
|
155
|
+
}
|
|
156
|
+
return `${serializeVariableValue(option.variables[literalValueNode.name])}`;
|
|
157
|
+
}
|
|
158
|
+
function serializeVariableValue(value) {
|
|
159
|
+
return stableJSONStringify(value);
|
|
160
|
+
}
|
|
161
|
+
function serializeAndSortListValueNode(objectValueDefinition, option) {
|
|
162
|
+
const { values } = objectValueDefinition;
|
|
163
|
+
const str = [];
|
|
164
|
+
const sorted = option.render === true ? sortAndCopyUsingObjectKey(values, 'value') : values;
|
|
165
|
+
for (let i = 0, len = sorted.length; i < len; i += 1) {
|
|
166
|
+
str.push(serializeArgumentValueNode(sorted[i], option));
|
|
167
|
+
}
|
|
168
|
+
return `[${str.join(',')}]`;
|
|
169
|
+
}
|
|
170
|
+
function serializeAndSortObjectValueNode(objectValueDefinition, option) {
|
|
171
|
+
const { fields } = objectValueDefinition;
|
|
172
|
+
let str = '';
|
|
173
|
+
const fieldKeys = keys(fields).sort();
|
|
174
|
+
for (let i = 0, len = fieldKeys.length; i < len; i += 1) {
|
|
175
|
+
const fieldKey = fieldKeys[i];
|
|
176
|
+
str = `${str}${fieldKey}:${serializeArgumentValueNode(fields[fieldKey], option)}`;
|
|
177
|
+
if (len > 1 && i < len - 1) {
|
|
178
|
+
str = `${str},`;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return `{${str}}`;
|
|
182
|
+
}
|
|
183
|
+
function serializeArgumentNode(arg, option) {
|
|
184
|
+
const { name, value } = arg;
|
|
185
|
+
return `${name}:${serializeArgumentValueNode(value, option)}`;
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
-
function render(sel, variables) {
|
|
189
|
-
return serializeField(sel, { render: true, variables });
|
|
190
|
-
}
|
|
191
|
-
function serializeField(sel, option) {
|
|
192
|
-
const { name: fieldName } = sel;
|
|
193
|
-
if (sel.kind === 'ScalarFieldSelection') {
|
|
194
|
-
return fieldName;
|
|
195
|
-
}
|
|
196
|
-
const { arguments: selectionArguments } = sel;
|
|
197
|
-
if (selectionArguments === undefined || selectionArguments.length === 0) {
|
|
198
|
-
return fieldName;
|
|
199
|
-
}
|
|
200
|
-
return `${fieldName}(${option.render === true
|
|
201
|
-
? render$1(selectionArguments, option.variables)
|
|
202
|
-
: serialize$1(selectionArguments)})`;
|
|
188
|
+
function render(sel, variables) {
|
|
189
|
+
return serializeField(sel, { render: true, variables });
|
|
190
|
+
}
|
|
191
|
+
function serializeField(sel, option) {
|
|
192
|
+
const { name: fieldName } = sel;
|
|
193
|
+
if (sel.kind === 'ScalarFieldSelection') {
|
|
194
|
+
return fieldName;
|
|
195
|
+
}
|
|
196
|
+
const { arguments: selectionArguments } = sel;
|
|
197
|
+
if (selectionArguments === undefined || selectionArguments.length === 0) {
|
|
198
|
+
return fieldName;
|
|
199
|
+
}
|
|
200
|
+
return `${fieldName}(${option.render === true
|
|
201
|
+
? render$1(selectionArguments, option.variables)
|
|
202
|
+
: serialize$1(selectionArguments)})`;
|
|
203
203
|
}
|
|
204
204
|
|
|
205
|
-
function readScalarFieldSelection(builder, source, fieldName, sink) {
|
|
206
|
-
const gqlData = source[fieldName];
|
|
207
|
-
if (gqlData !== undefined && gqlData !== null && gqlData.__ref !== undefined) {
|
|
208
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
209
|
-
throw new Error(`Scalar requested at "${fieldName}" but is instead an object at "${gqlData.__ref}"`);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
builder.readScalar(fieldName, source, sink);
|
|
205
|
+
function readScalarFieldSelection(builder, source, fieldName, sink) {
|
|
206
|
+
const gqlData = source[fieldName];
|
|
207
|
+
if (gqlData !== undefined && gqlData !== null && gqlData.__ref !== undefined) {
|
|
208
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
209
|
+
throw new Error(`Scalar requested at "${fieldName}" but is instead an object at "${gqlData.__ref}"`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
builder.readScalar(fieldName, source, sink);
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
-
const CUSTOM_FIELD_NODE_TYPE = 'Record';
|
|
216
|
-
const RECORD_DEFAULT_FIELD_VALUES = ['value', 'displayValue'];
|
|
217
|
-
function collectObjectFieldSelection(data) {
|
|
218
|
-
return {
|
|
219
|
-
value: data.value,
|
|
220
|
-
displayValue: data.displayValue,
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
function childTypeIsChildRelationships(sel, _data) {
|
|
224
|
-
return sel.type === CONNECTION_NODE_TYPE;
|
|
225
|
-
}
|
|
226
|
-
function childTypeIsSpanningGqlRecord(sel, _data) {
|
|
227
|
-
return sel.type === CUSTOM_FIELD_NODE_TYPE;
|
|
228
|
-
}
|
|
229
|
-
function convertAstToTrie(ast) {
|
|
230
|
-
const selections = ast.luvioSelections === undefined ? [] : ast.luvioSelections;
|
|
231
|
-
const children = {};
|
|
232
|
-
const trie = {
|
|
233
|
-
name: ast.name,
|
|
234
|
-
children,
|
|
235
|
-
};
|
|
236
|
-
for (let i = 0, len = selections.length; i < len; i += 1) {
|
|
237
|
-
const sel = getLuvioFieldNodeSelection(selections[i]);
|
|
238
|
-
const { name: selName, kind } = sel;
|
|
239
|
-
switch (kind) {
|
|
240
|
-
case 'ObjectFieldSelection': {
|
|
241
|
-
children[selName] = {
|
|
242
|
-
name: selName,
|
|
243
|
-
children: {},
|
|
244
|
-
};
|
|
245
|
-
break;
|
|
246
|
-
}
|
|
247
|
-
case 'CustomFieldSelection': {
|
|
248
|
-
children[selName] = convertAstToTrie(sel);
|
|
249
|
-
break;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
return trie;
|
|
254
|
-
}
|
|
255
|
-
function formatSpanningCustomFieldSelection(sel, data) {
|
|
256
|
-
if (data === null) {
|
|
257
|
-
return {
|
|
258
|
-
value: {
|
|
259
|
-
displayValue: null,
|
|
260
|
-
value: null,
|
|
261
|
-
},
|
|
262
|
-
trie: convertAstToTrie(sel),
|
|
263
|
-
};
|
|
264
|
-
}
|
|
265
|
-
const { recordRepresentation, fieldsTrie } = convertToRecordRepresentation(sel, data);
|
|
266
|
-
return {
|
|
267
|
-
trie: fieldsTrie,
|
|
268
|
-
value: {
|
|
269
|
-
displayValue: data.DisplayValue,
|
|
270
|
-
value: recordRepresentation,
|
|
271
|
-
},
|
|
272
|
-
};
|
|
273
|
-
}
|
|
274
|
-
function convertToRecordRepresentation(ast, record) {
|
|
275
|
-
const { Id, WeakEtag, ApiName, LastModifiedById, LastModifiedDate, SystemModstamp, ldsRecordTypeId, } = record;
|
|
276
|
-
const { luvioSelections } = ast;
|
|
277
|
-
if (luvioSelections === undefined) {
|
|
278
|
-
// eslint-disable-next-line @salesforce/lds/no-error-in-production
|
|
279
|
-
throw new Error('Undefined selections');
|
|
280
|
-
}
|
|
281
|
-
const trieChildren = {};
|
|
282
|
-
const trie = {
|
|
283
|
-
name: ApiName,
|
|
284
|
-
children: trieChildren,
|
|
285
|
-
};
|
|
286
|
-
const childRelationships = {};
|
|
287
|
-
const fieldsBag = {};
|
|
288
|
-
for (let i = 0, len = luvioSelections.length; i < len; i += 1) {
|
|
289
|
-
const sel = getLuvioFieldNodeSelection(luvioSelections[i]);
|
|
290
|
-
const { name: fieldName, alias } = sel;
|
|
291
|
-
const propertyName = alias === undefined ? fieldName : alias;
|
|
292
|
-
const data = record[propertyName];
|
|
293
|
-
switch (sel.kind) {
|
|
294
|
-
case 'ObjectFieldSelection': {
|
|
295
|
-
trieChildren[fieldName] = {
|
|
296
|
-
name: fieldName,
|
|
297
|
-
children: {},
|
|
298
|
-
};
|
|
299
|
-
fieldsBag[fieldName] = collectObjectFieldSelection(data);
|
|
300
|
-
break;
|
|
301
|
-
}
|
|
302
|
-
case 'CustomFieldSelection': {
|
|
303
|
-
if (childTypeIsSpanningGqlRecord(sel)) {
|
|
304
|
-
const { value, trie } = formatSpanningCustomFieldSelection(sel, data);
|
|
305
|
-
trieChildren[fieldName] = trie;
|
|
306
|
-
fieldsBag[fieldName] = value;
|
|
307
|
-
}
|
|
308
|
-
else if (childTypeIsChildRelationships(sel)) {
|
|
309
|
-
childRelationships[fieldName] = {
|
|
310
|
-
ast: sel,
|
|
311
|
-
data: data,
|
|
312
|
-
};
|
|
313
|
-
}
|
|
314
|
-
break;
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
const rep = {
|
|
319
|
-
apiName: ApiName,
|
|
320
|
-
eTag: '',
|
|
321
|
-
lastModifiedById: LastModifiedById.value,
|
|
322
|
-
lastModifiedDate: LastModifiedDate.value,
|
|
323
|
-
systemModstamp: SystemModstamp.value,
|
|
324
|
-
recordTypeId: ldsRecordTypeId === null ? null : ldsRecordTypeId.value,
|
|
325
|
-
recordTypeInfo: null,
|
|
326
|
-
childRelationships: {},
|
|
327
|
-
id: Id,
|
|
328
|
-
weakEtag: WeakEtag,
|
|
329
|
-
fields: fieldsBag,
|
|
330
|
-
};
|
|
331
|
-
return {
|
|
332
|
-
recordRepresentation: rep,
|
|
333
|
-
fieldsTrie: trie,
|
|
334
|
-
childRelationships,
|
|
335
|
-
};
|
|
336
|
-
}
|
|
337
|
-
const defaultRecordFieldsFragmentName = 'defaultRecordFields';
|
|
338
|
-
const defaultRecordFieldsFragment = `fragment ${defaultRecordFieldsFragmentName} on Record { __typename, ApiName, WeakEtag, Id, DisplayValue, SystemModstamp { value } LastModifiedById { value } LastModifiedDate { value } ldsRecordTypeId: RecordTypeId(fallback: true) { value } }`;
|
|
339
|
-
function getChildRelationshipsKey(recordKey, propertyName) {
|
|
340
|
-
return `${recordKey}__childRelationships__${propertyName}`;
|
|
341
|
-
}
|
|
342
|
-
const createIngest$4 = (ast, variables) => {
|
|
343
|
-
return (data, path, luvio, store, timestamp) => {
|
|
344
|
-
const { recordRepresentation, fieldsTrie, childRelationships } = convertToRecordRepresentation(ast, data);
|
|
345
|
-
const ingestRecord = createIngestRecordWithFields(fieldsTrie, {
|
|
346
|
-
name: recordRepresentation.apiName,
|
|
347
|
-
children: {},
|
|
348
|
-
});
|
|
349
|
-
const recordIngest = ingestRecord(recordRepresentation, path, luvio, store, timestamp);
|
|
350
|
-
const recordKey = recordIngest.__ref;
|
|
351
|
-
const childRelationshipKeys = Object.keys(childRelationships);
|
|
352
|
-
for (let i = 0, len = childRelationshipKeys.length; i < len; i += 1) {
|
|
353
|
-
const propertyName = childRelationshipKeys[i];
|
|
354
|
-
const childRelationship = childRelationships[propertyName];
|
|
355
|
-
const { ast: childRelationshipAst, data: childRelationshipData } = childRelationship;
|
|
356
|
-
const fullPath = getChildRelationshipsKey(recordKey, propertyName);
|
|
357
|
-
createIngest$1(childRelationshipAst, fullPath, variables)(childRelationshipData, {
|
|
358
|
-
parent: {
|
|
359
|
-
data,
|
|
360
|
-
key: recordKey,
|
|
361
|
-
existing: undefined,
|
|
362
|
-
},
|
|
363
|
-
fullPath: fullPath,
|
|
364
|
-
propertyName: propertyName,
|
|
365
|
-
}, luvio, store, timestamp);
|
|
366
|
-
}
|
|
367
|
-
return recordIngest;
|
|
368
|
-
};
|
|
369
|
-
};
|
|
370
|
-
const recordProperties = {
|
|
371
|
-
Id: {
|
|
372
|
-
propertyName: 'id',
|
|
373
|
-
},
|
|
374
|
-
ApiName: {
|
|
375
|
-
propertyName: 'apiName',
|
|
376
|
-
},
|
|
377
|
-
};
|
|
378
|
-
function getNonSpanningField(sel, builder, source) {
|
|
379
|
-
const sink = {};
|
|
380
|
-
const { luvioSelections } = sel;
|
|
381
|
-
if (luvioSelections === undefined) {
|
|
382
|
-
// eslint-disable-next-line @salesforce/lds/no-error-in-production
|
|
383
|
-
throw new Error('Empty selections not supported');
|
|
384
|
-
}
|
|
385
|
-
for (let i = 0, len = luvioSelections.length; i < len; i += 1) {
|
|
386
|
-
const sel = getLuvioFieldNodeSelection(luvioSelections[i]);
|
|
387
|
-
const { kind } = sel;
|
|
388
|
-
const name = sel.name;
|
|
389
|
-
builder.enterPath(name);
|
|
390
|
-
if (kind !== 'ScalarFieldSelection') {
|
|
391
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
392
|
-
throw new Error(`Unexpected kind "${kind}"`);
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
builder.assignScalar(name, sink, source[name]);
|
|
396
|
-
builder.exitPath();
|
|
397
|
-
}
|
|
398
|
-
return sink;
|
|
399
|
-
}
|
|
400
|
-
function getCustomSelection(luvio, selection, builder, options, variables) {
|
|
401
|
-
const { type } = selection;
|
|
402
|
-
switch (type) {
|
|
403
|
-
case 'Record':
|
|
404
|
-
return readRecordRepresentation(luvio, selection, builder, options, variables);
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
function getScalarValue(selectionName, state) {
|
|
408
|
-
if (selectionName === 'DisplayValue') {
|
|
409
|
-
const { parentFieldValue } = state;
|
|
410
|
-
if (parentFieldValue === undefined) {
|
|
411
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
412
|
-
throw new Error('Unable to calculate DisplayValue');
|
|
413
|
-
}
|
|
414
|
-
else {
|
|
415
|
-
return undefined;
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
return parentFieldValue.displayValue;
|
|
419
|
-
}
|
|
420
|
-
const assignment = recordProperties[selectionName];
|
|
421
|
-
if (assignment === undefined) {
|
|
422
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
423
|
-
throw new Error(`Unknown assignment for ScalarFieldSelection at property "${selectionName}"`);
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
return state.source[assignment.propertyName];
|
|
427
|
-
}
|
|
428
|
-
function assignConnectionSelection(luvio, builder, sink, sel, recordKey, propertyName, variables) {
|
|
429
|
-
const key = getChildRelationshipsKey(recordKey, propertyName);
|
|
430
|
-
const resolved = resolveKey(builder, key);
|
|
431
|
-
if (resolved === undefined) {
|
|
432
|
-
return;
|
|
433
|
-
}
|
|
434
|
-
const data = createRead$2(luvio, sel, variables)(resolved.value, builder);
|
|
435
|
-
builder.assignNonScalar(sink, propertyName, data);
|
|
436
|
-
}
|
|
437
|
-
function assignSelection(luvio, selection, builder, state, variables) {
|
|
438
|
-
const sel = getLuvioFieldNodeSelection(selection);
|
|
439
|
-
const { name: selectionName, kind, alias } = sel;
|
|
440
|
-
const propertyName = alias === undefined ? selectionName : alias;
|
|
441
|
-
const { source, sink } = state;
|
|
442
|
-
const { fields } = source;
|
|
443
|
-
builder.enterPath(selectionName);
|
|
444
|
-
switch (kind) {
|
|
445
|
-
case 'ScalarFieldSelection': {
|
|
446
|
-
builder.assignScalar(propertyName, sink, getScalarValue(selectionName, state));
|
|
447
|
-
break;
|
|
448
|
-
}
|
|
449
|
-
case 'ObjectFieldSelection': {
|
|
450
|
-
// regular field, not spanning
|
|
451
|
-
const field = propertyLookup(builder, selectionName, fields);
|
|
452
|
-
if (field.state === PropertyLookupResultState.Missing) {
|
|
453
|
-
break;
|
|
454
|
-
}
|
|
455
|
-
const resolved = resolveLink(builder, field.value);
|
|
456
|
-
if (resolved === undefined) {
|
|
457
|
-
break;
|
|
458
|
-
}
|
|
459
|
-
const data = getNonSpanningField(sel, builder, resolved.value);
|
|
460
|
-
builder.assignNonScalar(sink, propertyName, data);
|
|
461
|
-
break;
|
|
462
|
-
}
|
|
463
|
-
case 'CustomFieldSelection': {
|
|
464
|
-
if (sel.type === 'Connection') {
|
|
465
|
-
const recordKey = keyBuilderRecord(luvio, {
|
|
466
|
-
recordId: state.source.id,
|
|
467
|
-
});
|
|
468
|
-
assignConnectionSelection(luvio, builder, sink, sel, recordKey, propertyName, variables);
|
|
469
|
-
}
|
|
470
|
-
else {
|
|
471
|
-
const field = fields[selectionName];
|
|
472
|
-
const resolvedParentFieldValue = resolveLink(builder, field);
|
|
473
|
-
if (resolvedParentFieldValue === undefined) {
|
|
474
|
-
break;
|
|
475
|
-
}
|
|
476
|
-
const { value: spanningFieldResult } = resolvedParentFieldValue;
|
|
477
|
-
const { value: spanningFieldValue } = spanningFieldResult;
|
|
478
|
-
if (spanningFieldValue === null || typeof spanningFieldValue !== 'object') {
|
|
479
|
-
sink[propertyName] = null;
|
|
480
|
-
break;
|
|
481
|
-
}
|
|
482
|
-
const resolvedSpanningRecordValue = resolveLink(builder, spanningFieldValue);
|
|
483
|
-
if (resolvedSpanningRecordValue === undefined) {
|
|
484
|
-
break;
|
|
485
|
-
}
|
|
486
|
-
const data = getCustomSelection(luvio, sel, builder, {
|
|
487
|
-
source: resolvedSpanningRecordValue.value,
|
|
488
|
-
parentFieldValue: spanningFieldResult,
|
|
489
|
-
}, variables);
|
|
490
|
-
builder.assignNonScalar(sink, propertyName, data);
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
builder.exitPath();
|
|
495
|
-
}
|
|
496
|
-
function readRecordRepresentation(luvio, ast, builder, options, variables) {
|
|
497
|
-
const { luvioSelections } = ast;
|
|
498
|
-
if (luvioSelections === undefined) {
|
|
499
|
-
// eslint-disable-next-line @salesforce/lds/no-error-in-production
|
|
500
|
-
throw new Error('Empty selections not supported');
|
|
501
|
-
}
|
|
502
|
-
const sink = {};
|
|
503
|
-
const state = {
|
|
504
|
-
source: options.source,
|
|
505
|
-
sink,
|
|
506
|
-
parentFieldValue: options.parentFieldValue,
|
|
507
|
-
};
|
|
508
|
-
for (let i = 0, len = luvioSelections.length; i < len; i += 1) {
|
|
509
|
-
assignSelection(luvio, luvioSelections[i], builder, state, variables);
|
|
510
|
-
}
|
|
511
|
-
return sink;
|
|
512
|
-
}
|
|
513
|
-
const createRead$3 = (luvio, ast, variables) => {
|
|
514
|
-
return (data, builder) => {
|
|
515
|
-
return readRecordRepresentation(luvio, ast, builder, {
|
|
516
|
-
source: data,
|
|
517
|
-
parentFieldValue: undefined,
|
|
518
|
-
}, variables);
|
|
519
|
-
};
|
|
215
|
+
const CUSTOM_FIELD_NODE_TYPE = 'Record';
|
|
216
|
+
const RECORD_DEFAULT_FIELD_VALUES = ['value', 'displayValue'];
|
|
217
|
+
function collectObjectFieldSelection(data) {
|
|
218
|
+
return {
|
|
219
|
+
value: data.value,
|
|
220
|
+
displayValue: data.displayValue,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
function childTypeIsChildRelationships(sel, _data) {
|
|
224
|
+
return sel.type === CONNECTION_NODE_TYPE;
|
|
225
|
+
}
|
|
226
|
+
function childTypeIsSpanningGqlRecord(sel, _data) {
|
|
227
|
+
return sel.type === CUSTOM_FIELD_NODE_TYPE;
|
|
228
|
+
}
|
|
229
|
+
function convertAstToTrie(ast) {
|
|
230
|
+
const selections = ast.luvioSelections === undefined ? [] : ast.luvioSelections;
|
|
231
|
+
const children = {};
|
|
232
|
+
const trie = {
|
|
233
|
+
name: ast.name,
|
|
234
|
+
children,
|
|
235
|
+
};
|
|
236
|
+
for (let i = 0, len = selections.length; i < len; i += 1) {
|
|
237
|
+
const sel = getLuvioFieldNodeSelection(selections[i]);
|
|
238
|
+
const { name: selName, kind } = sel;
|
|
239
|
+
switch (kind) {
|
|
240
|
+
case 'ObjectFieldSelection': {
|
|
241
|
+
children[selName] = {
|
|
242
|
+
name: selName,
|
|
243
|
+
children: {},
|
|
244
|
+
};
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
case 'CustomFieldSelection': {
|
|
248
|
+
children[selName] = convertAstToTrie(sel);
|
|
249
|
+
break;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return trie;
|
|
254
|
+
}
|
|
255
|
+
function formatSpanningCustomFieldSelection(sel, data) {
|
|
256
|
+
if (data === null) {
|
|
257
|
+
return {
|
|
258
|
+
value: {
|
|
259
|
+
displayValue: null,
|
|
260
|
+
value: null,
|
|
261
|
+
},
|
|
262
|
+
trie: convertAstToTrie(sel),
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
const { recordRepresentation, fieldsTrie } = convertToRecordRepresentation(sel, data);
|
|
266
|
+
return {
|
|
267
|
+
trie: fieldsTrie,
|
|
268
|
+
value: {
|
|
269
|
+
displayValue: data.DisplayValue,
|
|
270
|
+
value: recordRepresentation,
|
|
271
|
+
},
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
function convertToRecordRepresentation(ast, record) {
|
|
275
|
+
const { Id, WeakEtag, ApiName, LastModifiedById, LastModifiedDate, SystemModstamp, ldsRecordTypeId, } = record;
|
|
276
|
+
const { luvioSelections } = ast;
|
|
277
|
+
if (luvioSelections === undefined) {
|
|
278
|
+
// eslint-disable-next-line @salesforce/lds/no-error-in-production
|
|
279
|
+
throw new Error('Undefined selections');
|
|
280
|
+
}
|
|
281
|
+
const trieChildren = {};
|
|
282
|
+
const trie = {
|
|
283
|
+
name: ApiName,
|
|
284
|
+
children: trieChildren,
|
|
285
|
+
};
|
|
286
|
+
const childRelationships = {};
|
|
287
|
+
const fieldsBag = {};
|
|
288
|
+
for (let i = 0, len = luvioSelections.length; i < len; i += 1) {
|
|
289
|
+
const sel = getLuvioFieldNodeSelection(luvioSelections[i]);
|
|
290
|
+
const { name: fieldName, alias } = sel;
|
|
291
|
+
const propertyName = alias === undefined ? fieldName : alias;
|
|
292
|
+
const data = record[propertyName];
|
|
293
|
+
switch (sel.kind) {
|
|
294
|
+
case 'ObjectFieldSelection': {
|
|
295
|
+
trieChildren[fieldName] = {
|
|
296
|
+
name: fieldName,
|
|
297
|
+
children: {},
|
|
298
|
+
};
|
|
299
|
+
fieldsBag[fieldName] = collectObjectFieldSelection(data);
|
|
300
|
+
break;
|
|
301
|
+
}
|
|
302
|
+
case 'CustomFieldSelection': {
|
|
303
|
+
if (childTypeIsSpanningGqlRecord(sel)) {
|
|
304
|
+
const { value, trie } = formatSpanningCustomFieldSelection(sel, data);
|
|
305
|
+
trieChildren[fieldName] = trie;
|
|
306
|
+
fieldsBag[fieldName] = value;
|
|
307
|
+
}
|
|
308
|
+
else if (childTypeIsChildRelationships(sel)) {
|
|
309
|
+
childRelationships[fieldName] = {
|
|
310
|
+
ast: sel,
|
|
311
|
+
data: data,
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
break;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
const rep = {
|
|
319
|
+
apiName: ApiName,
|
|
320
|
+
eTag: '',
|
|
321
|
+
lastModifiedById: LastModifiedById.value,
|
|
322
|
+
lastModifiedDate: LastModifiedDate.value,
|
|
323
|
+
systemModstamp: SystemModstamp.value,
|
|
324
|
+
recordTypeId: ldsRecordTypeId === null ? null : ldsRecordTypeId.value,
|
|
325
|
+
recordTypeInfo: null,
|
|
326
|
+
childRelationships: {},
|
|
327
|
+
id: Id,
|
|
328
|
+
weakEtag: WeakEtag,
|
|
329
|
+
fields: fieldsBag,
|
|
330
|
+
};
|
|
331
|
+
return {
|
|
332
|
+
recordRepresentation: rep,
|
|
333
|
+
fieldsTrie: trie,
|
|
334
|
+
childRelationships,
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
const defaultRecordFieldsFragmentName = 'defaultRecordFields';
|
|
338
|
+
const defaultRecordFieldsFragment = `fragment ${defaultRecordFieldsFragmentName} on Record { __typename, ApiName, WeakEtag, Id, DisplayValue, SystemModstamp { value } LastModifiedById { value } LastModifiedDate { value } ldsRecordTypeId: RecordTypeId(fallback: true) { value } }`;
|
|
339
|
+
function getChildRelationshipsKey(recordKey, propertyName) {
|
|
340
|
+
return `${recordKey}__childRelationships__${propertyName}`;
|
|
341
|
+
}
|
|
342
|
+
const createIngest$4 = (ast, variables) => {
|
|
343
|
+
return (data, path, luvio, store, timestamp) => {
|
|
344
|
+
const { recordRepresentation, fieldsTrie, childRelationships } = convertToRecordRepresentation(ast, data);
|
|
345
|
+
const ingestRecord = createIngestRecordWithFields(fieldsTrie, {
|
|
346
|
+
name: recordRepresentation.apiName,
|
|
347
|
+
children: {},
|
|
348
|
+
});
|
|
349
|
+
const recordIngest = ingestRecord(recordRepresentation, path, luvio, store, timestamp);
|
|
350
|
+
const recordKey = recordIngest.__ref;
|
|
351
|
+
const childRelationshipKeys = Object.keys(childRelationships);
|
|
352
|
+
for (let i = 0, len = childRelationshipKeys.length; i < len; i += 1) {
|
|
353
|
+
const propertyName = childRelationshipKeys[i];
|
|
354
|
+
const childRelationship = childRelationships[propertyName];
|
|
355
|
+
const { ast: childRelationshipAst, data: childRelationshipData } = childRelationship;
|
|
356
|
+
const fullPath = getChildRelationshipsKey(recordKey, propertyName);
|
|
357
|
+
createIngest$1(childRelationshipAst, fullPath, variables)(childRelationshipData, {
|
|
358
|
+
parent: {
|
|
359
|
+
data,
|
|
360
|
+
key: recordKey,
|
|
361
|
+
existing: undefined,
|
|
362
|
+
},
|
|
363
|
+
fullPath: fullPath,
|
|
364
|
+
propertyName: propertyName,
|
|
365
|
+
}, luvio, store, timestamp);
|
|
366
|
+
}
|
|
367
|
+
return recordIngest;
|
|
368
|
+
};
|
|
369
|
+
};
|
|
370
|
+
const recordProperties = {
|
|
371
|
+
Id: {
|
|
372
|
+
propertyName: 'id',
|
|
373
|
+
},
|
|
374
|
+
ApiName: {
|
|
375
|
+
propertyName: 'apiName',
|
|
376
|
+
},
|
|
377
|
+
};
|
|
378
|
+
function getNonSpanningField(sel, builder, source) {
|
|
379
|
+
const sink = {};
|
|
380
|
+
const { luvioSelections } = sel;
|
|
381
|
+
if (luvioSelections === undefined) {
|
|
382
|
+
// eslint-disable-next-line @salesforce/lds/no-error-in-production
|
|
383
|
+
throw new Error('Empty selections not supported');
|
|
384
|
+
}
|
|
385
|
+
for (let i = 0, len = luvioSelections.length; i < len; i += 1) {
|
|
386
|
+
const sel = getLuvioFieldNodeSelection(luvioSelections[i]);
|
|
387
|
+
const { kind } = sel;
|
|
388
|
+
const name = sel.name;
|
|
389
|
+
builder.enterPath(name);
|
|
390
|
+
if (kind !== 'ScalarFieldSelection') {
|
|
391
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
392
|
+
throw new Error(`Unexpected kind "${kind}"`);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
builder.assignScalar(name, sink, source[name]);
|
|
396
|
+
builder.exitPath();
|
|
397
|
+
}
|
|
398
|
+
return sink;
|
|
399
|
+
}
|
|
400
|
+
function getCustomSelection(luvio, selection, builder, options, variables) {
|
|
401
|
+
const { type } = selection;
|
|
402
|
+
switch (type) {
|
|
403
|
+
case 'Record':
|
|
404
|
+
return readRecordRepresentation(luvio, selection, builder, options, variables);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
function getScalarValue(selectionName, state) {
|
|
408
|
+
if (selectionName === 'DisplayValue') {
|
|
409
|
+
const { parentFieldValue } = state;
|
|
410
|
+
if (parentFieldValue === undefined) {
|
|
411
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
412
|
+
throw new Error('Unable to calculate DisplayValue');
|
|
413
|
+
}
|
|
414
|
+
else {
|
|
415
|
+
return undefined;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
return parentFieldValue.displayValue;
|
|
419
|
+
}
|
|
420
|
+
const assignment = recordProperties[selectionName];
|
|
421
|
+
if (assignment === undefined) {
|
|
422
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
423
|
+
throw new Error(`Unknown assignment for ScalarFieldSelection at property "${selectionName}"`);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
return state.source[assignment.propertyName];
|
|
427
|
+
}
|
|
428
|
+
function assignConnectionSelection(luvio, builder, sink, sel, recordKey, propertyName, variables) {
|
|
429
|
+
const key = getChildRelationshipsKey(recordKey, propertyName);
|
|
430
|
+
const resolved = resolveKey(builder, key);
|
|
431
|
+
if (resolved === undefined) {
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
const data = createRead$2(luvio, sel, variables)(resolved.value, builder);
|
|
435
|
+
builder.assignNonScalar(sink, propertyName, data);
|
|
436
|
+
}
|
|
437
|
+
function assignSelection(luvio, selection, builder, state, variables) {
|
|
438
|
+
const sel = getLuvioFieldNodeSelection(selection);
|
|
439
|
+
const { name: selectionName, kind, alias } = sel;
|
|
440
|
+
const propertyName = alias === undefined ? selectionName : alias;
|
|
441
|
+
const { source, sink } = state;
|
|
442
|
+
const { fields } = source;
|
|
443
|
+
builder.enterPath(selectionName);
|
|
444
|
+
switch (kind) {
|
|
445
|
+
case 'ScalarFieldSelection': {
|
|
446
|
+
builder.assignScalar(propertyName, sink, getScalarValue(selectionName, state));
|
|
447
|
+
break;
|
|
448
|
+
}
|
|
449
|
+
case 'ObjectFieldSelection': {
|
|
450
|
+
// regular field, not spanning
|
|
451
|
+
const field = propertyLookup(builder, selectionName, fields);
|
|
452
|
+
if (field.state === PropertyLookupResultState.Missing) {
|
|
453
|
+
break;
|
|
454
|
+
}
|
|
455
|
+
const resolved = resolveLink(builder, field.value);
|
|
456
|
+
if (resolved === undefined) {
|
|
457
|
+
break;
|
|
458
|
+
}
|
|
459
|
+
const data = getNonSpanningField(sel, builder, resolved.value);
|
|
460
|
+
builder.assignNonScalar(sink, propertyName, data);
|
|
461
|
+
break;
|
|
462
|
+
}
|
|
463
|
+
case 'CustomFieldSelection': {
|
|
464
|
+
if (sel.type === 'Connection') {
|
|
465
|
+
const recordKey = keyBuilderRecord(luvio, {
|
|
466
|
+
recordId: state.source.id,
|
|
467
|
+
});
|
|
468
|
+
assignConnectionSelection(luvio, builder, sink, sel, recordKey, propertyName, variables);
|
|
469
|
+
}
|
|
470
|
+
else {
|
|
471
|
+
const field = fields[selectionName];
|
|
472
|
+
const resolvedParentFieldValue = resolveLink(builder, field);
|
|
473
|
+
if (resolvedParentFieldValue === undefined) {
|
|
474
|
+
break;
|
|
475
|
+
}
|
|
476
|
+
const { value: spanningFieldResult } = resolvedParentFieldValue;
|
|
477
|
+
const { value: spanningFieldValue } = spanningFieldResult;
|
|
478
|
+
if (spanningFieldValue === null || typeof spanningFieldValue !== 'object') {
|
|
479
|
+
sink[propertyName] = null;
|
|
480
|
+
break;
|
|
481
|
+
}
|
|
482
|
+
const resolvedSpanningRecordValue = resolveLink(builder, spanningFieldValue);
|
|
483
|
+
if (resolvedSpanningRecordValue === undefined) {
|
|
484
|
+
break;
|
|
485
|
+
}
|
|
486
|
+
const data = getCustomSelection(luvio, sel, builder, {
|
|
487
|
+
source: resolvedSpanningRecordValue.value,
|
|
488
|
+
parentFieldValue: spanningFieldResult,
|
|
489
|
+
}, variables);
|
|
490
|
+
builder.assignNonScalar(sink, propertyName, data);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
builder.exitPath();
|
|
495
|
+
}
|
|
496
|
+
function readRecordRepresentation(luvio, ast, builder, options, variables) {
|
|
497
|
+
const { luvioSelections } = ast;
|
|
498
|
+
if (luvioSelections === undefined) {
|
|
499
|
+
// eslint-disable-next-line @salesforce/lds/no-error-in-production
|
|
500
|
+
throw new Error('Empty selections not supported');
|
|
501
|
+
}
|
|
502
|
+
const sink = {};
|
|
503
|
+
const state = {
|
|
504
|
+
source: options.source,
|
|
505
|
+
sink,
|
|
506
|
+
parentFieldValue: options.parentFieldValue,
|
|
507
|
+
};
|
|
508
|
+
for (let i = 0, len = luvioSelections.length; i < len; i += 1) {
|
|
509
|
+
assignSelection(luvio, luvioSelections[i], builder, state, variables);
|
|
510
|
+
}
|
|
511
|
+
return sink;
|
|
512
|
+
}
|
|
513
|
+
const createRead$3 = (luvio, ast, variables) => {
|
|
514
|
+
return (data, builder) => {
|
|
515
|
+
return readRecordRepresentation(luvio, ast, builder, {
|
|
516
|
+
source: data,
|
|
517
|
+
parentFieldValue: undefined,
|
|
518
|
+
}, variables);
|
|
519
|
+
};
|
|
520
520
|
};
|
|
521
521
|
|
|
522
|
-
const createIngest$3 = (ast, variables) => {
|
|
523
|
-
const { type } = ast;
|
|
524
|
-
switch (type) {
|
|
525
|
-
case CUSTOM_FIELD_NODE_TYPE:
|
|
526
|
-
return createIngest$4(ast, variables);
|
|
527
|
-
case CONNECTION_NODE_TYPE:
|
|
528
|
-
return createIngest$1(ast, keyBuilder(ast, variables), variables);
|
|
529
|
-
}
|
|
530
|
-
// eslint-disable-next-line @salesforce/lds/no-error-in-production
|
|
531
|
-
throw new Error(`Unsupported type: "${type}"`);
|
|
522
|
+
const createIngest$3 = (ast, variables) => {
|
|
523
|
+
const { type } = ast;
|
|
524
|
+
switch (type) {
|
|
525
|
+
case CUSTOM_FIELD_NODE_TYPE:
|
|
526
|
+
return createIngest$4(ast, variables);
|
|
527
|
+
case CONNECTION_NODE_TYPE:
|
|
528
|
+
return createIngest$1(ast, keyBuilder(ast, variables), variables);
|
|
529
|
+
}
|
|
530
|
+
// eslint-disable-next-line @salesforce/lds/no-error-in-production
|
|
531
|
+
throw new Error(`Unsupported type: "${type}"`);
|
|
532
532
|
};
|
|
533
533
|
|
|
534
|
-
function merge(existing, incoming) {
|
|
535
|
-
if (existing === undefined) {
|
|
536
|
-
return incoming;
|
|
537
|
-
}
|
|
538
|
-
// Merge existing and incoming values together
|
|
539
|
-
return {
|
|
540
|
-
...existing,
|
|
541
|
-
...incoming,
|
|
542
|
-
};
|
|
534
|
+
function merge(existing, incoming) {
|
|
535
|
+
if (existing === undefined) {
|
|
536
|
+
return incoming;
|
|
537
|
+
}
|
|
538
|
+
// Merge existing and incoming values together
|
|
539
|
+
return {
|
|
540
|
+
...existing,
|
|
541
|
+
...incoming,
|
|
542
|
+
};
|
|
543
543
|
}
|
|
544
544
|
|
|
545
|
-
function resolveValue(ast, variables, source) {
|
|
546
|
-
const { alias } = ast;
|
|
547
|
-
const propertyName = render(ast, variables);
|
|
548
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
549
|
-
if (alias !== undefined && alias in source) {
|
|
550
|
-
throw new Error(`Invalid alias "${alias}" passed to "equal" function. All aliases need to be normalized before calling equal`);
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
return source[propertyName];
|
|
554
|
-
}
|
|
555
|
-
function linkEquals(ast, variables, existing, incoming) {
|
|
556
|
-
const value = resolveValue(ast, variables, existing);
|
|
557
|
-
if (value === undefined) {
|
|
558
|
-
return false;
|
|
559
|
-
}
|
|
560
|
-
const incomingLink = resolveValue(ast, variables, incoming);
|
|
561
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
562
|
-
if (incomingLink === undefined) {
|
|
563
|
-
throw new Error('Unexpected undefined link');
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
return value.__ref === incomingLink.__ref;
|
|
567
|
-
}
|
|
568
|
-
function scalarFieldEquals(ast, variables, existing, incoming) {
|
|
569
|
-
const { name } = ast;
|
|
570
|
-
const value = existing[name];
|
|
571
|
-
if (value === undefined) {
|
|
572
|
-
return false;
|
|
573
|
-
}
|
|
574
|
-
return value === resolveValue(ast, variables, incoming);
|
|
575
|
-
}
|
|
576
|
-
function equals(ast, variables, existing, incoming) {
|
|
577
|
-
const selections = ast.luvioSelections === undefined ? [] : ast.luvioSelections;
|
|
578
|
-
for (let i = 0, len = selections.length; i < len; i += 1) {
|
|
579
|
-
const sel = getLuvioFieldNodeSelection(selections[i]);
|
|
580
|
-
if (sel.kind === 'ScalarFieldSelection') {
|
|
581
|
-
if (scalarFieldEquals(sel, variables, existing, incoming) === false) {
|
|
582
|
-
return false;
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
else {
|
|
586
|
-
if (linkEquals(sel, variables, existing, incoming) === false) {
|
|
587
|
-
return false;
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
}
|
|
591
|
-
return true;
|
|
545
|
+
function resolveValue(ast, variables, source) {
|
|
546
|
+
const { alias } = ast;
|
|
547
|
+
const propertyName = render(ast, variables);
|
|
548
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
549
|
+
if (alias !== undefined && alias in source) {
|
|
550
|
+
throw new Error(`Invalid alias "${alias}" passed to "equal" function. All aliases need to be normalized before calling equal`);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
return source[propertyName];
|
|
554
|
+
}
|
|
555
|
+
function linkEquals(ast, variables, existing, incoming) {
|
|
556
|
+
const value = resolveValue(ast, variables, existing);
|
|
557
|
+
if (value === undefined) {
|
|
558
|
+
return false;
|
|
559
|
+
}
|
|
560
|
+
const incomingLink = resolveValue(ast, variables, incoming);
|
|
561
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
562
|
+
if (incomingLink === undefined) {
|
|
563
|
+
throw new Error('Unexpected undefined link');
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
return value.__ref === incomingLink.__ref;
|
|
567
|
+
}
|
|
568
|
+
function scalarFieldEquals(ast, variables, existing, incoming) {
|
|
569
|
+
const { name } = ast;
|
|
570
|
+
const value = existing[name];
|
|
571
|
+
if (value === undefined) {
|
|
572
|
+
return false;
|
|
573
|
+
}
|
|
574
|
+
return value === resolveValue(ast, variables, incoming);
|
|
575
|
+
}
|
|
576
|
+
function equals(ast, variables, existing, incoming) {
|
|
577
|
+
const selections = ast.luvioSelections === undefined ? [] : ast.luvioSelections;
|
|
578
|
+
for (let i = 0, len = selections.length; i < len; i += 1) {
|
|
579
|
+
const sel = getLuvioFieldNodeSelection(selections[i]);
|
|
580
|
+
if (sel.kind === 'ScalarFieldSelection') {
|
|
581
|
+
if (scalarFieldEquals(sel, variables, existing, incoming) === false) {
|
|
582
|
+
return false;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
else {
|
|
586
|
+
if (linkEquals(sel, variables, existing, incoming) === false) {
|
|
587
|
+
return false;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
return true;
|
|
592
592
|
}
|
|
593
593
|
|
|
594
|
-
const DEFAULT_GRAPHQL_TTL = 30000;
|
|
595
|
-
const GRAPHQL_INGEST_VERSION = 'GRAPHQL_INGEST_VERSION_1';
|
|
596
|
-
function createIngest$2(ast, variables) {
|
|
597
|
-
if (ast.kind === 'CustomFieldSelection') {
|
|
598
|
-
return createIngest$3(ast, variables);
|
|
599
|
-
}
|
|
600
|
-
return genericCreateIngest(ast, variables);
|
|
601
|
-
}
|
|
602
|
-
function publishDataIfChanged(params) {
|
|
603
|
-
const { store, key, ast, incoming, luvio, variables } = params;
|
|
604
|
-
const existing = store.readEntry(key);
|
|
605
|
-
if (existing === undefined || equals(ast, variables, existing, incoming) === false) {
|
|
606
|
-
const newData = merge(existing, incoming);
|
|
607
|
-
luvio.storePublish(key, newData);
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
function genericCreateIngest(ast, variables) {
|
|
611
|
-
let selections = ast.luvioSelections === undefined ? [] : ast.luvioSelections;
|
|
612
|
-
return (data, path, luvio, store, timestamp) => {
|
|
613
|
-
const { fullPath } = path;
|
|
614
|
-
for (let i = 0, len = selections.length; i < len; i += 1) {
|
|
615
|
-
const sel = getLuvioFieldNodeSelection(selections[i]);
|
|
616
|
-
if (sel.kind === 'ScalarFieldSelection') {
|
|
617
|
-
continue;
|
|
618
|
-
}
|
|
619
|
-
const { name: fieldName, alias } = sel;
|
|
620
|
-
const readPropertyName = alias === undefined ? fieldName : alias;
|
|
621
|
-
const propertyFullPath = `${fullPath}__${fieldName}`;
|
|
622
|
-
const writePropertyName = render(sel, variables);
|
|
623
|
-
const childPath = {
|
|
624
|
-
parent: {
|
|
625
|
-
existing: null,
|
|
626
|
-
key: fullPath,
|
|
627
|
-
data,
|
|
628
|
-
},
|
|
629
|
-
propertyName: readPropertyName,
|
|
630
|
-
fullPath: propertyFullPath,
|
|
631
|
-
};
|
|
632
|
-
data[writePropertyName] = createIngest$2(sel, variables)(data[readPropertyName], childPath, luvio, store, timestamp);
|
|
633
|
-
if (writePropertyName !== readPropertyName && data[readPropertyName] !== undefined) {
|
|
634
|
-
delete data[readPropertyName];
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
publishDataIfChanged({
|
|
638
|
-
ast,
|
|
639
|
-
luvio,
|
|
640
|
-
store,
|
|
641
|
-
key: fullPath,
|
|
642
|
-
variables: {},
|
|
643
|
-
incoming: data,
|
|
644
|
-
});
|
|
645
|
-
if (data && data.__typename !== undefined) {
|
|
646
|
-
luvio.publishStoreMetadata(fullPath, {
|
|
647
|
-
representationName: data.__typename,
|
|
648
|
-
namespace: namespace,
|
|
649
|
-
ttl: DEFAULT_GRAPHQL_TTL,
|
|
650
|
-
version: GRAPHQL_INGEST_VERSION,
|
|
651
|
-
});
|
|
652
|
-
}
|
|
653
|
-
return {
|
|
654
|
-
__ref: fullPath,
|
|
655
|
-
};
|
|
656
|
-
};
|
|
594
|
+
const DEFAULT_GRAPHQL_TTL = 30000;
|
|
595
|
+
const GRAPHQL_INGEST_VERSION = 'GRAPHQL_INGEST_VERSION_1';
|
|
596
|
+
function createIngest$2(ast, variables) {
|
|
597
|
+
if (ast.kind === 'CustomFieldSelection') {
|
|
598
|
+
return createIngest$3(ast, variables);
|
|
599
|
+
}
|
|
600
|
+
return genericCreateIngest(ast, variables);
|
|
601
|
+
}
|
|
602
|
+
function publishDataIfChanged(params) {
|
|
603
|
+
const { store, key, ast, incoming, luvio, variables } = params;
|
|
604
|
+
const existing = store.readEntry(key);
|
|
605
|
+
if (existing === undefined || equals(ast, variables, existing, incoming) === false) {
|
|
606
|
+
const newData = merge(existing, incoming);
|
|
607
|
+
luvio.storePublish(key, newData);
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
function genericCreateIngest(ast, variables) {
|
|
611
|
+
let selections = ast.luvioSelections === undefined ? [] : ast.luvioSelections;
|
|
612
|
+
return (data, path, luvio, store, timestamp) => {
|
|
613
|
+
const { fullPath } = path;
|
|
614
|
+
for (let i = 0, len = selections.length; i < len; i += 1) {
|
|
615
|
+
const sel = getLuvioFieldNodeSelection(selections[i]);
|
|
616
|
+
if (sel.kind === 'ScalarFieldSelection') {
|
|
617
|
+
continue;
|
|
618
|
+
}
|
|
619
|
+
const { name: fieldName, alias } = sel;
|
|
620
|
+
const readPropertyName = alias === undefined ? fieldName : alias;
|
|
621
|
+
const propertyFullPath = `${fullPath}__${fieldName}`;
|
|
622
|
+
const writePropertyName = render(sel, variables);
|
|
623
|
+
const childPath = {
|
|
624
|
+
parent: {
|
|
625
|
+
existing: null,
|
|
626
|
+
key: fullPath,
|
|
627
|
+
data,
|
|
628
|
+
},
|
|
629
|
+
propertyName: readPropertyName,
|
|
630
|
+
fullPath: propertyFullPath,
|
|
631
|
+
};
|
|
632
|
+
data[writePropertyName] = createIngest$2(sel, variables)(data[readPropertyName], childPath, luvio, store, timestamp);
|
|
633
|
+
if (writePropertyName !== readPropertyName && data[readPropertyName] !== undefined) {
|
|
634
|
+
delete data[readPropertyName];
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
publishDataIfChanged({
|
|
638
|
+
ast,
|
|
639
|
+
luvio,
|
|
640
|
+
store,
|
|
641
|
+
key: fullPath,
|
|
642
|
+
variables: {},
|
|
643
|
+
incoming: data,
|
|
644
|
+
});
|
|
645
|
+
if (data && data.__typename !== undefined) {
|
|
646
|
+
luvio.publishStoreMetadata(fullPath, {
|
|
647
|
+
representationName: data.__typename,
|
|
648
|
+
namespace: namespace,
|
|
649
|
+
ttl: DEFAULT_GRAPHQL_TTL,
|
|
650
|
+
version: GRAPHQL_INGEST_VERSION,
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
return {
|
|
654
|
+
__ref: fullPath,
|
|
655
|
+
};
|
|
656
|
+
};
|
|
657
657
|
}
|
|
658
658
|
|
|
659
|
-
const CONNECTION_NODE_TYPE = 'Connection';
|
|
660
|
-
const TYPENAME_FIELD$1 = '__typename';
|
|
661
|
-
const PAGE_INFO_REQUIRED_FIELDS = ['hasNextPage', 'hasPreviousPage'];
|
|
662
|
-
const EDGE_REQUIRED_FIELDS = ['cursor'];
|
|
663
|
-
const PROPERTY_NAME_EDGES = 'edges';
|
|
664
|
-
const PROPERTY_NAME_PAGE_INFO = 'pageInfo';
|
|
665
|
-
const PROPERTY_NAME_TOTAL_COUNT = 'totalCount';
|
|
666
|
-
function keyBuilder(ast, variables) {
|
|
667
|
-
const { arguments: args, name } = ast;
|
|
668
|
-
if (args === undefined) {
|
|
669
|
-
return `${namespace}::${CONNECTION_NODE_TYPE}:${name}()`;
|
|
670
|
-
}
|
|
671
|
-
const serialized = render$1(args, variables);
|
|
672
|
-
return `${namespace}::${CONNECTION_NODE_TYPE}:${name}(${serialized})`;
|
|
673
|
-
}
|
|
674
|
-
function selectEdges(luvio, builder, ast, links, variables) {
|
|
675
|
-
const sink = [];
|
|
676
|
-
for (let i = 0, len = links.length; i < len; i += 1) {
|
|
677
|
-
builder.enterPath(i);
|
|
678
|
-
const link = links[i];
|
|
679
|
-
const resolved = followLink(luvio, ast, builder, link, variables);
|
|
680
|
-
builder.assignNonScalar(sink, i, resolved);
|
|
681
|
-
builder.exitPath();
|
|
682
|
-
}
|
|
683
|
-
return sink;
|
|
684
|
-
}
|
|
685
|
-
const createRead$2 = (luvio, ast, variables) => {
|
|
686
|
-
const selections = ast.luvioSelections === undefined ? [] : ast.luvioSelections;
|
|
687
|
-
return (source, builder) => {
|
|
688
|
-
const sink = {};
|
|
689
|
-
for (let i = 0, len = selections.length; i < len; i += 1) {
|
|
690
|
-
const sel = getLuvioFieldNodeSelection(selections[i]);
|
|
691
|
-
const { name, kind } = sel;
|
|
692
|
-
if (kind === 'ScalarFieldSelection') {
|
|
693
|
-
readScalarFieldSelection(builder, source, name, sink);
|
|
694
|
-
continue;
|
|
695
|
-
}
|
|
696
|
-
const readPropertyName = render(sel, variables);
|
|
697
|
-
builder.enterPath(readPropertyName);
|
|
698
|
-
const edges = resolveLink(builder, source[readPropertyName]);
|
|
699
|
-
if (edges === undefined) {
|
|
700
|
-
builder.exitPath();
|
|
701
|
-
break;
|
|
702
|
-
}
|
|
703
|
-
if (readPropertyName === PROPERTY_NAME_EDGES) {
|
|
704
|
-
const data = selectEdges(luvio, builder, sel, edges.value, variables);
|
|
705
|
-
builder.assignNonScalar(sink, readPropertyName, data);
|
|
706
|
-
}
|
|
707
|
-
else {
|
|
708
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
709
|
-
throw new Error('Not supported');
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
builder.exitPath();
|
|
713
|
-
}
|
|
714
|
-
return sink;
|
|
715
|
-
};
|
|
716
|
-
};
|
|
717
|
-
function ingestConnectionProperty(sel, data, path, luvio, store, timestamp, variables) {
|
|
718
|
-
const propertyName = sel.name;
|
|
719
|
-
switch (propertyName) {
|
|
720
|
-
case PROPERTY_NAME_EDGES:
|
|
721
|
-
return ingestConnectionEdges(sel, data, path, luvio, store, timestamp, variables);
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
function ingestConnectionEdges(sel, data, path, luvio, store, timestamp, variables) {
|
|
725
|
-
const key = path.fullPath;
|
|
726
|
-
const existing = store.readEntry(key);
|
|
727
|
-
let hasChanges = existing === undefined || data.length !== existing.length;
|
|
728
|
-
for (let i = 0, len = data.length; i < len; i += 1) {
|
|
729
|
-
const incomingItem = (data[i] = createIngest$2(sel, variables)(data[i], {
|
|
730
|
-
parent: {
|
|
731
|
-
data,
|
|
732
|
-
existing: null,
|
|
733
|
-
key,
|
|
734
|
-
},
|
|
735
|
-
propertyName: i,
|
|
736
|
-
fullPath: `${key}__${i}`,
|
|
737
|
-
}, luvio, store, timestamp));
|
|
738
|
-
const existingItem = existing !== undefined ? existing[i] : undefined;
|
|
739
|
-
if (existingItem === undefined || existingItem.__ref !== incomingItem.__ref) {
|
|
740
|
-
hasChanges = true;
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
if (hasChanges === true) {
|
|
744
|
-
luvio.storePublish(key, data);
|
|
745
|
-
}
|
|
746
|
-
luvio.publishStoreMetadata(key, {
|
|
747
|
-
representationName: CONNECTION_NODE_TYPE,
|
|
748
|
-
namespace: namespace,
|
|
749
|
-
ttl: DEFAULT_GRAPHQL_TTL,
|
|
750
|
-
version: GRAPHQL_INGEST_VERSION,
|
|
751
|
-
});
|
|
752
|
-
return {
|
|
753
|
-
__ref: key,
|
|
754
|
-
};
|
|
755
|
-
}
|
|
756
|
-
const createIngest$1 = (ast, key, variables) => {
|
|
757
|
-
const { luvioSelections } = ast;
|
|
758
|
-
const selections = luvioSelections === undefined ? [] : luvioSelections;
|
|
759
|
-
return (data, path, luvio, store, timestamp) => {
|
|
760
|
-
for (let i = 0, len = selections.length; i < len; i += 1) {
|
|
761
|
-
const sel = getLuvioFieldNodeSelection(selections[i]);
|
|
762
|
-
const { kind } = sel;
|
|
763
|
-
const propertyName = sel.name;
|
|
764
|
-
if (kind !== 'ObjectFieldSelection') {
|
|
765
|
-
continue;
|
|
766
|
-
}
|
|
767
|
-
data[propertyName] = ingestConnectionProperty(sel, data[propertyName], {
|
|
768
|
-
parent: {
|
|
769
|
-
existing: null,
|
|
770
|
-
key,
|
|
771
|
-
data,
|
|
772
|
-
},
|
|
773
|
-
fullPath: `${key}__${propertyName}`,
|
|
774
|
-
propertyName,
|
|
775
|
-
}, luvio, store, timestamp, variables);
|
|
776
|
-
}
|
|
777
|
-
publishDataIfChanged({
|
|
778
|
-
key,
|
|
779
|
-
luvio,
|
|
780
|
-
store,
|
|
781
|
-
incoming: data,
|
|
782
|
-
variables: {},
|
|
783
|
-
ast,
|
|
784
|
-
});
|
|
785
|
-
const typeName = data.__typename;
|
|
786
|
-
luvio.publishStoreMetadata(key, {
|
|
787
|
-
representationName: typeName,
|
|
788
|
-
namespace: namespace,
|
|
789
|
-
ttl: DEFAULT_GRAPHQL_TTL,
|
|
790
|
-
version: GRAPHQL_INGEST_VERSION,
|
|
791
|
-
});
|
|
792
|
-
return {
|
|
793
|
-
__ref: key,
|
|
794
|
-
};
|
|
795
|
-
};
|
|
796
|
-
};
|
|
797
|
-
function serialize(def, state) {
|
|
798
|
-
const { luvioSelections, arguments: args } = def;
|
|
799
|
-
if (luvioSelections === undefined) {
|
|
800
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
801
|
-
throw new Error('Connection field node must have selections');
|
|
802
|
-
}
|
|
803
|
-
return '';
|
|
804
|
-
}
|
|
805
|
-
const argsString = args === undefined || args.length === 0 ? '' : `(${serializeArguments(args)})`;
|
|
806
|
-
const seenFields = {};
|
|
807
|
-
const serializedFields = [];
|
|
808
|
-
for (let i = 0; i < luvioSelections.length; i++) {
|
|
809
|
-
const sel = getLuvioFieldNodeSelection(luvioSelections[i]);
|
|
810
|
-
const { name: fieldName } = sel;
|
|
811
|
-
seenFields[fieldName] = true;
|
|
812
|
-
if (fieldName === PROPERTY_NAME_PAGE_INFO) {
|
|
813
|
-
serializedFields.push(serializePageInfo(sel, state));
|
|
814
|
-
}
|
|
815
|
-
else if (fieldName === PROPERTY_NAME_EDGES) {
|
|
816
|
-
serializedFields.push(serializeEdges(sel, state));
|
|
817
|
-
}
|
|
818
|
-
else {
|
|
819
|
-
serializedFields.push(serializeFieldNode(sel, state));
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
appendRequiredConnectionFields(seenFields, serializedFields);
|
|
823
|
-
return `${serializeFieldNodeName(def)}${argsString} { ${serializedFields.join(' ')} }`;
|
|
824
|
-
}
|
|
825
|
-
function serializeEdges(node, state) {
|
|
826
|
-
if (!isLuvioFieldNodeObjectFieldNode(node)) {
|
|
827
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
828
|
-
throw new Error('PageInfo must be an ObjectFieldNode');
|
|
829
|
-
}
|
|
830
|
-
return '';
|
|
831
|
-
}
|
|
832
|
-
const { luvioSelections } = node;
|
|
833
|
-
if (luvioSelections === undefined)
|
|
834
|
-
return '';
|
|
835
|
-
const seenFields = {};
|
|
836
|
-
const serializedFields = [];
|
|
837
|
-
for (let i = 0; i < luvioSelections.length; i++) {
|
|
838
|
-
const sel = getLuvioFieldNodeSelection(luvioSelections[i]);
|
|
839
|
-
seenFields[sel.name] = true;
|
|
840
|
-
serializedFields.push(serializeFieldNode(sel, state));
|
|
841
|
-
}
|
|
842
|
-
appendRequiredFields(EDGE_REQUIRED_FIELDS, seenFields, serializedFields);
|
|
843
|
-
insertTypeName(seenFields, serializedFields);
|
|
844
|
-
return `${serializeFieldNodeName(node)} { ${serializedFields.join(' ')} }`;
|
|
845
|
-
}
|
|
846
|
-
function serializePageInfo(node, state) {
|
|
847
|
-
if (!isLuvioFieldNodeObjectFieldNode(node)) {
|
|
848
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
849
|
-
throw new Error('PageInfo must be an ObjectFieldNode');
|
|
850
|
-
}
|
|
851
|
-
return '';
|
|
852
|
-
}
|
|
853
|
-
const { luvioSelections } = node;
|
|
854
|
-
if (luvioSelections === undefined)
|
|
855
|
-
return '';
|
|
856
|
-
const seenFields = {};
|
|
857
|
-
const serializedFields = [];
|
|
858
|
-
for (let i = 0; i < luvioSelections.length; i++) {
|
|
859
|
-
const sel = getLuvioFieldNodeSelection(luvioSelections[i]);
|
|
860
|
-
seenFields[sel.name] = true;
|
|
861
|
-
serializedFields.push(serializeFieldNode(sel, state));
|
|
862
|
-
}
|
|
863
|
-
appendRequiredFields(PAGE_INFO_REQUIRED_FIELDS, seenFields, serializedFields);
|
|
864
|
-
return `${serializeFieldNodeName(node)} { ${serializedFields.join(' ')} }`;
|
|
865
|
-
}
|
|
866
|
-
function appendRequiredFields(requiredFields, seenFields, result) {
|
|
867
|
-
for (let i = 0; i < requiredFields.length; i++) {
|
|
868
|
-
const fieldName = requiredFields[i];
|
|
869
|
-
if (seenFields[fieldName] !== true) {
|
|
870
|
-
result.push(fieldName);
|
|
871
|
-
}
|
|
872
|
-
}
|
|
873
|
-
}
|
|
874
|
-
function appendRequiredConnectionFields(seenFields, result) {
|
|
875
|
-
if (seenFields[PROPERTY_NAME_PAGE_INFO] !== true) {
|
|
876
|
-
result.push('pageInfo { hasNextPage hasPreviousPage }');
|
|
877
|
-
}
|
|
878
|
-
if (seenFields[PROPERTY_NAME_TOTAL_COUNT] !== true) {
|
|
879
|
-
result.push(PROPERTY_NAME_TOTAL_COUNT);
|
|
880
|
-
}
|
|
881
|
-
insertTypeName(seenFields, result);
|
|
882
|
-
}
|
|
883
|
-
function insertTypeName(seenFields, result) {
|
|
884
|
-
if (seenFields[TYPENAME_FIELD$1] !== true) {
|
|
885
|
-
result.unshift(TYPENAME_FIELD$1);
|
|
886
|
-
}
|
|
659
|
+
const CONNECTION_NODE_TYPE = 'Connection';
|
|
660
|
+
const TYPENAME_FIELD$1 = '__typename';
|
|
661
|
+
const PAGE_INFO_REQUIRED_FIELDS = ['hasNextPage', 'hasPreviousPage'];
|
|
662
|
+
const EDGE_REQUIRED_FIELDS = ['cursor'];
|
|
663
|
+
const PROPERTY_NAME_EDGES = 'edges';
|
|
664
|
+
const PROPERTY_NAME_PAGE_INFO = 'pageInfo';
|
|
665
|
+
const PROPERTY_NAME_TOTAL_COUNT = 'totalCount';
|
|
666
|
+
function keyBuilder(ast, variables) {
|
|
667
|
+
const { arguments: args, name } = ast;
|
|
668
|
+
if (args === undefined) {
|
|
669
|
+
return `${namespace}::${CONNECTION_NODE_TYPE}:${name}()`;
|
|
670
|
+
}
|
|
671
|
+
const serialized = render$1(args, variables);
|
|
672
|
+
return `${namespace}::${CONNECTION_NODE_TYPE}:${name}(${serialized})`;
|
|
673
|
+
}
|
|
674
|
+
function selectEdges(luvio, builder, ast, links, variables) {
|
|
675
|
+
const sink = [];
|
|
676
|
+
for (let i = 0, len = links.length; i < len; i += 1) {
|
|
677
|
+
builder.enterPath(i);
|
|
678
|
+
const link = links[i];
|
|
679
|
+
const resolved = followLink(luvio, ast, builder, link, variables);
|
|
680
|
+
builder.assignNonScalar(sink, i, resolved);
|
|
681
|
+
builder.exitPath();
|
|
682
|
+
}
|
|
683
|
+
return sink;
|
|
684
|
+
}
|
|
685
|
+
const createRead$2 = (luvio, ast, variables) => {
|
|
686
|
+
const selections = ast.luvioSelections === undefined ? [] : ast.luvioSelections;
|
|
687
|
+
return (source, builder) => {
|
|
688
|
+
const sink = {};
|
|
689
|
+
for (let i = 0, len = selections.length; i < len; i += 1) {
|
|
690
|
+
const sel = getLuvioFieldNodeSelection(selections[i]);
|
|
691
|
+
const { name, kind } = sel;
|
|
692
|
+
if (kind === 'ScalarFieldSelection') {
|
|
693
|
+
readScalarFieldSelection(builder, source, name, sink);
|
|
694
|
+
continue;
|
|
695
|
+
}
|
|
696
|
+
const readPropertyName = render(sel, variables);
|
|
697
|
+
builder.enterPath(readPropertyName);
|
|
698
|
+
const edges = resolveLink(builder, source[readPropertyName]);
|
|
699
|
+
if (edges === undefined) {
|
|
700
|
+
builder.exitPath();
|
|
701
|
+
break;
|
|
702
|
+
}
|
|
703
|
+
if (readPropertyName === PROPERTY_NAME_EDGES) {
|
|
704
|
+
const data = selectEdges(luvio, builder, sel, edges.value, variables);
|
|
705
|
+
builder.assignNonScalar(sink, readPropertyName, data);
|
|
706
|
+
}
|
|
707
|
+
else {
|
|
708
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
709
|
+
throw new Error('Not supported');
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
builder.exitPath();
|
|
713
|
+
}
|
|
714
|
+
return sink;
|
|
715
|
+
};
|
|
716
|
+
};
|
|
717
|
+
function ingestConnectionProperty(sel, data, path, luvio, store, timestamp, variables) {
|
|
718
|
+
const propertyName = sel.name;
|
|
719
|
+
switch (propertyName) {
|
|
720
|
+
case PROPERTY_NAME_EDGES:
|
|
721
|
+
return ingestConnectionEdges(sel, data, path, luvio, store, timestamp, variables);
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
function ingestConnectionEdges(sel, data, path, luvio, store, timestamp, variables) {
|
|
725
|
+
const key = path.fullPath;
|
|
726
|
+
const existing = store.readEntry(key);
|
|
727
|
+
let hasChanges = existing === undefined || data.length !== existing.length;
|
|
728
|
+
for (let i = 0, len = data.length; i < len; i += 1) {
|
|
729
|
+
const incomingItem = (data[i] = createIngest$2(sel, variables)(data[i], {
|
|
730
|
+
parent: {
|
|
731
|
+
data,
|
|
732
|
+
existing: null,
|
|
733
|
+
key,
|
|
734
|
+
},
|
|
735
|
+
propertyName: i,
|
|
736
|
+
fullPath: `${key}__${i}`,
|
|
737
|
+
}, luvio, store, timestamp));
|
|
738
|
+
const existingItem = existing !== undefined ? existing[i] : undefined;
|
|
739
|
+
if (existingItem === undefined || existingItem.__ref !== incomingItem.__ref) {
|
|
740
|
+
hasChanges = true;
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
if (hasChanges === true) {
|
|
744
|
+
luvio.storePublish(key, data);
|
|
745
|
+
}
|
|
746
|
+
luvio.publishStoreMetadata(key, {
|
|
747
|
+
representationName: CONNECTION_NODE_TYPE,
|
|
748
|
+
namespace: namespace,
|
|
749
|
+
ttl: DEFAULT_GRAPHQL_TTL,
|
|
750
|
+
version: GRAPHQL_INGEST_VERSION,
|
|
751
|
+
});
|
|
752
|
+
return {
|
|
753
|
+
__ref: key,
|
|
754
|
+
};
|
|
755
|
+
}
|
|
756
|
+
const createIngest$1 = (ast, key, variables) => {
|
|
757
|
+
const { luvioSelections } = ast;
|
|
758
|
+
const selections = luvioSelections === undefined ? [] : luvioSelections;
|
|
759
|
+
return (data, path, luvio, store, timestamp) => {
|
|
760
|
+
for (let i = 0, len = selections.length; i < len; i += 1) {
|
|
761
|
+
const sel = getLuvioFieldNodeSelection(selections[i]);
|
|
762
|
+
const { kind } = sel;
|
|
763
|
+
const propertyName = sel.name;
|
|
764
|
+
if (kind !== 'ObjectFieldSelection') {
|
|
765
|
+
continue;
|
|
766
|
+
}
|
|
767
|
+
data[propertyName] = ingestConnectionProperty(sel, data[propertyName], {
|
|
768
|
+
parent: {
|
|
769
|
+
existing: null,
|
|
770
|
+
key,
|
|
771
|
+
data,
|
|
772
|
+
},
|
|
773
|
+
fullPath: `${key}__${propertyName}`,
|
|
774
|
+
propertyName,
|
|
775
|
+
}, luvio, store, timestamp, variables);
|
|
776
|
+
}
|
|
777
|
+
publishDataIfChanged({
|
|
778
|
+
key,
|
|
779
|
+
luvio,
|
|
780
|
+
store,
|
|
781
|
+
incoming: data,
|
|
782
|
+
variables: {},
|
|
783
|
+
ast,
|
|
784
|
+
});
|
|
785
|
+
const typeName = data.__typename;
|
|
786
|
+
luvio.publishStoreMetadata(key, {
|
|
787
|
+
representationName: typeName,
|
|
788
|
+
namespace: namespace,
|
|
789
|
+
ttl: DEFAULT_GRAPHQL_TTL,
|
|
790
|
+
version: GRAPHQL_INGEST_VERSION,
|
|
791
|
+
});
|
|
792
|
+
return {
|
|
793
|
+
__ref: key,
|
|
794
|
+
};
|
|
795
|
+
};
|
|
796
|
+
};
|
|
797
|
+
function serialize(def, state) {
|
|
798
|
+
const { luvioSelections, arguments: args } = def;
|
|
799
|
+
if (luvioSelections === undefined) {
|
|
800
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
801
|
+
throw new Error('Connection field node must have selections');
|
|
802
|
+
}
|
|
803
|
+
return '';
|
|
804
|
+
}
|
|
805
|
+
const argsString = args === undefined || args.length === 0 ? '' : `(${serializeArguments(args)})`;
|
|
806
|
+
const seenFields = {};
|
|
807
|
+
const serializedFields = [];
|
|
808
|
+
for (let i = 0; i < luvioSelections.length; i++) {
|
|
809
|
+
const sel = getLuvioFieldNodeSelection(luvioSelections[i]);
|
|
810
|
+
const { name: fieldName } = sel;
|
|
811
|
+
seenFields[fieldName] = true;
|
|
812
|
+
if (fieldName === PROPERTY_NAME_PAGE_INFO) {
|
|
813
|
+
serializedFields.push(serializePageInfo(sel, state));
|
|
814
|
+
}
|
|
815
|
+
else if (fieldName === PROPERTY_NAME_EDGES) {
|
|
816
|
+
serializedFields.push(serializeEdges(sel, state));
|
|
817
|
+
}
|
|
818
|
+
else {
|
|
819
|
+
serializedFields.push(serializeFieldNode(sel, state));
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
appendRequiredConnectionFields(seenFields, serializedFields);
|
|
823
|
+
return `${serializeFieldNodeName(def)}${argsString} { ${serializedFields.join(' ')} }`;
|
|
824
|
+
}
|
|
825
|
+
function serializeEdges(node, state) {
|
|
826
|
+
if (!isLuvioFieldNodeObjectFieldNode(node)) {
|
|
827
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
828
|
+
throw new Error('PageInfo must be an ObjectFieldNode');
|
|
829
|
+
}
|
|
830
|
+
return '';
|
|
831
|
+
}
|
|
832
|
+
const { luvioSelections } = node;
|
|
833
|
+
if (luvioSelections === undefined)
|
|
834
|
+
return '';
|
|
835
|
+
const seenFields = {};
|
|
836
|
+
const serializedFields = [];
|
|
837
|
+
for (let i = 0; i < luvioSelections.length; i++) {
|
|
838
|
+
const sel = getLuvioFieldNodeSelection(luvioSelections[i]);
|
|
839
|
+
seenFields[sel.name] = true;
|
|
840
|
+
serializedFields.push(serializeFieldNode(sel, state));
|
|
841
|
+
}
|
|
842
|
+
appendRequiredFields(EDGE_REQUIRED_FIELDS, seenFields, serializedFields);
|
|
843
|
+
insertTypeName(seenFields, serializedFields);
|
|
844
|
+
return `${serializeFieldNodeName(node)} { ${serializedFields.join(' ')} }`;
|
|
845
|
+
}
|
|
846
|
+
function serializePageInfo(node, state) {
|
|
847
|
+
if (!isLuvioFieldNodeObjectFieldNode(node)) {
|
|
848
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
849
|
+
throw new Error('PageInfo must be an ObjectFieldNode');
|
|
850
|
+
}
|
|
851
|
+
return '';
|
|
852
|
+
}
|
|
853
|
+
const { luvioSelections } = node;
|
|
854
|
+
if (luvioSelections === undefined)
|
|
855
|
+
return '';
|
|
856
|
+
const seenFields = {};
|
|
857
|
+
const serializedFields = [];
|
|
858
|
+
for (let i = 0; i < luvioSelections.length; i++) {
|
|
859
|
+
const sel = getLuvioFieldNodeSelection(luvioSelections[i]);
|
|
860
|
+
seenFields[sel.name] = true;
|
|
861
|
+
serializedFields.push(serializeFieldNode(sel, state));
|
|
862
|
+
}
|
|
863
|
+
appendRequiredFields(PAGE_INFO_REQUIRED_FIELDS, seenFields, serializedFields);
|
|
864
|
+
return `${serializeFieldNodeName(node)} { ${serializedFields.join(' ')} }`;
|
|
865
|
+
}
|
|
866
|
+
function appendRequiredFields(requiredFields, seenFields, result) {
|
|
867
|
+
for (let i = 0; i < requiredFields.length; i++) {
|
|
868
|
+
const fieldName = requiredFields[i];
|
|
869
|
+
if (seenFields[fieldName] !== true) {
|
|
870
|
+
result.push(fieldName);
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
function appendRequiredConnectionFields(seenFields, result) {
|
|
875
|
+
if (seenFields[PROPERTY_NAME_PAGE_INFO] !== true) {
|
|
876
|
+
result.push('pageInfo { hasNextPage hasPreviousPage }');
|
|
877
|
+
}
|
|
878
|
+
if (seenFields[PROPERTY_NAME_TOTAL_COUNT] !== true) {
|
|
879
|
+
result.push(PROPERTY_NAME_TOTAL_COUNT);
|
|
880
|
+
}
|
|
881
|
+
insertTypeName(seenFields, result);
|
|
882
|
+
}
|
|
883
|
+
function insertTypeName(seenFields, result) {
|
|
884
|
+
if (seenFields[TYPENAME_FIELD$1] !== true) {
|
|
885
|
+
result.unshift(TYPENAME_FIELD$1);
|
|
886
|
+
}
|
|
887
887
|
}
|
|
888
888
|
|
|
889
|
-
function createCustomFieldRead(luvio, sel, variables) {
|
|
890
|
-
if (sel.type === 'Connection') {
|
|
891
|
-
return createRead$2(luvio, sel, variables);
|
|
892
|
-
}
|
|
893
|
-
return createRead$3(luvio, sel, variables);
|
|
894
|
-
}
|
|
895
|
-
function createRead$1(luvio, ast, variables) {
|
|
896
|
-
if (ast.kind === 'CustomFieldSelection') {
|
|
897
|
-
return createCustomFieldRead(luvio, ast, variables);
|
|
898
|
-
}
|
|
899
|
-
if (ast.kind === 'FragmentSpread' ||
|
|
900
|
-
ast.kind === 'InlineFragment' ||
|
|
901
|
-
ast.kind === 'ScalarFieldSelection') {
|
|
902
|
-
// eslint-disable-next-line @salesforce/lds/no-error-in-production
|
|
903
|
-
throw new Error('"FragmentSpread" and "InlineFragment" currently not supported');
|
|
904
|
-
}
|
|
905
|
-
return genericCreateRead(luvio, ast, variables);
|
|
906
|
-
}
|
|
907
|
-
const genericCreateRead = (luvio, ast, variables) => {
|
|
908
|
-
const selections = ast.luvioSelections === undefined ? [] : ast.luvioSelections;
|
|
909
|
-
return (source, builder) => {
|
|
910
|
-
const sink = {};
|
|
911
|
-
for (let i = 0, len = selections.length; i < len; i += 1) {
|
|
912
|
-
const sel = getLuvioFieldNodeSelection(selections[i]);
|
|
913
|
-
const { name: fieldName, alias } = sel;
|
|
914
|
-
const propertyName = alias === undefined ? fieldName : alias;
|
|
915
|
-
builder.enterPath(fieldName);
|
|
916
|
-
switch (sel.kind) {
|
|
917
|
-
case 'ScalarFieldSelection':
|
|
918
|
-
readScalarFieldSelection(builder, source, fieldName, sink);
|
|
919
|
-
break;
|
|
920
|
-
default: {
|
|
921
|
-
const data = followLink(luvio, sel, builder, source[render(sel, variables)], variables);
|
|
922
|
-
builder.assignNonScalar(sink, propertyName, data);
|
|
923
|
-
}
|
|
924
|
-
}
|
|
925
|
-
builder.exitPath();
|
|
926
|
-
}
|
|
927
|
-
return sink;
|
|
928
|
-
};
|
|
889
|
+
function createCustomFieldRead(luvio, sel, variables) {
|
|
890
|
+
if (sel.type === 'Connection') {
|
|
891
|
+
return createRead$2(luvio, sel, variables);
|
|
892
|
+
}
|
|
893
|
+
return createRead$3(luvio, sel, variables);
|
|
894
|
+
}
|
|
895
|
+
function createRead$1(luvio, ast, variables) {
|
|
896
|
+
if (ast.kind === 'CustomFieldSelection') {
|
|
897
|
+
return createCustomFieldRead(luvio, ast, variables);
|
|
898
|
+
}
|
|
899
|
+
if (ast.kind === 'FragmentSpread' ||
|
|
900
|
+
ast.kind === 'InlineFragment' ||
|
|
901
|
+
ast.kind === 'ScalarFieldSelection') {
|
|
902
|
+
// eslint-disable-next-line @salesforce/lds/no-error-in-production
|
|
903
|
+
throw new Error('"FragmentSpread" and "InlineFragment" currently not supported');
|
|
904
|
+
}
|
|
905
|
+
return genericCreateRead(luvio, ast, variables);
|
|
906
|
+
}
|
|
907
|
+
const genericCreateRead = (luvio, ast, variables) => {
|
|
908
|
+
const selections = ast.luvioSelections === undefined ? [] : ast.luvioSelections;
|
|
909
|
+
return (source, builder) => {
|
|
910
|
+
const sink = {};
|
|
911
|
+
for (let i = 0, len = selections.length; i < len; i += 1) {
|
|
912
|
+
const sel = getLuvioFieldNodeSelection(selections[i]);
|
|
913
|
+
const { name: fieldName, alias } = sel;
|
|
914
|
+
const propertyName = alias === undefined ? fieldName : alias;
|
|
915
|
+
builder.enterPath(fieldName);
|
|
916
|
+
switch (sel.kind) {
|
|
917
|
+
case 'ScalarFieldSelection':
|
|
918
|
+
readScalarFieldSelection(builder, source, fieldName, sink);
|
|
919
|
+
break;
|
|
920
|
+
default: {
|
|
921
|
+
const data = followLink(luvio, sel, builder, source[render(sel, variables)], variables);
|
|
922
|
+
builder.assignNonScalar(sink, propertyName, data);
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
builder.exitPath();
|
|
926
|
+
}
|
|
927
|
+
return sink;
|
|
928
|
+
};
|
|
929
929
|
};
|
|
930
930
|
|
|
931
|
-
var PropertyLookupResultState;
|
|
932
|
-
(function (PropertyLookupResultState) {
|
|
933
|
-
PropertyLookupResultState[PropertyLookupResultState["Missing"] = 0] = "Missing";
|
|
934
|
-
PropertyLookupResultState[PropertyLookupResultState["Present"] = 1] = "Present";
|
|
935
|
-
})(PropertyLookupResultState || (PropertyLookupResultState = {}));
|
|
936
|
-
const objectPrototypeHasOwnProperty = Object.prototype.hasOwnProperty;
|
|
937
|
-
function propertyLookup(builder, key, source) {
|
|
938
|
-
if (objectPrototypeHasOwnProperty.call(source, key) === false) {
|
|
939
|
-
builder.markMissing();
|
|
940
|
-
return {
|
|
941
|
-
state: PropertyLookupResultState.Missing,
|
|
942
|
-
};
|
|
943
|
-
}
|
|
944
|
-
return {
|
|
945
|
-
state: PropertyLookupResultState.Present,
|
|
946
|
-
value: source[key],
|
|
947
|
-
};
|
|
948
|
-
}
|
|
949
|
-
function markStoreResolveResultSeen(builder, state) {
|
|
950
|
-
const { redirects, resolvedKey } = state;
|
|
951
|
-
builder.markSeenId(resolvedKey);
|
|
952
|
-
const { length: len } = redirects;
|
|
953
|
-
if (len === 0) {
|
|
954
|
-
return;
|
|
955
|
-
}
|
|
956
|
-
for (let i = 0; i < len; i += 1) {
|
|
957
|
-
builder.markSeenId(redirects[i]);
|
|
958
|
-
}
|
|
959
|
-
}
|
|
960
|
-
function resolveKey(builder, key) {
|
|
961
|
-
const { StoreResolveResultState } = builder;
|
|
962
|
-
const lookup = builder.storeLookup(key);
|
|
963
|
-
markStoreResolveResultSeen(builder, lookup);
|
|
964
|
-
switch (lookup.state) {
|
|
965
|
-
case StoreResolveResultState.NotPresent:
|
|
966
|
-
builder.markMissingLink(key);
|
|
967
|
-
return;
|
|
968
|
-
case StoreResolveResultState.Stale:
|
|
969
|
-
builder.markStale();
|
|
970
|
-
return lookup;
|
|
971
|
-
case StoreResolveResultState.Error:
|
|
972
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
973
|
-
throw new Error('TODO: Implement error links');
|
|
974
|
-
}
|
|
975
|
-
else {
|
|
976
|
-
return;
|
|
977
|
-
}
|
|
978
|
-
}
|
|
979
|
-
return lookup;
|
|
980
|
-
}
|
|
981
|
-
function resolveLink(builder, storeLink) {
|
|
982
|
-
const { StoreLinkStateValues } = builder;
|
|
983
|
-
const linkState = builder.getLinkState(storeLink);
|
|
984
|
-
switch (linkState.state) {
|
|
985
|
-
case StoreLinkStateValues.RefNotPresent:
|
|
986
|
-
case StoreLinkStateValues.NotPresent:
|
|
987
|
-
case StoreLinkStateValues.Missing:
|
|
988
|
-
builder.markMissing();
|
|
989
|
-
return;
|
|
990
|
-
case StoreLinkStateValues.Pending:
|
|
991
|
-
builder.markPending();
|
|
992
|
-
return;
|
|
993
|
-
case StoreLinkStateValues.Null:
|
|
994
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
995
|
-
throw new Error(`TODO: Invalid Link State. Link on "${builder.currentPath.fullPath}"`);
|
|
996
|
-
}
|
|
997
|
-
else {
|
|
998
|
-
return;
|
|
999
|
-
}
|
|
1000
|
-
}
|
|
1001
|
-
const { key: __ref } = linkState;
|
|
1002
|
-
return resolveKey(builder, __ref);
|
|
1003
|
-
}
|
|
1004
|
-
function followLink(luvio, sel, builder, storeLink, variables) {
|
|
1005
|
-
const linkState = resolveLink(builder, storeLink);
|
|
1006
|
-
if (linkState === undefined) {
|
|
1007
|
-
return;
|
|
1008
|
-
}
|
|
1009
|
-
const { value } = linkState;
|
|
1010
|
-
return createRead$1(luvio, sel, variables)(value, builder);
|
|
1011
|
-
}
|
|
1012
|
-
function getLuvioFieldNodeSelection(ast) {
|
|
1013
|
-
const { kind } = ast;
|
|
1014
|
-
if (kind === 'FragmentSpread' || kind === 'InlineFragment') {
|
|
1015
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
1016
|
-
throw new Error('"FragmentSpread" and "InlineFragment" currently not supported');
|
|
1017
|
-
}
|
|
1018
|
-
}
|
|
1019
|
-
return ast;
|
|
931
|
+
var PropertyLookupResultState;
|
|
932
|
+
(function (PropertyLookupResultState) {
|
|
933
|
+
PropertyLookupResultState[PropertyLookupResultState["Missing"] = 0] = "Missing";
|
|
934
|
+
PropertyLookupResultState[PropertyLookupResultState["Present"] = 1] = "Present";
|
|
935
|
+
})(PropertyLookupResultState || (PropertyLookupResultState = {}));
|
|
936
|
+
const objectPrototypeHasOwnProperty = Object.prototype.hasOwnProperty;
|
|
937
|
+
function propertyLookup(builder, key, source) {
|
|
938
|
+
if (objectPrototypeHasOwnProperty.call(source, key) === false) {
|
|
939
|
+
builder.markMissing();
|
|
940
|
+
return {
|
|
941
|
+
state: PropertyLookupResultState.Missing,
|
|
942
|
+
};
|
|
943
|
+
}
|
|
944
|
+
return {
|
|
945
|
+
state: PropertyLookupResultState.Present,
|
|
946
|
+
value: source[key],
|
|
947
|
+
};
|
|
948
|
+
}
|
|
949
|
+
function markStoreResolveResultSeen(builder, state) {
|
|
950
|
+
const { redirects, resolvedKey } = state;
|
|
951
|
+
builder.markSeenId(resolvedKey);
|
|
952
|
+
const { length: len } = redirects;
|
|
953
|
+
if (len === 0) {
|
|
954
|
+
return;
|
|
955
|
+
}
|
|
956
|
+
for (let i = 0; i < len; i += 1) {
|
|
957
|
+
builder.markSeenId(redirects[i]);
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
function resolveKey(builder, key) {
|
|
961
|
+
const { StoreResolveResultState } = builder;
|
|
962
|
+
const lookup = builder.storeLookup(key);
|
|
963
|
+
markStoreResolveResultSeen(builder, lookup);
|
|
964
|
+
switch (lookup.state) {
|
|
965
|
+
case StoreResolveResultState.NotPresent:
|
|
966
|
+
builder.markMissingLink(key);
|
|
967
|
+
return;
|
|
968
|
+
case StoreResolveResultState.Stale:
|
|
969
|
+
builder.markStale();
|
|
970
|
+
return lookup;
|
|
971
|
+
case StoreResolveResultState.Error:
|
|
972
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
973
|
+
throw new Error('TODO: Implement error links');
|
|
974
|
+
}
|
|
975
|
+
else {
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
return lookup;
|
|
980
|
+
}
|
|
981
|
+
function resolveLink(builder, storeLink) {
|
|
982
|
+
const { StoreLinkStateValues } = builder;
|
|
983
|
+
const linkState = builder.getLinkState(storeLink);
|
|
984
|
+
switch (linkState.state) {
|
|
985
|
+
case StoreLinkStateValues.RefNotPresent:
|
|
986
|
+
case StoreLinkStateValues.NotPresent:
|
|
987
|
+
case StoreLinkStateValues.Missing:
|
|
988
|
+
builder.markMissing();
|
|
989
|
+
return;
|
|
990
|
+
case StoreLinkStateValues.Pending:
|
|
991
|
+
builder.markPending();
|
|
992
|
+
return;
|
|
993
|
+
case StoreLinkStateValues.Null:
|
|
994
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
995
|
+
throw new Error(`TODO: Invalid Link State. Link on "${builder.currentPath.fullPath}"`);
|
|
996
|
+
}
|
|
997
|
+
else {
|
|
998
|
+
return;
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
const { key: __ref } = linkState;
|
|
1002
|
+
return resolveKey(builder, __ref);
|
|
1003
|
+
}
|
|
1004
|
+
function followLink(luvio, sel, builder, storeLink, variables) {
|
|
1005
|
+
const linkState = resolveLink(builder, storeLink);
|
|
1006
|
+
if (linkState === undefined) {
|
|
1007
|
+
return;
|
|
1008
|
+
}
|
|
1009
|
+
const { value } = linkState;
|
|
1010
|
+
return createRead$1(luvio, sel, variables)(value, builder);
|
|
1011
|
+
}
|
|
1012
|
+
function getLuvioFieldNodeSelection(ast) {
|
|
1013
|
+
const { kind } = ast;
|
|
1014
|
+
if (kind === 'FragmentSpread' || kind === 'InlineFragment') {
|
|
1015
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
1016
|
+
throw new Error('"FragmentSpread" and "InlineFragment" currently not supported');
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
return ast;
|
|
1020
1020
|
}
|
|
1021
1021
|
|
|
1022
|
-
const TYPENAME_FIELD = '__typename';
|
|
1023
|
-
const KIND_OBJECT_FIELD_SELECTION = 'ObjectFieldSelection';
|
|
1024
|
-
function serializeFieldNodeName(node) {
|
|
1025
|
-
const { name, alias } = node;
|
|
1026
|
-
return alias === undefined ? `${name}` : `${alias}: ${name}`;
|
|
1027
|
-
}
|
|
1028
|
-
function serializeSelections(selections, state) {
|
|
1029
|
-
if (selections === undefined) {
|
|
1030
|
-
return '';
|
|
1031
|
-
}
|
|
1032
|
-
let str = '';
|
|
1033
|
-
for (let i = 0, len = selections.length; i < len; i += 1) {
|
|
1034
|
-
const def = serializeFieldNode(selections[i], state);
|
|
1035
|
-
str = `${str}${def}`;
|
|
1036
|
-
}
|
|
1037
|
-
return str;
|
|
1038
|
-
}
|
|
1039
|
-
function serializeFieldNode(def, state) {
|
|
1040
|
-
const { kind } = def;
|
|
1041
|
-
switch (kind) {
|
|
1042
|
-
case 'ObjectFieldSelection':
|
|
1043
|
-
return serializeObjectFieldNode(def, state);
|
|
1044
|
-
case 'CustomFieldSelection':
|
|
1045
|
-
return serializeCustomFieldNode(def, state);
|
|
1046
|
-
case 'ScalarFieldSelection':
|
|
1047
|
-
return serializeScalarFieldNode(def);
|
|
1048
|
-
}
|
|
1049
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
1050
|
-
throw new Error(`Unable to serialize graphql query, unsupported field node "${kind}"`);
|
|
1051
|
-
}
|
|
1052
|
-
return '';
|
|
1053
|
-
}
|
|
1054
|
-
function serializeObjectFieldNode(def, state) {
|
|
1055
|
-
const { luvioSelections, arguments: defArgs } = def;
|
|
1056
|
-
const args = defArgs === undefined ? '' : `(${serializeArguments(defArgs)})`;
|
|
1057
|
-
return `${serializeFieldNodeName(def)}${args} { ${TYPENAME_FIELD} ${serializeSelections(luvioSelections, state)} }`;
|
|
1058
|
-
}
|
|
1059
|
-
function serializeCustomFieldNode(def, state) {
|
|
1060
|
-
const { type } = def;
|
|
1061
|
-
switch (type) {
|
|
1062
|
-
case 'Connection':
|
|
1063
|
-
return serialize(def, state);
|
|
1064
|
-
case 'Record':
|
|
1065
|
-
return serializeCustomFieldRecord(def, state);
|
|
1066
|
-
}
|
|
1067
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
1068
|
-
throw new Error(`Unable to serialize graphql query, unsupported CustomField type "${type}"`);
|
|
1069
|
-
}
|
|
1070
|
-
return '';
|
|
1071
|
-
}
|
|
1072
|
-
function serializeScalarFieldNode(def) {
|
|
1073
|
-
return `${serializeFieldNodeName(def)}, `;
|
|
1074
|
-
}
|
|
1075
|
-
function serializeRecordSelections(selections, state) {
|
|
1076
|
-
if (selections === undefined) {
|
|
1077
|
-
return '';
|
|
1078
|
-
}
|
|
1079
|
-
let str = '';
|
|
1080
|
-
for (let i = 0, len = selections.length; i < len; i += 1) {
|
|
1081
|
-
const sel = getLuvioFieldNodeSelection(selections[i]);
|
|
1082
|
-
const def = isLuvioFieldNodeObjectFieldNode(sel)
|
|
1083
|
-
? serializeObjectFieldNodeUnderRecord(sel)
|
|
1084
|
-
: serializeFieldNode(sel, state);
|
|
1085
|
-
str = `${str}${def}`;
|
|
1086
|
-
}
|
|
1087
|
-
return str;
|
|
1088
|
-
}
|
|
1089
|
-
function isLuvioFieldNodeObjectFieldNode(node) {
|
|
1090
|
-
return node.kind === KIND_OBJECT_FIELD_SELECTION;
|
|
1091
|
-
}
|
|
1092
|
-
function serializeObjectFieldNodeUnderRecord(node) {
|
|
1093
|
-
const { luvioSelections, arguments: nodeArgs, name: nodeName } = node;
|
|
1094
|
-
const fields = {};
|
|
1095
|
-
let result = ``;
|
|
1096
|
-
if (luvioSelections === undefined) {
|
|
1097
|
-
// eslint-disable-next-line @salesforce/lds/no-error-in-production
|
|
1098
|
-
throw new Error('selection should not be empty for ObjectFieldNodeUnderRecord');
|
|
1099
|
-
}
|
|
1100
|
-
const luvioSelectionsLength = luvioSelections.length;
|
|
1101
|
-
for (let i = 0; i < luvioSelectionsLength; i++) {
|
|
1102
|
-
const sel = getLuvioFieldNodeSelection(luvioSelections[i]);
|
|
1103
|
-
const { name } = sel;
|
|
1104
|
-
if (sel.kind !== 'ScalarFieldSelection') {
|
|
1105
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
1106
|
-
throw new Error(`Invalid selection for ${nodeName}. ${nodeName} appears to be a Record, but is missing @resource(type: "Record")`);
|
|
1107
|
-
}
|
|
1108
|
-
}
|
|
1109
|
-
if (RECORD_DEFAULT_FIELD_VALUES.indexOf(name) === -1) {
|
|
1110
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
1111
|
-
throw new Error(`Invalid selection for "${nodeName}.${name}". Only ${RECORD_DEFAULT_FIELD_VALUES.join(', ')} are supported. If "${nodeName}" is a spanning Record, please include @resource(type: "Record") directive.`);
|
|
1112
|
-
}
|
|
1113
|
-
}
|
|
1114
|
-
fields[name] = true;
|
|
1115
|
-
result = `${result}${serializeScalarFieldNode(sel)}`;
|
|
1116
|
-
}
|
|
1117
|
-
result = appendRecordDefaultFieldValues(result, fields);
|
|
1118
|
-
const args = nodeArgs === undefined ? '' : `(${serializeArguments(nodeArgs)})`;
|
|
1119
|
-
return `${serializeFieldNodeName(node)}${args} { ${TYPENAME_FIELD} ${result} }`;
|
|
1120
|
-
}
|
|
1121
|
-
function appendRecordDefaultFieldValues(fieldValues, fieldValuesMap) {
|
|
1122
|
-
let str = fieldValues;
|
|
1123
|
-
for (let i = 0, len = RECORD_DEFAULT_FIELD_VALUES.length; i < len; i++) {
|
|
1124
|
-
const defaultField = RECORD_DEFAULT_FIELD_VALUES[i];
|
|
1125
|
-
if (fieldValuesMap[defaultField] !== true) {
|
|
1126
|
-
str = `${str}${defaultField}, `;
|
|
1127
|
-
}
|
|
1128
|
-
}
|
|
1129
|
-
return str;
|
|
1130
|
-
}
|
|
1131
|
-
function appendSpanningRecordIds(luvioSelections) {
|
|
1132
|
-
if (luvioSelections === undefined) {
|
|
1133
|
-
return undefined;
|
|
1134
|
-
}
|
|
1135
|
-
//add record ref ids
|
|
1136
|
-
let spanningRecordIdFields = [];
|
|
1137
|
-
let selections = luvioSelections;
|
|
1138
|
-
//Find all fields with a record type declaration and add the corresponding
|
|
1139
|
-
//reference ID.
|
|
1140
|
-
// TODO [W-11342283]: This approach uses a naming pattern that is brittle and not
|
|
1141
|
-
// guaranteed to work in the long run. A more correct approach is to thread through
|
|
1142
|
-
// ObjectInfo schemas and use its mapping definitions.
|
|
1143
|
-
for (let i = 0; i < selections.length; i++) {
|
|
1144
|
-
const selection = selections[i];
|
|
1145
|
-
if (selection.kind === 'CustomFieldSelection' && selection.type === 'Record') {
|
|
1146
|
-
const customFieldMatches = selection.name.match(/(.*__)r$/);
|
|
1147
|
-
if (customFieldMatches) {
|
|
1148
|
-
// For `FSL__Related_Service__r {...}`, inject `FSL__Related_Service__c { value } as a peer field`
|
|
1149
|
-
const [, captureGroup] = customFieldMatches;
|
|
1150
|
-
spanningRecordIdFields.push(`${captureGroup}c`);
|
|
1151
|
-
}
|
|
1152
|
-
else {
|
|
1153
|
-
// For `Owner {...}`, inject `OwnerId { value } as a peer field`
|
|
1154
|
-
spanningRecordIdFields.push(`${selection.name}Id`);
|
|
1155
|
-
}
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
1158
|
-
//Add all missing reference IDs to the set of selections
|
|
1159
|
-
for (let i = 0; i < spanningRecordIdFields.length; i++) {
|
|
1160
|
-
const idField = spanningRecordIdFields[i];
|
|
1161
|
-
if (selections.findIndex((e) => e.kind === 'ObjectFieldSelection' && e.name === idField) >
|
|
1162
|
-
-1) {
|
|
1163
|
-
continue;
|
|
1164
|
-
}
|
|
1165
|
-
selections.push({
|
|
1166
|
-
kind: 'ObjectFieldSelection',
|
|
1167
|
-
name: idField,
|
|
1168
|
-
luvioSelections: [{ kind: 'ScalarFieldSelection', name: 'value' }],
|
|
1169
|
-
});
|
|
1170
|
-
}
|
|
1171
|
-
return selections;
|
|
1172
|
-
}
|
|
1173
|
-
function serializeCustomFieldRecord(def, state) {
|
|
1174
|
-
const { luvioSelections } = def;
|
|
1175
|
-
if (state.fragments[defaultRecordFieldsFragmentName] === undefined) {
|
|
1176
|
-
state.fragments[defaultRecordFieldsFragmentName] = defaultRecordFieldsFragment;
|
|
1177
|
-
}
|
|
1178
|
-
const selections = appendSpanningRecordIds(luvioSelections);
|
|
1179
|
-
return `${serializeFieldNodeName(def)} { ${serializeRecordSelections(selections, state)} ...${defaultRecordFieldsFragmentName} }`;
|
|
1180
|
-
}
|
|
1181
|
-
function serializeArguments(argDefinitions) {
|
|
1182
|
-
if (argDefinitions === undefined) {
|
|
1183
|
-
return '';
|
|
1184
|
-
}
|
|
1185
|
-
let str = '';
|
|
1186
|
-
for (let i = 0, len = argDefinitions.length; i < len; i += 1) {
|
|
1187
|
-
let def = serializeArgument(argDefinitions[i]);
|
|
1188
|
-
if (i !== 0) {
|
|
1189
|
-
def = ` ${def}`;
|
|
1190
|
-
}
|
|
1191
|
-
str = `${str}${def}`;
|
|
1192
|
-
}
|
|
1193
|
-
return str;
|
|
1194
|
-
}
|
|
1195
|
-
function serializeArgument(argDefinition) {
|
|
1196
|
-
const { name, value } = argDefinition;
|
|
1197
|
-
return `${name}: ${serializeValueNode(value)}`;
|
|
1022
|
+
const TYPENAME_FIELD = '__typename';
|
|
1023
|
+
const KIND_OBJECT_FIELD_SELECTION = 'ObjectFieldSelection';
|
|
1024
|
+
function serializeFieldNodeName(node) {
|
|
1025
|
+
const { name, alias } = node;
|
|
1026
|
+
return alias === undefined ? `${name}` : `${alias}: ${name}`;
|
|
1027
|
+
}
|
|
1028
|
+
function serializeSelections(selections, state) {
|
|
1029
|
+
if (selections === undefined) {
|
|
1030
|
+
return '';
|
|
1031
|
+
}
|
|
1032
|
+
let str = '';
|
|
1033
|
+
for (let i = 0, len = selections.length; i < len; i += 1) {
|
|
1034
|
+
const def = serializeFieldNode(selections[i], state);
|
|
1035
|
+
str = `${str}${def}`;
|
|
1036
|
+
}
|
|
1037
|
+
return str;
|
|
1038
|
+
}
|
|
1039
|
+
function serializeFieldNode(def, state) {
|
|
1040
|
+
const { kind } = def;
|
|
1041
|
+
switch (kind) {
|
|
1042
|
+
case 'ObjectFieldSelection':
|
|
1043
|
+
return serializeObjectFieldNode(def, state);
|
|
1044
|
+
case 'CustomFieldSelection':
|
|
1045
|
+
return serializeCustomFieldNode(def, state);
|
|
1046
|
+
case 'ScalarFieldSelection':
|
|
1047
|
+
return serializeScalarFieldNode(def);
|
|
1048
|
+
}
|
|
1049
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
1050
|
+
throw new Error(`Unable to serialize graphql query, unsupported field node "${kind}"`);
|
|
1051
|
+
}
|
|
1052
|
+
return '';
|
|
1053
|
+
}
|
|
1054
|
+
function serializeObjectFieldNode(def, state) {
|
|
1055
|
+
const { luvioSelections, arguments: defArgs } = def;
|
|
1056
|
+
const args = defArgs === undefined ? '' : `(${serializeArguments(defArgs)})`;
|
|
1057
|
+
return `${serializeFieldNodeName(def)}${args} { ${TYPENAME_FIELD} ${serializeSelections(luvioSelections, state)} }`;
|
|
1058
|
+
}
|
|
1059
|
+
function serializeCustomFieldNode(def, state) {
|
|
1060
|
+
const { type } = def;
|
|
1061
|
+
switch (type) {
|
|
1062
|
+
case 'Connection':
|
|
1063
|
+
return serialize(def, state);
|
|
1064
|
+
case 'Record':
|
|
1065
|
+
return serializeCustomFieldRecord(def, state);
|
|
1066
|
+
}
|
|
1067
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
1068
|
+
throw new Error(`Unable to serialize graphql query, unsupported CustomField type "${type}"`);
|
|
1069
|
+
}
|
|
1070
|
+
return '';
|
|
1071
|
+
}
|
|
1072
|
+
function serializeScalarFieldNode(def) {
|
|
1073
|
+
return `${serializeFieldNodeName(def)}, `;
|
|
1074
|
+
}
|
|
1075
|
+
function serializeRecordSelections(selections, state) {
|
|
1076
|
+
if (selections === undefined) {
|
|
1077
|
+
return '';
|
|
1078
|
+
}
|
|
1079
|
+
let str = '';
|
|
1080
|
+
for (let i = 0, len = selections.length; i < len; i += 1) {
|
|
1081
|
+
const sel = getLuvioFieldNodeSelection(selections[i]);
|
|
1082
|
+
const def = isLuvioFieldNodeObjectFieldNode(sel)
|
|
1083
|
+
? serializeObjectFieldNodeUnderRecord(sel)
|
|
1084
|
+
: serializeFieldNode(sel, state);
|
|
1085
|
+
str = `${str}${def}`;
|
|
1086
|
+
}
|
|
1087
|
+
return str;
|
|
1088
|
+
}
|
|
1089
|
+
function isLuvioFieldNodeObjectFieldNode(node) {
|
|
1090
|
+
return node.kind === KIND_OBJECT_FIELD_SELECTION;
|
|
1091
|
+
}
|
|
1092
|
+
function serializeObjectFieldNodeUnderRecord(node) {
|
|
1093
|
+
const { luvioSelections, arguments: nodeArgs, name: nodeName } = node;
|
|
1094
|
+
const fields = {};
|
|
1095
|
+
let result = ``;
|
|
1096
|
+
if (luvioSelections === undefined) {
|
|
1097
|
+
// eslint-disable-next-line @salesforce/lds/no-error-in-production
|
|
1098
|
+
throw new Error('selection should not be empty for ObjectFieldNodeUnderRecord');
|
|
1099
|
+
}
|
|
1100
|
+
const luvioSelectionsLength = luvioSelections.length;
|
|
1101
|
+
for (let i = 0; i < luvioSelectionsLength; i++) {
|
|
1102
|
+
const sel = getLuvioFieldNodeSelection(luvioSelections[i]);
|
|
1103
|
+
const { name } = sel;
|
|
1104
|
+
if (sel.kind !== 'ScalarFieldSelection') {
|
|
1105
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
1106
|
+
throw new Error(`Invalid selection for ${nodeName}. ${nodeName} appears to be a Record, but is missing @resource(type: "Record")`);
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
if (RECORD_DEFAULT_FIELD_VALUES.indexOf(name) === -1) {
|
|
1110
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
1111
|
+
throw new Error(`Invalid selection for "${nodeName}.${name}". Only ${RECORD_DEFAULT_FIELD_VALUES.join(', ')} are supported. If "${nodeName}" is a spanning Record, please include @resource(type: "Record") directive.`);
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
fields[name] = true;
|
|
1115
|
+
result = `${result}${serializeScalarFieldNode(sel)}`;
|
|
1116
|
+
}
|
|
1117
|
+
result = appendRecordDefaultFieldValues(result, fields);
|
|
1118
|
+
const args = nodeArgs === undefined ? '' : `(${serializeArguments(nodeArgs)})`;
|
|
1119
|
+
return `${serializeFieldNodeName(node)}${args} { ${TYPENAME_FIELD} ${result} }`;
|
|
1120
|
+
}
|
|
1121
|
+
function appendRecordDefaultFieldValues(fieldValues, fieldValuesMap) {
|
|
1122
|
+
let str = fieldValues;
|
|
1123
|
+
for (let i = 0, len = RECORD_DEFAULT_FIELD_VALUES.length; i < len; i++) {
|
|
1124
|
+
const defaultField = RECORD_DEFAULT_FIELD_VALUES[i];
|
|
1125
|
+
if (fieldValuesMap[defaultField] !== true) {
|
|
1126
|
+
str = `${str}${defaultField}, `;
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
return str;
|
|
1130
|
+
}
|
|
1131
|
+
function appendSpanningRecordIds(luvioSelections) {
|
|
1132
|
+
if (luvioSelections === undefined) {
|
|
1133
|
+
return undefined;
|
|
1134
|
+
}
|
|
1135
|
+
//add record ref ids
|
|
1136
|
+
let spanningRecordIdFields = [];
|
|
1137
|
+
let selections = luvioSelections;
|
|
1138
|
+
//Find all fields with a record type declaration and add the corresponding
|
|
1139
|
+
//reference ID.
|
|
1140
|
+
// TODO [W-11342283]: This approach uses a naming pattern that is brittle and not
|
|
1141
|
+
// guaranteed to work in the long run. A more correct approach is to thread through
|
|
1142
|
+
// ObjectInfo schemas and use its mapping definitions.
|
|
1143
|
+
for (let i = 0; i < selections.length; i++) {
|
|
1144
|
+
const selection = selections[i];
|
|
1145
|
+
if (selection.kind === 'CustomFieldSelection' && selection.type === 'Record') {
|
|
1146
|
+
const customFieldMatches = selection.name.match(/(.*__)r$/);
|
|
1147
|
+
if (customFieldMatches) {
|
|
1148
|
+
// For `FSL__Related_Service__r {...}`, inject `FSL__Related_Service__c { value } as a peer field`
|
|
1149
|
+
const [, captureGroup] = customFieldMatches;
|
|
1150
|
+
spanningRecordIdFields.push(`${captureGroup}c`);
|
|
1151
|
+
}
|
|
1152
|
+
else {
|
|
1153
|
+
// For `Owner {...}`, inject `OwnerId { value } as a peer field`
|
|
1154
|
+
spanningRecordIdFields.push(`${selection.name}Id`);
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
//Add all missing reference IDs to the set of selections
|
|
1159
|
+
for (let i = 0; i < spanningRecordIdFields.length; i++) {
|
|
1160
|
+
const idField = spanningRecordIdFields[i];
|
|
1161
|
+
if (selections.findIndex((e) => e.kind === 'ObjectFieldSelection' && e.name === idField) >
|
|
1162
|
+
-1) {
|
|
1163
|
+
continue;
|
|
1164
|
+
}
|
|
1165
|
+
selections.push({
|
|
1166
|
+
kind: 'ObjectFieldSelection',
|
|
1167
|
+
name: idField,
|
|
1168
|
+
luvioSelections: [{ kind: 'ScalarFieldSelection', name: 'value' }],
|
|
1169
|
+
});
|
|
1170
|
+
}
|
|
1171
|
+
return selections;
|
|
1172
|
+
}
|
|
1173
|
+
function serializeCustomFieldRecord(def, state) {
|
|
1174
|
+
const { luvioSelections } = def;
|
|
1175
|
+
if (state.fragments[defaultRecordFieldsFragmentName] === undefined) {
|
|
1176
|
+
state.fragments[defaultRecordFieldsFragmentName] = defaultRecordFieldsFragment;
|
|
1177
|
+
}
|
|
1178
|
+
const selections = appendSpanningRecordIds(luvioSelections);
|
|
1179
|
+
return `${serializeFieldNodeName(def)} { ${serializeRecordSelections(selections, state)} ...${defaultRecordFieldsFragmentName} }`;
|
|
1180
|
+
}
|
|
1181
|
+
function serializeArguments(argDefinitions) {
|
|
1182
|
+
if (argDefinitions === undefined) {
|
|
1183
|
+
return '';
|
|
1184
|
+
}
|
|
1185
|
+
let str = '';
|
|
1186
|
+
for (let i = 0, len = argDefinitions.length; i < len; i += 1) {
|
|
1187
|
+
let def = serializeArgument(argDefinitions[i]);
|
|
1188
|
+
if (i !== 0) {
|
|
1189
|
+
def = ` ${def}`;
|
|
1190
|
+
}
|
|
1191
|
+
str = `${str}${def}`;
|
|
1192
|
+
}
|
|
1193
|
+
return str;
|
|
1194
|
+
}
|
|
1195
|
+
function serializeArgument(argDefinition) {
|
|
1196
|
+
const { name, value } = argDefinition;
|
|
1197
|
+
return `${name}: ${serializeValueNode(value)}`;
|
|
1198
1198
|
}
|
|
1199
1199
|
|
|
1200
|
-
function serializeValueNode(valueDefinition) {
|
|
1201
|
-
const { kind } = valueDefinition;
|
|
1202
|
-
switch (kind) {
|
|
1203
|
-
case 'ObjectValue':
|
|
1204
|
-
return serializeObjectValueNode(valueDefinition);
|
|
1205
|
-
case 'StringValue':
|
|
1206
|
-
return serializeStringValueNode(valueDefinition);
|
|
1207
|
-
case 'NullValue':
|
|
1208
|
-
return 'null';
|
|
1209
|
-
case 'FloatValue':
|
|
1210
|
-
case 'IntValue':
|
|
1211
|
-
case 'BooleanValue':
|
|
1212
|
-
case 'EnumValue':
|
|
1213
|
-
return valueDefinition.value;
|
|
1214
|
-
case 'Variable':
|
|
1215
|
-
return serializeVariableNode(valueDefinition);
|
|
1216
|
-
case 'ListValue':
|
|
1217
|
-
return serializeListValueNode(valueDefinition);
|
|
1218
|
-
}
|
|
1219
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
1220
|
-
throw new Error(`Unable to serialize graphql query, unsupported value node "${kind}"`);
|
|
1221
|
-
}
|
|
1222
|
-
}
|
|
1223
|
-
function serializeVariableNode(variableNode) {
|
|
1224
|
-
return `$${variableNode.name}`;
|
|
1225
|
-
}
|
|
1226
|
-
function serializeListValueNode(listNode) {
|
|
1227
|
-
const { values } = listNode;
|
|
1228
|
-
if (values.length === 0) {
|
|
1229
|
-
return '';
|
|
1230
|
-
}
|
|
1231
|
-
let str = '';
|
|
1232
|
-
for (let i = 0, len = values.length; i < len; i += 1) {
|
|
1233
|
-
str = `${str}${serializeValueNode(values[i])}, `;
|
|
1234
|
-
}
|
|
1235
|
-
return `[${str.substring(0, str.length - 2)}]`;
|
|
1236
|
-
}
|
|
1237
|
-
function serializeStringValueNode(literalValueNode) {
|
|
1238
|
-
return `"${literalValueNode.value}"`;
|
|
1239
|
-
}
|
|
1240
|
-
function serializeObjectValueNode(objectValueDefinition) {
|
|
1241
|
-
const { fields } = objectValueDefinition;
|
|
1242
|
-
let str = [];
|
|
1243
|
-
const fieldKeys = keys(fields);
|
|
1244
|
-
for (let i = 0, len = fieldKeys.length; i < len; i += 1) {
|
|
1245
|
-
const fieldKey = fieldKeys[i];
|
|
1246
|
-
str.push(`${fieldKey}: ${serializeValueNode(fields[fieldKey])}`);
|
|
1247
|
-
}
|
|
1248
|
-
return `{ ${str.join(', ')} }`;
|
|
1249
|
-
}
|
|
1250
|
-
function serializeVariableDefinitions(definitons) {
|
|
1251
|
-
if (definitons === undefined || definitons.length === 0) {
|
|
1252
|
-
return '';
|
|
1253
|
-
}
|
|
1254
|
-
let str = '';
|
|
1255
|
-
for (let i = 0, len = definitons.length; i < len; i += 1) {
|
|
1256
|
-
const def = serializeVariableDefinitionNode(definitons[i]);
|
|
1257
|
-
str = `${str}${def}, `;
|
|
1258
|
-
}
|
|
1259
|
-
return ` (${str.substring(0, str.length - 2)})`;
|
|
1260
|
-
}
|
|
1261
|
-
function serializeVariableDefinitionNode(def) {
|
|
1262
|
-
const { variable, type, defaultValue } = def;
|
|
1263
|
-
return defaultValue === undefined
|
|
1264
|
-
? `$${variable.name}: ${serializeTypeNode(type)}`
|
|
1265
|
-
: `$${variable.name}: ${serializeTypeNode(type)} = ${serializeValueNode(defaultValue)}`;
|
|
1266
|
-
}
|
|
1267
|
-
function serializeTypeNode(type) {
|
|
1268
|
-
const { kind } = type;
|
|
1269
|
-
switch (kind) {
|
|
1270
|
-
case 'NamedType':
|
|
1271
|
-
return serializeNamedTypeNode(type);
|
|
1272
|
-
case 'ListType':
|
|
1273
|
-
return serializeListTypeNode(type);
|
|
1274
|
-
}
|
|
1275
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
1276
|
-
throw new Error(`Unable to serialize graphql query, unsupported variable definition type node "${type.kind}"`);
|
|
1277
|
-
}
|
|
1278
|
-
return '';
|
|
1279
|
-
}
|
|
1280
|
-
function serializeNamedTypeNode(type) {
|
|
1281
|
-
return type.name;
|
|
1282
|
-
}
|
|
1283
|
-
function serializeListTypeNode(type) {
|
|
1284
|
-
return `[${serializeTypeNode(type.type)}]`;
|
|
1285
|
-
}
|
|
1286
|
-
function serializeOperationNode(def, state) {
|
|
1287
|
-
const { kind } = def;
|
|
1288
|
-
switch (kind) {
|
|
1289
|
-
case 'OperationDefinition':
|
|
1290
|
-
return serializeOperationDefinition(def, state);
|
|
1291
|
-
}
|
|
1292
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
1293
|
-
throw new Error(`Unable to serialize graphql query, unsupported OperationDefinition type "${kind}"`);
|
|
1294
|
-
}
|
|
1295
|
-
}
|
|
1296
|
-
function serializeOperationDefinition(def, state) {
|
|
1297
|
-
const { operation, luvioSelections, name, variableDefinitions } = def;
|
|
1298
|
-
const nameStr = name === undefined ? ' ' : ` ${name} `;
|
|
1299
|
-
return `${operation}${nameStr}${serializeVariableDefinitions(variableDefinitions)}{ ${TYPENAME_FIELD} ${serializeSelections(luvioSelections, state)} }`;
|
|
1300
|
-
}
|
|
1301
|
-
function applyFragments(str, fragments) {
|
|
1302
|
-
let appliedString = str;
|
|
1303
|
-
const fragmentNames = Object.keys(fragments);
|
|
1304
|
-
for (let i = 0, len = fragmentNames.length; i < len; i += 1) {
|
|
1305
|
-
const name = fragmentNames[i];
|
|
1306
|
-
appliedString = `${appliedString} ${fragments[name]}`;
|
|
1307
|
-
}
|
|
1308
|
-
return appliedString;
|
|
1309
|
-
}
|
|
1310
|
-
function astToString(ast) {
|
|
1311
|
-
const { definitions } = ast;
|
|
1312
|
-
const state = {
|
|
1313
|
-
fragments: {},
|
|
1314
|
-
};
|
|
1315
|
-
let str = '';
|
|
1316
|
-
for (let i = 0, len = definitions.length; i < len; i += 1) {
|
|
1317
|
-
const def = serializeOperationNode(definitions[i], state);
|
|
1318
|
-
str = `${str}${def}`;
|
|
1319
|
-
}
|
|
1320
|
-
return applyFragments(str, state.fragments);
|
|
1200
|
+
function serializeValueNode(valueDefinition) {
|
|
1201
|
+
const { kind } = valueDefinition;
|
|
1202
|
+
switch (kind) {
|
|
1203
|
+
case 'ObjectValue':
|
|
1204
|
+
return serializeObjectValueNode(valueDefinition);
|
|
1205
|
+
case 'StringValue':
|
|
1206
|
+
return serializeStringValueNode(valueDefinition);
|
|
1207
|
+
case 'NullValue':
|
|
1208
|
+
return 'null';
|
|
1209
|
+
case 'FloatValue':
|
|
1210
|
+
case 'IntValue':
|
|
1211
|
+
case 'BooleanValue':
|
|
1212
|
+
case 'EnumValue':
|
|
1213
|
+
return valueDefinition.value;
|
|
1214
|
+
case 'Variable':
|
|
1215
|
+
return serializeVariableNode(valueDefinition);
|
|
1216
|
+
case 'ListValue':
|
|
1217
|
+
return serializeListValueNode(valueDefinition);
|
|
1218
|
+
}
|
|
1219
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
1220
|
+
throw new Error(`Unable to serialize graphql query, unsupported value node "${kind}"`);
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
function serializeVariableNode(variableNode) {
|
|
1224
|
+
return `$${variableNode.name}`;
|
|
1225
|
+
}
|
|
1226
|
+
function serializeListValueNode(listNode) {
|
|
1227
|
+
const { values } = listNode;
|
|
1228
|
+
if (values.length === 0) {
|
|
1229
|
+
return '';
|
|
1230
|
+
}
|
|
1231
|
+
let str = '';
|
|
1232
|
+
for (let i = 0, len = values.length; i < len; i += 1) {
|
|
1233
|
+
str = `${str}${serializeValueNode(values[i])}, `;
|
|
1234
|
+
}
|
|
1235
|
+
return `[${str.substring(0, str.length - 2)}]`;
|
|
1236
|
+
}
|
|
1237
|
+
function serializeStringValueNode(literalValueNode) {
|
|
1238
|
+
return `"${literalValueNode.value}"`;
|
|
1239
|
+
}
|
|
1240
|
+
function serializeObjectValueNode(objectValueDefinition) {
|
|
1241
|
+
const { fields } = objectValueDefinition;
|
|
1242
|
+
let str = [];
|
|
1243
|
+
const fieldKeys = keys(fields);
|
|
1244
|
+
for (let i = 0, len = fieldKeys.length; i < len; i += 1) {
|
|
1245
|
+
const fieldKey = fieldKeys[i];
|
|
1246
|
+
str.push(`${fieldKey}: ${serializeValueNode(fields[fieldKey])}`);
|
|
1247
|
+
}
|
|
1248
|
+
return `{ ${str.join(', ')} }`;
|
|
1249
|
+
}
|
|
1250
|
+
function serializeVariableDefinitions(definitons) {
|
|
1251
|
+
if (definitons === undefined || definitons.length === 0) {
|
|
1252
|
+
return '';
|
|
1253
|
+
}
|
|
1254
|
+
let str = '';
|
|
1255
|
+
for (let i = 0, len = definitons.length; i < len; i += 1) {
|
|
1256
|
+
const def = serializeVariableDefinitionNode(definitons[i]);
|
|
1257
|
+
str = `${str}${def}, `;
|
|
1258
|
+
}
|
|
1259
|
+
return ` (${str.substring(0, str.length - 2)})`;
|
|
1260
|
+
}
|
|
1261
|
+
function serializeVariableDefinitionNode(def) {
|
|
1262
|
+
const { variable, type, defaultValue } = def;
|
|
1263
|
+
return defaultValue === undefined
|
|
1264
|
+
? `$${variable.name}: ${serializeTypeNode(type)}`
|
|
1265
|
+
: `$${variable.name}: ${serializeTypeNode(type)} = ${serializeValueNode(defaultValue)}`;
|
|
1266
|
+
}
|
|
1267
|
+
function serializeTypeNode(type) {
|
|
1268
|
+
const { kind } = type;
|
|
1269
|
+
switch (kind) {
|
|
1270
|
+
case 'NamedType':
|
|
1271
|
+
return serializeNamedTypeNode(type);
|
|
1272
|
+
case 'ListType':
|
|
1273
|
+
return serializeListTypeNode(type);
|
|
1274
|
+
}
|
|
1275
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
1276
|
+
throw new Error(`Unable to serialize graphql query, unsupported variable definition type node "${type.kind}"`);
|
|
1277
|
+
}
|
|
1278
|
+
return '';
|
|
1279
|
+
}
|
|
1280
|
+
function serializeNamedTypeNode(type) {
|
|
1281
|
+
return type.name;
|
|
1282
|
+
}
|
|
1283
|
+
function serializeListTypeNode(type) {
|
|
1284
|
+
return `[${serializeTypeNode(type.type)}]`;
|
|
1285
|
+
}
|
|
1286
|
+
function serializeOperationNode(def, state) {
|
|
1287
|
+
const { kind } = def;
|
|
1288
|
+
switch (kind) {
|
|
1289
|
+
case 'OperationDefinition':
|
|
1290
|
+
return serializeOperationDefinition(def, state);
|
|
1291
|
+
}
|
|
1292
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
1293
|
+
throw new Error(`Unable to serialize graphql query, unsupported OperationDefinition type "${kind}"`);
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
function serializeOperationDefinition(def, state) {
|
|
1297
|
+
const { operation, luvioSelections, name, variableDefinitions } = def;
|
|
1298
|
+
const nameStr = name === undefined ? ' ' : ` ${name} `;
|
|
1299
|
+
return `${operation}${nameStr}${serializeVariableDefinitions(variableDefinitions)}{ ${TYPENAME_FIELD} ${serializeSelections(luvioSelections, state)} }`;
|
|
1300
|
+
}
|
|
1301
|
+
function applyFragments(str, fragments) {
|
|
1302
|
+
let appliedString = str;
|
|
1303
|
+
const fragmentNames = Object.keys(fragments);
|
|
1304
|
+
for (let i = 0, len = fragmentNames.length; i < len; i += 1) {
|
|
1305
|
+
const name = fragmentNames[i];
|
|
1306
|
+
appliedString = `${appliedString} ${fragments[name]}`;
|
|
1307
|
+
}
|
|
1308
|
+
return appliedString;
|
|
1309
|
+
}
|
|
1310
|
+
function astToString(ast) {
|
|
1311
|
+
const { definitions } = ast;
|
|
1312
|
+
const state = {
|
|
1313
|
+
fragments: {},
|
|
1314
|
+
};
|
|
1315
|
+
let str = '';
|
|
1316
|
+
for (let i = 0, len = definitions.length; i < len; i += 1) {
|
|
1317
|
+
const def = serializeOperationNode(definitions[i], state);
|
|
1318
|
+
str = `${str}${def}`;
|
|
1319
|
+
}
|
|
1320
|
+
return applyFragments(str, state.fragments);
|
|
1321
1321
|
}
|
|
1322
1322
|
|
|
1323
|
-
function isGraphQLVariables(unknown) {
|
|
1324
|
-
return untrustedIsObject(unknown);
|
|
1325
|
-
}
|
|
1326
|
-
function validateVariableDefinitions(definitons, variables) {
|
|
1327
|
-
const errors = [];
|
|
1328
|
-
for (let i = 0, len = definitons.length; i < len; i += 1) {
|
|
1329
|
-
const { variable, type, defaultValue } = definitons[i];
|
|
1330
|
-
const value = getVariableValue(variable.name, variables, defaultValue);
|
|
1331
|
-
if (value === undefined) {
|
|
1332
|
-
errors.push(`Variable $${variable.name} has an undefined value provided for it.`);
|
|
1333
|
-
}
|
|
1334
|
-
if (type.kind === 'NonNullType' && value === null) {
|
|
1335
|
-
errors.push(`Expected a non-null value to be provided as value for $${variable.name}`);
|
|
1336
|
-
}
|
|
1337
|
-
if (type.kind === 'ListType' && value !== null && !Array.isArray(value)) {
|
|
1338
|
-
errors.push(`Expected a list to be provided as value for $${variable.name}`);
|
|
1339
|
-
}
|
|
1340
|
-
}
|
|
1341
|
-
return errors;
|
|
1342
|
-
}
|
|
1343
|
-
function getVariableValue(name, variables, defaultValue) {
|
|
1344
|
-
if (name in variables) {
|
|
1345
|
-
return variables[name];
|
|
1346
|
-
}
|
|
1347
|
-
if (defaultValue === undefined) {
|
|
1348
|
-
return null;
|
|
1349
|
-
}
|
|
1350
|
-
return defaultValue;
|
|
1323
|
+
function isGraphQLVariables(unknown) {
|
|
1324
|
+
return untrustedIsObject(unknown);
|
|
1325
|
+
}
|
|
1326
|
+
function validateVariableDefinitions(definitons, variables) {
|
|
1327
|
+
const errors = [];
|
|
1328
|
+
for (let i = 0, len = definitons.length; i < len; i += 1) {
|
|
1329
|
+
const { variable, type, defaultValue } = definitons[i];
|
|
1330
|
+
const value = getVariableValue(variable.name, variables, defaultValue);
|
|
1331
|
+
if (value === undefined) {
|
|
1332
|
+
errors.push(`Variable $${variable.name} has an undefined value provided for it.`);
|
|
1333
|
+
}
|
|
1334
|
+
if (type.kind === 'NonNullType' && value === null) {
|
|
1335
|
+
errors.push(`Expected a non-null value to be provided as value for $${variable.name}`);
|
|
1336
|
+
}
|
|
1337
|
+
if (type.kind === 'ListType' && value !== null && !Array.isArray(value)) {
|
|
1338
|
+
errors.push(`Expected a list to be provided as value for $${variable.name}`);
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
return errors;
|
|
1342
|
+
}
|
|
1343
|
+
function getVariableValue(name, variables, defaultValue) {
|
|
1344
|
+
if (name in variables) {
|
|
1345
|
+
return variables[name];
|
|
1346
|
+
}
|
|
1347
|
+
if (defaultValue === undefined) {
|
|
1348
|
+
return null;
|
|
1349
|
+
}
|
|
1350
|
+
return defaultValue;
|
|
1351
1351
|
}
|
|
1352
1352
|
|
|
1353
|
-
function validate$1(ast, variables) {
|
|
1354
|
-
const { variableDefinitions } = ast;
|
|
1355
|
-
const errors = [];
|
|
1356
|
-
if (variableDefinitions !== undefined) {
|
|
1357
|
-
errors.push(...validateVariableDefinitions(variableDefinitions, variables));
|
|
1358
|
-
}
|
|
1359
|
-
return errors;
|
|
1353
|
+
function validate$1(ast, variables) {
|
|
1354
|
+
const { variableDefinitions } = ast;
|
|
1355
|
+
const errors = [];
|
|
1356
|
+
if (variableDefinitions !== undefined) {
|
|
1357
|
+
errors.push(...validateVariableDefinitions(variableDefinitions, variables));
|
|
1358
|
+
}
|
|
1359
|
+
return errors;
|
|
1360
1360
|
}
|
|
1361
1361
|
|
|
1362
|
-
function isLuvioDocumentNode(unknown) {
|
|
1363
|
-
if (untrustedIsObject(unknown) === true &&
|
|
1364
|
-
hasOwnProperty.call(unknown, 'kind') === true &&
|
|
1365
|
-
hasOwnProperty.call(unknown, 'definitions') === true) {
|
|
1366
|
-
return (typeof unknown.kind === 'string' &&
|
|
1367
|
-
isArray(unknown.definitions));
|
|
1368
|
-
}
|
|
1369
|
-
return false;
|
|
1370
|
-
}
|
|
1371
|
-
const createRead = (luvio, ast, variables) => {
|
|
1372
|
-
const definitions = ast.definitions === undefined ? [] : ast.definitions;
|
|
1373
|
-
return (source, builder) => {
|
|
1374
|
-
builder.enterPath('data');
|
|
1375
|
-
let sink = {};
|
|
1376
|
-
for (let i = 0, len = definitions.length; i < len; i += 1) {
|
|
1377
|
-
const def = definitions[i];
|
|
1378
|
-
if (def.kind !== 'OperationDefinition') {
|
|
1379
|
-
// eslint-disable-next-line @salesforce/lds/no-error-in-production
|
|
1380
|
-
throw new Error(`Unsupported document definition "${def.kind}"`);
|
|
1381
|
-
}
|
|
1382
|
-
const data = createRead$1(luvio, def, variables)(source, builder);
|
|
1383
|
-
sink = {
|
|
1384
|
-
...sink,
|
|
1385
|
-
...data,
|
|
1386
|
-
};
|
|
1387
|
-
}
|
|
1388
|
-
const gqlData = {};
|
|
1389
|
-
builder.assignNonScalar(gqlData, 'data', sink);
|
|
1390
|
-
builder.exitPath();
|
|
1391
|
-
builder.enterPath('errors');
|
|
1392
|
-
builder.assignNonScalar(gqlData, 'errors', []);
|
|
1393
|
-
builder.exitPath();
|
|
1394
|
-
return gqlData;
|
|
1395
|
-
};
|
|
1396
|
-
};
|
|
1397
|
-
function createIngest(ast, variables) {
|
|
1398
|
-
const definitions = ast.definitions === undefined ? [] : ast.definitions;
|
|
1399
|
-
return (data, path, luvio, store, timestamp) => {
|
|
1400
|
-
const key = path.fullPath;
|
|
1401
|
-
for (let i = 0, len = definitions.length; i < len; i += 1) {
|
|
1402
|
-
const def = definitions[i];
|
|
1403
|
-
if (def.kind !== 'OperationDefinition') {
|
|
1404
|
-
// eslint-disable-next-line @salesforce/lds/no-error-in-production
|
|
1405
|
-
throw new Error(`Unsupported document definition "${def.kind}"`);
|
|
1406
|
-
}
|
|
1407
|
-
createIngest$2(def, variables)(data, {
|
|
1408
|
-
parent: null,
|
|
1409
|
-
fullPath: key,
|
|
1410
|
-
propertyName: null,
|
|
1411
|
-
}, luvio, store, timestamp);
|
|
1412
|
-
}
|
|
1413
|
-
return {
|
|
1414
|
-
__ref: key,
|
|
1415
|
-
};
|
|
1416
|
-
};
|
|
1417
|
-
}
|
|
1418
|
-
function validate(ast, variables) {
|
|
1419
|
-
const errors = [];
|
|
1420
|
-
const { definitions } = ast;
|
|
1421
|
-
for (let i = 0, len = definitions.length; i < len; i += 1) {
|
|
1422
|
-
const def = definitions[i];
|
|
1423
|
-
if (def.kind !== 'OperationDefinition') {
|
|
1424
|
-
errors.push(`Unsupported document definition "${def.kind}"`);
|
|
1425
|
-
}
|
|
1426
|
-
else {
|
|
1427
|
-
errors.push(...validate$1(def, variables));
|
|
1428
|
-
}
|
|
1429
|
-
}
|
|
1430
|
-
return errors;
|
|
1362
|
+
function isLuvioDocumentNode(unknown) {
|
|
1363
|
+
if (untrustedIsObject(unknown) === true &&
|
|
1364
|
+
hasOwnProperty.call(unknown, 'kind') === true &&
|
|
1365
|
+
hasOwnProperty.call(unknown, 'definitions') === true) {
|
|
1366
|
+
return (typeof unknown.kind === 'string' &&
|
|
1367
|
+
isArray(unknown.definitions));
|
|
1368
|
+
}
|
|
1369
|
+
return false;
|
|
1370
|
+
}
|
|
1371
|
+
const createRead = (luvio, ast, variables) => {
|
|
1372
|
+
const definitions = ast.definitions === undefined ? [] : ast.definitions;
|
|
1373
|
+
return (source, builder) => {
|
|
1374
|
+
builder.enterPath('data');
|
|
1375
|
+
let sink = {};
|
|
1376
|
+
for (let i = 0, len = definitions.length; i < len; i += 1) {
|
|
1377
|
+
const def = definitions[i];
|
|
1378
|
+
if (def.kind !== 'OperationDefinition') {
|
|
1379
|
+
// eslint-disable-next-line @salesforce/lds/no-error-in-production
|
|
1380
|
+
throw new Error(`Unsupported document definition "${def.kind}"`);
|
|
1381
|
+
}
|
|
1382
|
+
const data = createRead$1(luvio, def, variables)(source, builder);
|
|
1383
|
+
sink = {
|
|
1384
|
+
...sink,
|
|
1385
|
+
...data,
|
|
1386
|
+
};
|
|
1387
|
+
}
|
|
1388
|
+
const gqlData = {};
|
|
1389
|
+
builder.assignNonScalar(gqlData, 'data', sink);
|
|
1390
|
+
builder.exitPath();
|
|
1391
|
+
builder.enterPath('errors');
|
|
1392
|
+
builder.assignNonScalar(gqlData, 'errors', []);
|
|
1393
|
+
builder.exitPath();
|
|
1394
|
+
return gqlData;
|
|
1395
|
+
};
|
|
1396
|
+
};
|
|
1397
|
+
function createIngest(ast, variables) {
|
|
1398
|
+
const definitions = ast.definitions === undefined ? [] : ast.definitions;
|
|
1399
|
+
return (data, path, luvio, store, timestamp) => {
|
|
1400
|
+
const key = path.fullPath;
|
|
1401
|
+
for (let i = 0, len = definitions.length; i < len; i += 1) {
|
|
1402
|
+
const def = definitions[i];
|
|
1403
|
+
if (def.kind !== 'OperationDefinition') {
|
|
1404
|
+
// eslint-disable-next-line @salesforce/lds/no-error-in-production
|
|
1405
|
+
throw new Error(`Unsupported document definition "${def.kind}"`);
|
|
1406
|
+
}
|
|
1407
|
+
createIngest$2(def, variables)(data, {
|
|
1408
|
+
parent: null,
|
|
1409
|
+
fullPath: key,
|
|
1410
|
+
propertyName: null,
|
|
1411
|
+
}, luvio, store, timestamp);
|
|
1412
|
+
}
|
|
1413
|
+
return {
|
|
1414
|
+
__ref: key,
|
|
1415
|
+
};
|
|
1416
|
+
};
|
|
1417
|
+
}
|
|
1418
|
+
function validate(ast, variables) {
|
|
1419
|
+
const errors = [];
|
|
1420
|
+
const { definitions } = ast;
|
|
1421
|
+
for (let i = 0, len = definitions.length; i < len; i += 1) {
|
|
1422
|
+
const def = definitions[i];
|
|
1423
|
+
if (def.kind !== 'OperationDefinition') {
|
|
1424
|
+
errors.push(`Unsupported document definition "${def.kind}"`);
|
|
1425
|
+
}
|
|
1426
|
+
else {
|
|
1427
|
+
errors.push(...validate$1(def, variables));
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
return errors;
|
|
1431
1431
|
}
|
|
1432
1432
|
|
|
1433
|
-
let storeEval = undefined;
|
|
1434
|
-
const configuration = {
|
|
1435
|
-
setStoreEval: function (storeEvalArg) {
|
|
1436
|
-
storeEval = storeEvalArg;
|
|
1437
|
-
},
|
|
1433
|
+
let storeEval = undefined;
|
|
1434
|
+
const configuration = {
|
|
1435
|
+
setStoreEval: function (storeEvalArg) {
|
|
1436
|
+
storeEval = storeEvalArg;
|
|
1437
|
+
},
|
|
1438
1438
|
};
|
|
1439
1439
|
|
|
1440
|
-
const assignedToMe = {
|
|
1441
|
-
kind: 'CustomFieldSelection',
|
|
1442
|
-
name: 'ServiceResources',
|
|
1443
|
-
type: 'Connection',
|
|
1444
|
-
luvioSelections: [
|
|
1445
|
-
{
|
|
1446
|
-
kind: 'ObjectFieldSelection',
|
|
1447
|
-
name: 'edges',
|
|
1448
|
-
luvioSelections: [
|
|
1449
|
-
{
|
|
1450
|
-
kind: 'CustomFieldSelection',
|
|
1451
|
-
name: 'node',
|
|
1452
|
-
type: 'Record',
|
|
1453
|
-
luvioSelections: [
|
|
1454
|
-
{
|
|
1455
|
-
kind: 'ObjectFieldSelection',
|
|
1456
|
-
name: 'ServiceResourceId',
|
|
1457
|
-
luvioSelections: [
|
|
1458
|
-
{
|
|
1459
|
-
kind: 'ScalarFieldSelection',
|
|
1460
|
-
name: 'value',
|
|
1461
|
-
},
|
|
1462
|
-
],
|
|
1463
|
-
},
|
|
1464
|
-
{
|
|
1465
|
-
kind: 'ObjectFieldSelection',
|
|
1466
|
-
name: 'ServiceAppointmentId',
|
|
1467
|
-
luvioSelections: [
|
|
1468
|
-
{
|
|
1469
|
-
kind: 'ScalarFieldSelection',
|
|
1470
|
-
name: 'value',
|
|
1471
|
-
},
|
|
1472
|
-
],
|
|
1473
|
-
},
|
|
1474
|
-
{
|
|
1475
|
-
kind: 'CustomFieldSelection',
|
|
1476
|
-
name: 'ServiceResource',
|
|
1477
|
-
type: 'Record',
|
|
1478
|
-
luvioSelections: [
|
|
1479
|
-
{
|
|
1480
|
-
kind: 'ScalarFieldSelection',
|
|
1481
|
-
name: 'Id',
|
|
1482
|
-
},
|
|
1483
|
-
{
|
|
1484
|
-
kind: 'ObjectFieldSelection',
|
|
1485
|
-
name: 'RelatedRecordId',
|
|
1486
|
-
luvioSelections: [
|
|
1487
|
-
{
|
|
1488
|
-
kind: 'ScalarFieldSelection',
|
|
1489
|
-
name: 'value',
|
|
1490
|
-
},
|
|
1491
|
-
],
|
|
1492
|
-
},
|
|
1493
|
-
],
|
|
1494
|
-
},
|
|
1495
|
-
],
|
|
1496
|
-
},
|
|
1497
|
-
],
|
|
1498
|
-
},
|
|
1499
|
-
],
|
|
1500
|
-
};
|
|
1501
|
-
function shouldInjectFields(ast) {
|
|
1502
|
-
let injectScope = false;
|
|
1503
|
-
const recordNodes = findRecordSelections(ast);
|
|
1504
|
-
if (recordNodes !== undefined && recordNodes.length > 0) {
|
|
1505
|
-
for (const recordNode of recordNodes) {
|
|
1506
|
-
if (recordNode.arguments !== undefined) {
|
|
1507
|
-
for (const argument of recordNode.arguments) {
|
|
1508
|
-
if (argument.name === 'scope' &&
|
|
1509
|
-
argument.value.kind === 'EnumValue' &&
|
|
1510
|
-
argument.value.value === 'ASSIGNEDTOME') {
|
|
1511
|
-
injectScope = true;
|
|
1512
|
-
break;
|
|
1513
|
-
}
|
|
1514
|
-
}
|
|
1515
|
-
}
|
|
1516
|
-
}
|
|
1517
|
-
}
|
|
1518
|
-
return injectScope;
|
|
1519
|
-
}
|
|
1520
|
-
function injectFieldsGQL(ast) {
|
|
1521
|
-
return injectScopeFields(ast);
|
|
1522
|
-
}
|
|
1523
|
-
function injectScopeFields(ast) {
|
|
1524
|
-
const modifiedDocumentNode = {
|
|
1525
|
-
kind: 'Document',
|
|
1526
|
-
definitions: [
|
|
1527
|
-
{
|
|
1528
|
-
kind: 'OperationDefinition',
|
|
1529
|
-
operation: 'query',
|
|
1530
|
-
luvioSelections: [
|
|
1531
|
-
{
|
|
1532
|
-
kind: 'ObjectFieldSelection',
|
|
1533
|
-
name: 'uiapi',
|
|
1534
|
-
luvioSelections: [
|
|
1535
|
-
{
|
|
1536
|
-
kind: 'ObjectFieldSelection',
|
|
1537
|
-
name: 'query',
|
|
1538
|
-
luvioSelections: [],
|
|
1539
|
-
},
|
|
1540
|
-
],
|
|
1541
|
-
},
|
|
1542
|
-
],
|
|
1543
|
-
},
|
|
1544
|
-
],
|
|
1545
|
-
};
|
|
1546
|
-
const modifiedSelections = [];
|
|
1547
|
-
const recordNodes = findRecordSelections(ast);
|
|
1548
|
-
if (recordNodes !== undefined && recordNodes.length > 0) {
|
|
1549
|
-
// each record node represent a connection
|
|
1550
|
-
for (const recordNode of recordNodes) {
|
|
1551
|
-
modifiedSelections.push(injectConnectionForScope(recordNode));
|
|
1552
|
-
}
|
|
1553
|
-
}
|
|
1554
|
-
const queryNode = modifiedDocumentNode.definitions
|
|
1555
|
-
.filter(isOperationDefinition)
|
|
1556
|
-
.reduce(flatMap(luvioSelections), [])
|
|
1557
|
-
.filter(isObjectFieldSelection)
|
|
1558
|
-
.filter(named('uiapi'))
|
|
1559
|
-
.reduce(flatMap(luvioSelections), [])
|
|
1560
|
-
.filter(isObjectFieldSelection)
|
|
1561
|
-
.filter(named('query'))[0];
|
|
1562
|
-
queryNode.luvioSelections.push(...modifiedSelections);
|
|
1563
|
-
return ast;
|
|
1564
|
-
}
|
|
1565
|
-
function injectConnectionForScope(connectionNode) {
|
|
1566
|
-
if (connectionNode.name === 'ServiceAppointment') {
|
|
1567
|
-
if (connectionNode.arguments !== undefined) {
|
|
1568
|
-
for (const argument of connectionNode.arguments) {
|
|
1569
|
-
if (argument.name === 'scope' &&
|
|
1570
|
-
argument.value.kind === 'EnumValue' &&
|
|
1571
|
-
argument.value.value === 'ASSIGNEDTOME') {
|
|
1572
|
-
const injectedConnctionNode = {
|
|
1573
|
-
...connectionNode,
|
|
1574
|
-
};
|
|
1575
|
-
if (injectedConnctionNode.luvioSelections !== undefined) {
|
|
1576
|
-
const injectedNodes = injectedConnctionNode.luvioSelections
|
|
1577
|
-
.filter(isObjectFieldSelection)
|
|
1578
|
-
.filter(named('edges'))
|
|
1579
|
-
.reduce(flatMap(luvioSelections), [])
|
|
1580
|
-
.filter(isCustomFieldNode)
|
|
1581
|
-
.filter(named('node'));
|
|
1582
|
-
if (injectedNodes !== undefined && injectedNodes.length > 0) {
|
|
1583
|
-
const injectedNode = injectedNodes[0];
|
|
1584
|
-
if (injectedNode.luvioSelections !== undefined) {
|
|
1585
|
-
injectedNode.luvioSelections = mergeSelectionNodes(injectedNode.luvioSelections, [assignedToMe]);
|
|
1586
|
-
}
|
|
1587
|
-
}
|
|
1588
|
-
}
|
|
1589
|
-
return injectedConnctionNode;
|
|
1590
|
-
}
|
|
1591
|
-
}
|
|
1592
|
-
}
|
|
1593
|
-
}
|
|
1594
|
-
return { ...connectionNode };
|
|
1595
|
-
}
|
|
1596
|
-
function mergeSelectionNodes(group1, group2) {
|
|
1597
|
-
let sameFields1 = [];
|
|
1598
|
-
let sameFields2 = [];
|
|
1599
|
-
let results = [];
|
|
1600
|
-
for (const node2 of group2) {
|
|
1601
|
-
if (isCustomFieldNode(node2)) {
|
|
1602
|
-
const nodes1SameLevel = group1
|
|
1603
|
-
.filter(isCustomFieldNode)
|
|
1604
|
-
.filter((node1) => node1.name === node2.name && node1.type === node2.type);
|
|
1605
|
-
if (nodes1SameLevel.length > 0) {
|
|
1606
|
-
sameFields1.push(...nodes1SameLevel);
|
|
1607
|
-
sameFields2.push(node2);
|
|
1608
|
-
const mergedNode = nodes1SameLevel.reduce((accu, cur) => mergeCustomFieldNodes(accu, cur), node2);
|
|
1609
|
-
results.push(mergedNode);
|
|
1610
|
-
}
|
|
1611
|
-
}
|
|
1612
|
-
else if (isObjectFieldSelection(node2)) {
|
|
1613
|
-
const nodes1SameLevel = group1
|
|
1614
|
-
.filter(isObjectFieldSelection)
|
|
1615
|
-
.filter((node1) => node1.name === node2.name);
|
|
1616
|
-
if (nodes1SameLevel.length > 0) {
|
|
1617
|
-
sameFields1.push(...nodes1SameLevel);
|
|
1618
|
-
sameFields2.push(node2);
|
|
1619
|
-
const mergedNode = nodes1SameLevel.reduce((accu, cur) => mergeObjectFieldNodes(accu, cur), node2);
|
|
1620
|
-
results.push(mergedNode);
|
|
1621
|
-
}
|
|
1622
|
-
}
|
|
1623
|
-
}
|
|
1624
|
-
if (sameFields1.length > 0) {
|
|
1625
|
-
const differentNodes1 = group1.filter((node) => !sameFields1.includes(node));
|
|
1626
|
-
results.push(...differentNodes1);
|
|
1627
|
-
const differentNodes2 = group2.filter((node) => !sameFields2.includes(node));
|
|
1628
|
-
results.push(...differentNodes2);
|
|
1629
|
-
}
|
|
1630
|
-
else {
|
|
1631
|
-
return group1.concat(group2);
|
|
1632
|
-
}
|
|
1633
|
-
return results;
|
|
1634
|
-
}
|
|
1635
|
-
function mergeCustomFieldNodes(node1, node2) {
|
|
1636
|
-
let result = node1;
|
|
1637
|
-
if (node1.name === node2.name && node1.kind === node2.kind && node1.type === node2.type) {
|
|
1638
|
-
result = {
|
|
1639
|
-
kind: node1.kind,
|
|
1640
|
-
name: node1.name,
|
|
1641
|
-
type: node1.type,
|
|
1642
|
-
luvioSelections: [],
|
|
1643
|
-
};
|
|
1644
|
-
let selections = [];
|
|
1645
|
-
let sameCustomFields1 = [];
|
|
1646
|
-
let sameCustomFields2 = [];
|
|
1647
|
-
let sameObjectFields1 = [];
|
|
1648
|
-
let sameObjectFields2 = [];
|
|
1649
|
-
let sameScalarFields1 = [];
|
|
1650
|
-
let sameScalarFields2 = [];
|
|
1651
|
-
if (node1.luvioSelections && node2.luvioSelections) {
|
|
1652
|
-
sameCustomFields1 = node1.luvioSelections
|
|
1653
|
-
.filter(isCustomFieldNode)
|
|
1654
|
-
.filter((childNode1) => {
|
|
1655
|
-
if (node2.luvioSelections) {
|
|
1656
|
-
const sames = node2.luvioSelections
|
|
1657
|
-
.filter(isCustomFieldNode)
|
|
1658
|
-
.filter((childNode2) => childNode2.name === childNode1.name);
|
|
1659
|
-
if (sames.length > 0) {
|
|
1660
|
-
const mergedNode = sames.reduce((accu, cur) => mergeCustomFieldNodes(accu, cur), childNode1);
|
|
1661
|
-
selections.push(mergedNode);
|
|
1662
|
-
result = {
|
|
1663
|
-
...result,
|
|
1664
|
-
luvioSelections: selections,
|
|
1665
|
-
};
|
|
1666
|
-
sameCustomFields2.push(...sames);
|
|
1667
|
-
return true;
|
|
1668
|
-
}
|
|
1669
|
-
}
|
|
1670
|
-
return false;
|
|
1671
|
-
});
|
|
1672
|
-
sameObjectFields1 = node1.luvioSelections
|
|
1673
|
-
.filter(isObjectFieldSelection)
|
|
1674
|
-
.filter((childNode1) => {
|
|
1675
|
-
if (node2.luvioSelections) {
|
|
1676
|
-
const sames = node2.luvioSelections
|
|
1677
|
-
.filter(isObjectFieldSelection)
|
|
1678
|
-
.filter((childNode2) => childNode2.name === childNode1.name);
|
|
1679
|
-
if (sames.length > 0) {
|
|
1680
|
-
const mergedNode = sames.reduce((accu, cur) => mergeObjectFieldNodes(accu, cur), childNode1);
|
|
1681
|
-
selections.push(mergedNode);
|
|
1682
|
-
result = {
|
|
1683
|
-
...result,
|
|
1684
|
-
luvioSelections: selections,
|
|
1685
|
-
};
|
|
1686
|
-
sameObjectFields2.push(...sames);
|
|
1687
|
-
return true;
|
|
1688
|
-
}
|
|
1689
|
-
}
|
|
1690
|
-
return false;
|
|
1691
|
-
});
|
|
1692
|
-
sameScalarFields1 = node1.luvioSelections
|
|
1693
|
-
.filter(isScalarFieldNode)
|
|
1694
|
-
.filter((childNode1) => {
|
|
1695
|
-
if (node2.luvioSelections) {
|
|
1696
|
-
const sames = node2.luvioSelections
|
|
1697
|
-
.filter(isScalarFieldNode)
|
|
1698
|
-
.filter((childNode2) => childNode2.name === childNode1.name);
|
|
1699
|
-
if (sames.length > 0) {
|
|
1700
|
-
const mergedNode = sames.reduce((accu, cur) => mergeScalarFieldNode(accu, cur), childNode1);
|
|
1701
|
-
selections.push(mergedNode);
|
|
1702
|
-
result = {
|
|
1703
|
-
...result,
|
|
1704
|
-
luvioSelections: selections,
|
|
1705
|
-
};
|
|
1706
|
-
sameScalarFields2.push(...sames);
|
|
1707
|
-
return true;
|
|
1708
|
-
}
|
|
1709
|
-
}
|
|
1710
|
-
return false;
|
|
1711
|
-
});
|
|
1712
|
-
if (sameCustomFields1.length > 0 ||
|
|
1713
|
-
sameObjectFields1.length > 0 ||
|
|
1714
|
-
sameScalarFields1.length > 0) {
|
|
1715
|
-
const diffNodes1 = node1.luvioSelections.filter((node) => !sameCustomFields1.includes(node) &&
|
|
1716
|
-
!sameObjectFields1.includes(node) &&
|
|
1717
|
-
!sameScalarFields1.includes(node));
|
|
1718
|
-
selections.push(...diffNodes1);
|
|
1719
|
-
const diffNodes2 = node2.luvioSelections.filter((node) => !sameCustomFields2.includes(node) &&
|
|
1720
|
-
!sameObjectFields2.includes(node) &&
|
|
1721
|
-
!sameScalarFields2.includes(node));
|
|
1722
|
-
selections.push(...diffNodes2);
|
|
1723
|
-
result = {
|
|
1724
|
-
...result,
|
|
1725
|
-
luvioSelections: selections,
|
|
1726
|
-
};
|
|
1727
|
-
}
|
|
1728
|
-
else {
|
|
1729
|
-
selections.push(...node1.luvioSelections);
|
|
1730
|
-
selections.push(...node2.luvioSelections);
|
|
1731
|
-
result = {
|
|
1732
|
-
...result,
|
|
1733
|
-
luvioSelections: selections,
|
|
1734
|
-
};
|
|
1735
|
-
}
|
|
1736
|
-
}
|
|
1737
|
-
else {
|
|
1738
|
-
if (node1.luvioSelections) {
|
|
1739
|
-
return node1;
|
|
1740
|
-
}
|
|
1741
|
-
if (node2.luvioSelections) {
|
|
1742
|
-
return node2;
|
|
1743
|
-
}
|
|
1744
|
-
}
|
|
1745
|
-
return result;
|
|
1746
|
-
}
|
|
1747
|
-
else {
|
|
1748
|
-
// eslint-disable-next-line
|
|
1749
|
-
throw new Error('The fields name needs to be same to be merged');
|
|
1750
|
-
}
|
|
1751
|
-
}
|
|
1752
|
-
function mergeObjectFieldNodes(node1, node2) {
|
|
1753
|
-
let result = node1;
|
|
1754
|
-
if (node1.name === node2.name && node1.kind === node2.kind) {
|
|
1755
|
-
result = {
|
|
1756
|
-
kind: node1.kind,
|
|
1757
|
-
name: node1.name,
|
|
1758
|
-
directives: node1.directives,
|
|
1759
|
-
luvioSelections: [],
|
|
1760
|
-
};
|
|
1761
|
-
let selections = [];
|
|
1762
|
-
let sameCustomFields1 = [];
|
|
1763
|
-
let sameCustomFields2 = [];
|
|
1764
|
-
let sameObjectFields1 = [];
|
|
1765
|
-
let sameObjectFields2 = [];
|
|
1766
|
-
let sameScalarFields1 = [];
|
|
1767
|
-
let sameScalarFields2 = [];
|
|
1768
|
-
if (node1.luvioSelections && node2.luvioSelections) {
|
|
1769
|
-
sameCustomFields1 = node1.luvioSelections
|
|
1770
|
-
.filter(isCustomFieldNode)
|
|
1771
|
-
.filter((childNode1) => {
|
|
1772
|
-
if (node2.luvioSelections) {
|
|
1773
|
-
const sames = node2.luvioSelections
|
|
1774
|
-
.filter(isCustomFieldNode)
|
|
1775
|
-
.filter((childNode2) => childNode2.name === childNode1.name);
|
|
1776
|
-
if (sames.length > 0) {
|
|
1777
|
-
const mergedNode = sames.reduce((accu, cur) => mergeCustomFieldNodes(accu, cur), childNode1);
|
|
1778
|
-
selections.push(mergedNode);
|
|
1779
|
-
result = {
|
|
1780
|
-
...result,
|
|
1781
|
-
luvioSelections: selections,
|
|
1782
|
-
};
|
|
1783
|
-
sameCustomFields2.push(...sames);
|
|
1784
|
-
return true;
|
|
1785
|
-
}
|
|
1786
|
-
}
|
|
1787
|
-
return false;
|
|
1788
|
-
});
|
|
1789
|
-
sameObjectFields1 = node1.luvioSelections
|
|
1790
|
-
.filter(isObjectFieldSelection)
|
|
1791
|
-
.filter((childNode1) => {
|
|
1792
|
-
if (node2.luvioSelections) {
|
|
1793
|
-
const sames = node2.luvioSelections
|
|
1794
|
-
.filter(isObjectFieldSelection)
|
|
1795
|
-
.filter((childNode2) => childNode2.name === childNode1.name);
|
|
1796
|
-
if (sames.length > 0) {
|
|
1797
|
-
const mergedNode = sames.reduce((accu, cur) => mergeObjectFieldNodes(accu, cur), childNode1);
|
|
1798
|
-
selections.push(mergedNode);
|
|
1799
|
-
result = {
|
|
1800
|
-
...result,
|
|
1801
|
-
luvioSelections: selections,
|
|
1802
|
-
};
|
|
1803
|
-
sameObjectFields2.push(...sames);
|
|
1804
|
-
return true;
|
|
1805
|
-
}
|
|
1806
|
-
}
|
|
1807
|
-
return false;
|
|
1808
|
-
});
|
|
1809
|
-
sameScalarFields1 = node1.luvioSelections
|
|
1810
|
-
.filter(isScalarFieldNode)
|
|
1811
|
-
.filter((childNode1) => {
|
|
1812
|
-
if (node2.luvioSelections) {
|
|
1813
|
-
const sames = node2.luvioSelections
|
|
1814
|
-
.filter(isScalarFieldNode)
|
|
1815
|
-
.filter((childNode2) => childNode2.name === childNode1.name);
|
|
1816
|
-
if (sames.length > 0) {
|
|
1817
|
-
const mergedNode = sames.reduce((accu, cur) => mergeScalarFieldNode(accu, cur), childNode1);
|
|
1818
|
-
selections.push(mergedNode);
|
|
1819
|
-
result = {
|
|
1820
|
-
...result,
|
|
1821
|
-
luvioSelections: selections,
|
|
1822
|
-
};
|
|
1823
|
-
sameScalarFields2.push(...sames);
|
|
1824
|
-
return true;
|
|
1825
|
-
}
|
|
1826
|
-
}
|
|
1827
|
-
return false;
|
|
1828
|
-
});
|
|
1829
|
-
if (sameCustomFields1.length > 0 ||
|
|
1830
|
-
sameObjectFields1.length > 0 ||
|
|
1831
|
-
sameScalarFields1.length > 0) {
|
|
1832
|
-
const diffNodes1 = node1.luvioSelections.filter((node) => !sameCustomFields1.includes(node) &&
|
|
1833
|
-
!sameObjectFields1.includes(node) &&
|
|
1834
|
-
!sameScalarFields1.includes(node));
|
|
1835
|
-
selections.push(...diffNodes1);
|
|
1836
|
-
const diffNodes2 = node2.luvioSelections.filter((node) => !sameCustomFields2.includes(node) &&
|
|
1837
|
-
!sameObjectFields2.includes(node) &&
|
|
1838
|
-
!sameScalarFields2.includes(node));
|
|
1839
|
-
selections.push(...diffNodes2);
|
|
1840
|
-
result = {
|
|
1841
|
-
...result,
|
|
1842
|
-
luvioSelections: selections,
|
|
1843
|
-
};
|
|
1844
|
-
}
|
|
1845
|
-
else {
|
|
1846
|
-
selections.push(...node1.luvioSelections);
|
|
1847
|
-
selections.push(...node2.luvioSelections);
|
|
1848
|
-
result = {
|
|
1849
|
-
...result,
|
|
1850
|
-
luvioSelections: selections,
|
|
1851
|
-
};
|
|
1852
|
-
}
|
|
1853
|
-
}
|
|
1854
|
-
else {
|
|
1855
|
-
if (node1.luvioSelections) {
|
|
1856
|
-
return node1;
|
|
1857
|
-
}
|
|
1858
|
-
if (node2.luvioSelections) {
|
|
1859
|
-
return node2;
|
|
1860
|
-
}
|
|
1861
|
-
}
|
|
1862
|
-
return result;
|
|
1863
|
-
}
|
|
1864
|
-
else {
|
|
1865
|
-
// eslint-disable-next-line
|
|
1866
|
-
throw new Error('The fields name needs to be same to be merged');
|
|
1867
|
-
}
|
|
1868
|
-
}
|
|
1869
|
-
function mergeScalarFieldNode(node1, node2) {
|
|
1870
|
-
if (node1.kind === node1.kind && node1.name === node2.name) {
|
|
1871
|
-
return { ...node1 };
|
|
1872
|
-
}
|
|
1873
|
-
// eslint-disable-next-line
|
|
1874
|
-
throw new Error('The fields name needs to be same to be merged');
|
|
1875
|
-
}
|
|
1876
|
-
function findRecordSelections(document) {
|
|
1877
|
-
return document.definitions
|
|
1878
|
-
.filter(isOperationDefinition)
|
|
1879
|
-
.reduce(flatMap(luvioSelections), [])
|
|
1880
|
-
.filter(isObjectFieldSelection)
|
|
1881
|
-
.filter(named('uiapi'))
|
|
1882
|
-
.reduce(flatMap(luvioSelections), [])
|
|
1883
|
-
.filter(isObjectFieldSelection)
|
|
1884
|
-
.filter(named('query'))
|
|
1885
|
-
.reduce(flatMap(luvioSelections), [])
|
|
1886
|
-
.filter(isCustomFieldNode);
|
|
1887
|
-
}
|
|
1888
|
-
function isOperationDefinition(node) {
|
|
1889
|
-
return node.kind === 'OperationDefinition';
|
|
1890
|
-
}
|
|
1891
|
-
function isObjectFieldSelection(node) {
|
|
1892
|
-
return node !== undefined && node.kind === 'ObjectFieldSelection';
|
|
1893
|
-
}
|
|
1894
|
-
function isCustomFieldNode(node) {
|
|
1895
|
-
return node !== undefined && node.kind === 'CustomFieldSelection';
|
|
1896
|
-
}
|
|
1897
|
-
function isScalarFieldNode(node) {
|
|
1898
|
-
return node !== undefined && node.kind === 'ScalarFieldSelection';
|
|
1899
|
-
}
|
|
1900
|
-
function flatMap(transform) {
|
|
1901
|
-
return (acc, current) => {
|
|
1902
|
-
const mapped = transform(current);
|
|
1903
|
-
return acc.concat(mapped);
|
|
1904
|
-
};
|
|
1905
|
-
}
|
|
1906
|
-
function luvioSelections(node) {
|
|
1907
|
-
return node.luvioSelections === undefined ? [] : node.luvioSelections;
|
|
1908
|
-
}
|
|
1909
|
-
function named(name) {
|
|
1910
|
-
return (node) => node.name === name;
|
|
1440
|
+
const assignedToMe = {
|
|
1441
|
+
kind: 'CustomFieldSelection',
|
|
1442
|
+
name: 'ServiceResources',
|
|
1443
|
+
type: 'Connection',
|
|
1444
|
+
luvioSelections: [
|
|
1445
|
+
{
|
|
1446
|
+
kind: 'ObjectFieldSelection',
|
|
1447
|
+
name: 'edges',
|
|
1448
|
+
luvioSelections: [
|
|
1449
|
+
{
|
|
1450
|
+
kind: 'CustomFieldSelection',
|
|
1451
|
+
name: 'node',
|
|
1452
|
+
type: 'Record',
|
|
1453
|
+
luvioSelections: [
|
|
1454
|
+
{
|
|
1455
|
+
kind: 'ObjectFieldSelection',
|
|
1456
|
+
name: 'ServiceResourceId',
|
|
1457
|
+
luvioSelections: [
|
|
1458
|
+
{
|
|
1459
|
+
kind: 'ScalarFieldSelection',
|
|
1460
|
+
name: 'value',
|
|
1461
|
+
},
|
|
1462
|
+
],
|
|
1463
|
+
},
|
|
1464
|
+
{
|
|
1465
|
+
kind: 'ObjectFieldSelection',
|
|
1466
|
+
name: 'ServiceAppointmentId',
|
|
1467
|
+
luvioSelections: [
|
|
1468
|
+
{
|
|
1469
|
+
kind: 'ScalarFieldSelection',
|
|
1470
|
+
name: 'value',
|
|
1471
|
+
},
|
|
1472
|
+
],
|
|
1473
|
+
},
|
|
1474
|
+
{
|
|
1475
|
+
kind: 'CustomFieldSelection',
|
|
1476
|
+
name: 'ServiceResource',
|
|
1477
|
+
type: 'Record',
|
|
1478
|
+
luvioSelections: [
|
|
1479
|
+
{
|
|
1480
|
+
kind: 'ScalarFieldSelection',
|
|
1481
|
+
name: 'Id',
|
|
1482
|
+
},
|
|
1483
|
+
{
|
|
1484
|
+
kind: 'ObjectFieldSelection',
|
|
1485
|
+
name: 'RelatedRecordId',
|
|
1486
|
+
luvioSelections: [
|
|
1487
|
+
{
|
|
1488
|
+
kind: 'ScalarFieldSelection',
|
|
1489
|
+
name: 'value',
|
|
1490
|
+
},
|
|
1491
|
+
],
|
|
1492
|
+
},
|
|
1493
|
+
],
|
|
1494
|
+
},
|
|
1495
|
+
],
|
|
1496
|
+
},
|
|
1497
|
+
],
|
|
1498
|
+
},
|
|
1499
|
+
],
|
|
1500
|
+
};
|
|
1501
|
+
function shouldInjectFields(ast) {
|
|
1502
|
+
let injectScope = false;
|
|
1503
|
+
const recordNodes = findRecordSelections(ast);
|
|
1504
|
+
if (recordNodes !== undefined && recordNodes.length > 0) {
|
|
1505
|
+
for (const recordNode of recordNodes) {
|
|
1506
|
+
if (recordNode.arguments !== undefined) {
|
|
1507
|
+
for (const argument of recordNode.arguments) {
|
|
1508
|
+
if (argument.name === 'scope' &&
|
|
1509
|
+
argument.value.kind === 'EnumValue' &&
|
|
1510
|
+
argument.value.value === 'ASSIGNEDTOME') {
|
|
1511
|
+
injectScope = true;
|
|
1512
|
+
break;
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
return injectScope;
|
|
1519
|
+
}
|
|
1520
|
+
function injectFieldsGQL(ast) {
|
|
1521
|
+
return injectScopeFields(ast);
|
|
1522
|
+
}
|
|
1523
|
+
function injectScopeFields(ast) {
|
|
1524
|
+
const modifiedDocumentNode = {
|
|
1525
|
+
kind: 'Document',
|
|
1526
|
+
definitions: [
|
|
1527
|
+
{
|
|
1528
|
+
kind: 'OperationDefinition',
|
|
1529
|
+
operation: 'query',
|
|
1530
|
+
luvioSelections: [
|
|
1531
|
+
{
|
|
1532
|
+
kind: 'ObjectFieldSelection',
|
|
1533
|
+
name: 'uiapi',
|
|
1534
|
+
luvioSelections: [
|
|
1535
|
+
{
|
|
1536
|
+
kind: 'ObjectFieldSelection',
|
|
1537
|
+
name: 'query',
|
|
1538
|
+
luvioSelections: [],
|
|
1539
|
+
},
|
|
1540
|
+
],
|
|
1541
|
+
},
|
|
1542
|
+
],
|
|
1543
|
+
},
|
|
1544
|
+
],
|
|
1545
|
+
};
|
|
1546
|
+
const modifiedSelections = [];
|
|
1547
|
+
const recordNodes = findRecordSelections(ast);
|
|
1548
|
+
if (recordNodes !== undefined && recordNodes.length > 0) {
|
|
1549
|
+
// each record node represent a connection
|
|
1550
|
+
for (const recordNode of recordNodes) {
|
|
1551
|
+
modifiedSelections.push(injectConnectionForScope(recordNode));
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
const queryNode = modifiedDocumentNode.definitions
|
|
1555
|
+
.filter(isOperationDefinition)
|
|
1556
|
+
.reduce(flatMap(luvioSelections), [])
|
|
1557
|
+
.filter(isObjectFieldSelection)
|
|
1558
|
+
.filter(named('uiapi'))
|
|
1559
|
+
.reduce(flatMap(luvioSelections), [])
|
|
1560
|
+
.filter(isObjectFieldSelection)
|
|
1561
|
+
.filter(named('query'))[0];
|
|
1562
|
+
queryNode.luvioSelections.push(...modifiedSelections);
|
|
1563
|
+
return ast;
|
|
1564
|
+
}
|
|
1565
|
+
function injectConnectionForScope(connectionNode) {
|
|
1566
|
+
if (connectionNode.name === 'ServiceAppointment') {
|
|
1567
|
+
if (connectionNode.arguments !== undefined) {
|
|
1568
|
+
for (const argument of connectionNode.arguments) {
|
|
1569
|
+
if (argument.name === 'scope' &&
|
|
1570
|
+
argument.value.kind === 'EnumValue' &&
|
|
1571
|
+
argument.value.value === 'ASSIGNEDTOME') {
|
|
1572
|
+
const injectedConnctionNode = {
|
|
1573
|
+
...connectionNode,
|
|
1574
|
+
};
|
|
1575
|
+
if (injectedConnctionNode.luvioSelections !== undefined) {
|
|
1576
|
+
const injectedNodes = injectedConnctionNode.luvioSelections
|
|
1577
|
+
.filter(isObjectFieldSelection)
|
|
1578
|
+
.filter(named('edges'))
|
|
1579
|
+
.reduce(flatMap(luvioSelections), [])
|
|
1580
|
+
.filter(isCustomFieldNode)
|
|
1581
|
+
.filter(named('node'));
|
|
1582
|
+
if (injectedNodes !== undefined && injectedNodes.length > 0) {
|
|
1583
|
+
const injectedNode = injectedNodes[0];
|
|
1584
|
+
if (injectedNode.luvioSelections !== undefined) {
|
|
1585
|
+
injectedNode.luvioSelections = mergeSelectionNodes(injectedNode.luvioSelections, [assignedToMe]);
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
return injectedConnctionNode;
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
return { ...connectionNode };
|
|
1595
|
+
}
|
|
1596
|
+
function mergeSelectionNodes(group1, group2) {
|
|
1597
|
+
let sameFields1 = [];
|
|
1598
|
+
let sameFields2 = [];
|
|
1599
|
+
let results = [];
|
|
1600
|
+
for (const node2 of group2) {
|
|
1601
|
+
if (isCustomFieldNode(node2)) {
|
|
1602
|
+
const nodes1SameLevel = group1
|
|
1603
|
+
.filter(isCustomFieldNode)
|
|
1604
|
+
.filter((node1) => node1.name === node2.name && node1.type === node2.type);
|
|
1605
|
+
if (nodes1SameLevel.length > 0) {
|
|
1606
|
+
sameFields1.push(...nodes1SameLevel);
|
|
1607
|
+
sameFields2.push(node2);
|
|
1608
|
+
const mergedNode = nodes1SameLevel.reduce((accu, cur) => mergeCustomFieldNodes(accu, cur), node2);
|
|
1609
|
+
results.push(mergedNode);
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
else if (isObjectFieldSelection(node2)) {
|
|
1613
|
+
const nodes1SameLevel = group1
|
|
1614
|
+
.filter(isObjectFieldSelection)
|
|
1615
|
+
.filter((node1) => node1.name === node2.name);
|
|
1616
|
+
if (nodes1SameLevel.length > 0) {
|
|
1617
|
+
sameFields1.push(...nodes1SameLevel);
|
|
1618
|
+
sameFields2.push(node2);
|
|
1619
|
+
const mergedNode = nodes1SameLevel.reduce((accu, cur) => mergeObjectFieldNodes(accu, cur), node2);
|
|
1620
|
+
results.push(mergedNode);
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
if (sameFields1.length > 0) {
|
|
1625
|
+
const differentNodes1 = group1.filter((node) => !sameFields1.includes(node));
|
|
1626
|
+
results.push(...differentNodes1);
|
|
1627
|
+
const differentNodes2 = group2.filter((node) => !sameFields2.includes(node));
|
|
1628
|
+
results.push(...differentNodes2);
|
|
1629
|
+
}
|
|
1630
|
+
else {
|
|
1631
|
+
return group1.concat(group2);
|
|
1632
|
+
}
|
|
1633
|
+
return results;
|
|
1634
|
+
}
|
|
1635
|
+
function mergeCustomFieldNodes(node1, node2) {
|
|
1636
|
+
let result = node1;
|
|
1637
|
+
if (node1.name === node2.name && node1.kind === node2.kind && node1.type === node2.type) {
|
|
1638
|
+
result = {
|
|
1639
|
+
kind: node1.kind,
|
|
1640
|
+
name: node1.name,
|
|
1641
|
+
type: node1.type,
|
|
1642
|
+
luvioSelections: [],
|
|
1643
|
+
};
|
|
1644
|
+
let selections = [];
|
|
1645
|
+
let sameCustomFields1 = [];
|
|
1646
|
+
let sameCustomFields2 = [];
|
|
1647
|
+
let sameObjectFields1 = [];
|
|
1648
|
+
let sameObjectFields2 = [];
|
|
1649
|
+
let sameScalarFields1 = [];
|
|
1650
|
+
let sameScalarFields2 = [];
|
|
1651
|
+
if (node1.luvioSelections && node2.luvioSelections) {
|
|
1652
|
+
sameCustomFields1 = node1.luvioSelections
|
|
1653
|
+
.filter(isCustomFieldNode)
|
|
1654
|
+
.filter((childNode1) => {
|
|
1655
|
+
if (node2.luvioSelections) {
|
|
1656
|
+
const sames = node2.luvioSelections
|
|
1657
|
+
.filter(isCustomFieldNode)
|
|
1658
|
+
.filter((childNode2) => childNode2.name === childNode1.name);
|
|
1659
|
+
if (sames.length > 0) {
|
|
1660
|
+
const mergedNode = sames.reduce((accu, cur) => mergeCustomFieldNodes(accu, cur), childNode1);
|
|
1661
|
+
selections.push(mergedNode);
|
|
1662
|
+
result = {
|
|
1663
|
+
...result,
|
|
1664
|
+
luvioSelections: selections,
|
|
1665
|
+
};
|
|
1666
|
+
sameCustomFields2.push(...sames);
|
|
1667
|
+
return true;
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
return false;
|
|
1671
|
+
});
|
|
1672
|
+
sameObjectFields1 = node1.luvioSelections
|
|
1673
|
+
.filter(isObjectFieldSelection)
|
|
1674
|
+
.filter((childNode1) => {
|
|
1675
|
+
if (node2.luvioSelections) {
|
|
1676
|
+
const sames = node2.luvioSelections
|
|
1677
|
+
.filter(isObjectFieldSelection)
|
|
1678
|
+
.filter((childNode2) => childNode2.name === childNode1.name);
|
|
1679
|
+
if (sames.length > 0) {
|
|
1680
|
+
const mergedNode = sames.reduce((accu, cur) => mergeObjectFieldNodes(accu, cur), childNode1);
|
|
1681
|
+
selections.push(mergedNode);
|
|
1682
|
+
result = {
|
|
1683
|
+
...result,
|
|
1684
|
+
luvioSelections: selections,
|
|
1685
|
+
};
|
|
1686
|
+
sameObjectFields2.push(...sames);
|
|
1687
|
+
return true;
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
return false;
|
|
1691
|
+
});
|
|
1692
|
+
sameScalarFields1 = node1.luvioSelections
|
|
1693
|
+
.filter(isScalarFieldNode)
|
|
1694
|
+
.filter((childNode1) => {
|
|
1695
|
+
if (node2.luvioSelections) {
|
|
1696
|
+
const sames = node2.luvioSelections
|
|
1697
|
+
.filter(isScalarFieldNode)
|
|
1698
|
+
.filter((childNode2) => childNode2.name === childNode1.name);
|
|
1699
|
+
if (sames.length > 0) {
|
|
1700
|
+
const mergedNode = sames.reduce((accu, cur) => mergeScalarFieldNode(accu, cur), childNode1);
|
|
1701
|
+
selections.push(mergedNode);
|
|
1702
|
+
result = {
|
|
1703
|
+
...result,
|
|
1704
|
+
luvioSelections: selections,
|
|
1705
|
+
};
|
|
1706
|
+
sameScalarFields2.push(...sames);
|
|
1707
|
+
return true;
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
return false;
|
|
1711
|
+
});
|
|
1712
|
+
if (sameCustomFields1.length > 0 ||
|
|
1713
|
+
sameObjectFields1.length > 0 ||
|
|
1714
|
+
sameScalarFields1.length > 0) {
|
|
1715
|
+
const diffNodes1 = node1.luvioSelections.filter((node) => !sameCustomFields1.includes(node) &&
|
|
1716
|
+
!sameObjectFields1.includes(node) &&
|
|
1717
|
+
!sameScalarFields1.includes(node));
|
|
1718
|
+
selections.push(...diffNodes1);
|
|
1719
|
+
const diffNodes2 = node2.luvioSelections.filter((node) => !sameCustomFields2.includes(node) &&
|
|
1720
|
+
!sameObjectFields2.includes(node) &&
|
|
1721
|
+
!sameScalarFields2.includes(node));
|
|
1722
|
+
selections.push(...diffNodes2);
|
|
1723
|
+
result = {
|
|
1724
|
+
...result,
|
|
1725
|
+
luvioSelections: selections,
|
|
1726
|
+
};
|
|
1727
|
+
}
|
|
1728
|
+
else {
|
|
1729
|
+
selections.push(...node1.luvioSelections);
|
|
1730
|
+
selections.push(...node2.luvioSelections);
|
|
1731
|
+
result = {
|
|
1732
|
+
...result,
|
|
1733
|
+
luvioSelections: selections,
|
|
1734
|
+
};
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
else {
|
|
1738
|
+
if (node1.luvioSelections) {
|
|
1739
|
+
return node1;
|
|
1740
|
+
}
|
|
1741
|
+
if (node2.luvioSelections) {
|
|
1742
|
+
return node2;
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1745
|
+
return result;
|
|
1746
|
+
}
|
|
1747
|
+
else {
|
|
1748
|
+
// eslint-disable-next-line
|
|
1749
|
+
throw new Error('The fields name needs to be same to be merged');
|
|
1750
|
+
}
|
|
1751
|
+
}
|
|
1752
|
+
function mergeObjectFieldNodes(node1, node2) {
|
|
1753
|
+
let result = node1;
|
|
1754
|
+
if (node1.name === node2.name && node1.kind === node2.kind) {
|
|
1755
|
+
result = {
|
|
1756
|
+
kind: node1.kind,
|
|
1757
|
+
name: node1.name,
|
|
1758
|
+
directives: node1.directives,
|
|
1759
|
+
luvioSelections: [],
|
|
1760
|
+
};
|
|
1761
|
+
let selections = [];
|
|
1762
|
+
let sameCustomFields1 = [];
|
|
1763
|
+
let sameCustomFields2 = [];
|
|
1764
|
+
let sameObjectFields1 = [];
|
|
1765
|
+
let sameObjectFields2 = [];
|
|
1766
|
+
let sameScalarFields1 = [];
|
|
1767
|
+
let sameScalarFields2 = [];
|
|
1768
|
+
if (node1.luvioSelections && node2.luvioSelections) {
|
|
1769
|
+
sameCustomFields1 = node1.luvioSelections
|
|
1770
|
+
.filter(isCustomFieldNode)
|
|
1771
|
+
.filter((childNode1) => {
|
|
1772
|
+
if (node2.luvioSelections) {
|
|
1773
|
+
const sames = node2.luvioSelections
|
|
1774
|
+
.filter(isCustomFieldNode)
|
|
1775
|
+
.filter((childNode2) => childNode2.name === childNode1.name);
|
|
1776
|
+
if (sames.length > 0) {
|
|
1777
|
+
const mergedNode = sames.reduce((accu, cur) => mergeCustomFieldNodes(accu, cur), childNode1);
|
|
1778
|
+
selections.push(mergedNode);
|
|
1779
|
+
result = {
|
|
1780
|
+
...result,
|
|
1781
|
+
luvioSelections: selections,
|
|
1782
|
+
};
|
|
1783
|
+
sameCustomFields2.push(...sames);
|
|
1784
|
+
return true;
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1787
|
+
return false;
|
|
1788
|
+
});
|
|
1789
|
+
sameObjectFields1 = node1.luvioSelections
|
|
1790
|
+
.filter(isObjectFieldSelection)
|
|
1791
|
+
.filter((childNode1) => {
|
|
1792
|
+
if (node2.luvioSelections) {
|
|
1793
|
+
const sames = node2.luvioSelections
|
|
1794
|
+
.filter(isObjectFieldSelection)
|
|
1795
|
+
.filter((childNode2) => childNode2.name === childNode1.name);
|
|
1796
|
+
if (sames.length > 0) {
|
|
1797
|
+
const mergedNode = sames.reduce((accu, cur) => mergeObjectFieldNodes(accu, cur), childNode1);
|
|
1798
|
+
selections.push(mergedNode);
|
|
1799
|
+
result = {
|
|
1800
|
+
...result,
|
|
1801
|
+
luvioSelections: selections,
|
|
1802
|
+
};
|
|
1803
|
+
sameObjectFields2.push(...sames);
|
|
1804
|
+
return true;
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
return false;
|
|
1808
|
+
});
|
|
1809
|
+
sameScalarFields1 = node1.luvioSelections
|
|
1810
|
+
.filter(isScalarFieldNode)
|
|
1811
|
+
.filter((childNode1) => {
|
|
1812
|
+
if (node2.luvioSelections) {
|
|
1813
|
+
const sames = node2.luvioSelections
|
|
1814
|
+
.filter(isScalarFieldNode)
|
|
1815
|
+
.filter((childNode2) => childNode2.name === childNode1.name);
|
|
1816
|
+
if (sames.length > 0) {
|
|
1817
|
+
const mergedNode = sames.reduce((accu, cur) => mergeScalarFieldNode(accu, cur), childNode1);
|
|
1818
|
+
selections.push(mergedNode);
|
|
1819
|
+
result = {
|
|
1820
|
+
...result,
|
|
1821
|
+
luvioSelections: selections,
|
|
1822
|
+
};
|
|
1823
|
+
sameScalarFields2.push(...sames);
|
|
1824
|
+
return true;
|
|
1825
|
+
}
|
|
1826
|
+
}
|
|
1827
|
+
return false;
|
|
1828
|
+
});
|
|
1829
|
+
if (sameCustomFields1.length > 0 ||
|
|
1830
|
+
sameObjectFields1.length > 0 ||
|
|
1831
|
+
sameScalarFields1.length > 0) {
|
|
1832
|
+
const diffNodes1 = node1.luvioSelections.filter((node) => !sameCustomFields1.includes(node) &&
|
|
1833
|
+
!sameObjectFields1.includes(node) &&
|
|
1834
|
+
!sameScalarFields1.includes(node));
|
|
1835
|
+
selections.push(...diffNodes1);
|
|
1836
|
+
const diffNodes2 = node2.luvioSelections.filter((node) => !sameCustomFields2.includes(node) &&
|
|
1837
|
+
!sameObjectFields2.includes(node) &&
|
|
1838
|
+
!sameScalarFields2.includes(node));
|
|
1839
|
+
selections.push(...diffNodes2);
|
|
1840
|
+
result = {
|
|
1841
|
+
...result,
|
|
1842
|
+
luvioSelections: selections,
|
|
1843
|
+
};
|
|
1844
|
+
}
|
|
1845
|
+
else {
|
|
1846
|
+
selections.push(...node1.luvioSelections);
|
|
1847
|
+
selections.push(...node2.luvioSelections);
|
|
1848
|
+
result = {
|
|
1849
|
+
...result,
|
|
1850
|
+
luvioSelections: selections,
|
|
1851
|
+
};
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
else {
|
|
1855
|
+
if (node1.luvioSelections) {
|
|
1856
|
+
return node1;
|
|
1857
|
+
}
|
|
1858
|
+
if (node2.luvioSelections) {
|
|
1859
|
+
return node2;
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1862
|
+
return result;
|
|
1863
|
+
}
|
|
1864
|
+
else {
|
|
1865
|
+
// eslint-disable-next-line
|
|
1866
|
+
throw new Error('The fields name needs to be same to be merged');
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
function mergeScalarFieldNode(node1, node2) {
|
|
1870
|
+
if (node1.kind === node1.kind && node1.name === node2.name) {
|
|
1871
|
+
return { ...node1 };
|
|
1872
|
+
}
|
|
1873
|
+
// eslint-disable-next-line
|
|
1874
|
+
throw new Error('The fields name needs to be same to be merged');
|
|
1875
|
+
}
|
|
1876
|
+
function findRecordSelections(document) {
|
|
1877
|
+
return document.definitions
|
|
1878
|
+
.filter(isOperationDefinition)
|
|
1879
|
+
.reduce(flatMap(luvioSelections), [])
|
|
1880
|
+
.filter(isObjectFieldSelection)
|
|
1881
|
+
.filter(named('uiapi'))
|
|
1882
|
+
.reduce(flatMap(luvioSelections), [])
|
|
1883
|
+
.filter(isObjectFieldSelection)
|
|
1884
|
+
.filter(named('query'))
|
|
1885
|
+
.reduce(flatMap(luvioSelections), [])
|
|
1886
|
+
.filter(isCustomFieldNode);
|
|
1887
|
+
}
|
|
1888
|
+
function isOperationDefinition(node) {
|
|
1889
|
+
return node.kind === 'OperationDefinition';
|
|
1890
|
+
}
|
|
1891
|
+
function isObjectFieldSelection(node) {
|
|
1892
|
+
return node !== undefined && node.kind === 'ObjectFieldSelection';
|
|
1893
|
+
}
|
|
1894
|
+
function isCustomFieldNode(node) {
|
|
1895
|
+
return node !== undefined && node.kind === 'CustomFieldSelection';
|
|
1896
|
+
}
|
|
1897
|
+
function isScalarFieldNode(node) {
|
|
1898
|
+
return node !== undefined && node.kind === 'ScalarFieldSelection';
|
|
1899
|
+
}
|
|
1900
|
+
function flatMap(transform) {
|
|
1901
|
+
return (acc, current) => {
|
|
1902
|
+
const mapped = transform(current);
|
|
1903
|
+
return acc.concat(mapped);
|
|
1904
|
+
};
|
|
1905
|
+
}
|
|
1906
|
+
function luvioSelections(node) {
|
|
1907
|
+
return node.luvioSelections === undefined ? [] : node.luvioSelections;
|
|
1908
|
+
}
|
|
1909
|
+
function named(name) {
|
|
1910
|
+
return (node) => node.name === name;
|
|
1911
1911
|
}
|
|
1912
1912
|
|
|
1913
|
-
const adapterName = 'graphQL';
|
|
1914
|
-
const RECORD_REPRESENTATION_NAME = 'RecordRepresentation';
|
|
1915
|
-
const GRAPHQL_ROOT_KEY = `${namespace}::${representationName}`;
|
|
1916
|
-
function buildSnapshotRefresh(luvio, config, fragment) {
|
|
1917
|
-
return {
|
|
1918
|
-
config,
|
|
1919
|
-
resolve: () => buildNetworkSnapshot(luvio, config, fragment),
|
|
1920
|
-
};
|
|
1921
|
-
}
|
|
1922
|
-
function createFragment(luvio, query, variables) {
|
|
1923
|
-
return {
|
|
1924
|
-
kind: 'Fragment',
|
|
1925
|
-
synthetic: false,
|
|
1926
|
-
reader: true,
|
|
1927
|
-
version: GRAPHQL_INGEST_VERSION,
|
|
1928
|
-
read: createRead(luvio, query, variables),
|
|
1929
|
-
};
|
|
1930
|
-
}
|
|
1931
|
-
function onFetchResponseSuccess(luvio, config, response, fragment) {
|
|
1932
|
-
const { query, variables } = config;
|
|
1933
|
-
const { body } = response;
|
|
1934
|
-
if (body.errors && body.errors.length > 0) {
|
|
1935
|
-
return Promise.resolve(luvio.storeLookup({
|
|
1936
|
-
recordId: representationName,
|
|
1937
|
-
node: {
|
|
1938
|
-
kind: 'Fragment',
|
|
1939
|
-
synthetic: true,
|
|
1940
|
-
reader: true,
|
|
1941
|
-
read: (reader) => {
|
|
1942
|
-
const sink = {};
|
|
1943
|
-
reader.enterPath('data');
|
|
1944
|
-
reader.assignNonScalar(sink, 'data', body.data);
|
|
1945
|
-
reader.exitPath();
|
|
1946
|
-
reader.enterPath('errors');
|
|
1947
|
-
reader.assignNonScalar(sink, 'errors', deepFreeze(body.errors));
|
|
1948
|
-
reader.exitPath();
|
|
1949
|
-
return sink;
|
|
1950
|
-
},
|
|
1951
|
-
},
|
|
1952
|
-
variables: {},
|
|
1953
|
-
}));
|
|
1954
|
-
}
|
|
1955
|
-
const ingest = createIngest(query, variables);
|
|
1956
|
-
luvio.storeIngest(GRAPHQL_ROOT_KEY, ingest, body.data);
|
|
1957
|
-
const snapshot = luvio.storeLookup({
|
|
1958
|
-
recordId: GRAPHQL_ROOT_KEY,
|
|
1959
|
-
node: fragment,
|
|
1960
|
-
variables: {},
|
|
1961
|
-
}, buildSnapshotRefresh(luvio, config, fragment));
|
|
1962
|
-
return luvio.storeBroadcast().then(() => snapshot);
|
|
1963
|
-
}
|
|
1964
|
-
function getResponseCacheKeys(luvio, config, response, fragment) {
|
|
1965
|
-
// TODO [W-10147827]: make this more efficient
|
|
1966
|
-
// for now we will get the cache keys by actually ingesting then looking at
|
|
1967
|
-
// the seenRecords + recordId
|
|
1968
|
-
const { query, variables } = config;
|
|
1969
|
-
const { body } = response;
|
|
1970
|
-
if (body.errors && body.errors.length > 0) {
|
|
1971
|
-
return new StoreKeyMap();
|
|
1972
|
-
}
|
|
1973
|
-
const ingest = createIngest(query, variables);
|
|
1974
|
-
// ingest mutates the response so we have to make a copy
|
|
1975
|
-
const dataCopy = parse(stringify(body.data));
|
|
1976
|
-
luvio.storeIngest(GRAPHQL_ROOT_KEY, ingest, dataCopy);
|
|
1977
|
-
const snapshot = luvio.storeLookup({
|
|
1978
|
-
recordId: GRAPHQL_ROOT_KEY,
|
|
1979
|
-
node: fragment,
|
|
1980
|
-
variables: {},
|
|
1981
|
-
}, buildSnapshotRefresh(luvio, config, fragment));
|
|
1982
|
-
if (snapshot.state === 'Error') {
|
|
1983
|
-
return new StoreKeyMap();
|
|
1984
|
-
}
|
|
1985
|
-
const keys = [...snapshot.seenRecords.keysAsArray(), snapshot.recordId];
|
|
1986
|
-
const keySet = new StoreKeyMap();
|
|
1987
|
-
for (let i = 0, len = keys.length; i < len; i++) {
|
|
1988
|
-
const key = keys[i];
|
|
1989
|
-
const keyNamespace = key.split('::')[0];
|
|
1990
|
-
const representationName = key.split('::')[1].split(':')[0];
|
|
1991
|
-
keySet.set(key, {
|
|
1992
|
-
namespace: keyNamespace,
|
|
1993
|
-
representationName,
|
|
1994
|
-
mergeable: keyNamespace === namespace || representationName === RECORD_REPRESENTATION_NAME,
|
|
1995
|
-
});
|
|
1996
|
-
}
|
|
1997
|
-
return keySet;
|
|
1998
|
-
}
|
|
1999
|
-
function onFetchResponseError(luvio, config, response) {
|
|
2000
|
-
const errorSnapshot = luvio.errorSnapshot(response);
|
|
2001
|
-
luvio.storeIngestError(GRAPHQL_ROOT_KEY, errorSnapshot);
|
|
2002
|
-
return luvio.storeBroadcast().then(() => errorSnapshot);
|
|
2003
|
-
}
|
|
2004
|
-
function buildNetworkSnapshot(luvio, config, fragment, options) {
|
|
2005
|
-
const { variables: queryVariables, query } = config;
|
|
2006
|
-
const request = {
|
|
2007
|
-
baseUri: '/services/data/v58.0',
|
|
2008
|
-
basePath: '/graphql',
|
|
2009
|
-
method: 'post',
|
|
2010
|
-
priority: 'normal',
|
|
2011
|
-
body: {
|
|
2012
|
-
query: astToString(query),
|
|
2013
|
-
variables: queryVariables,
|
|
2014
|
-
},
|
|
2015
|
-
queryParams: {},
|
|
2016
|
-
urlParams: {},
|
|
2017
|
-
headers: {},
|
|
2018
|
-
};
|
|
2019
|
-
return luvio.dispatchResourceRequest(request, options).then((resp) => {
|
|
2020
|
-
return luvio.handleSuccessResponse(() => onFetchResponseSuccess(luvio, config, resp, fragment), () => getResponseCacheKeys(luvio, config, resp, fragment));
|
|
2021
|
-
}, (errorResponse) => {
|
|
2022
|
-
return luvio.handleErrorResponse(() => onFetchResponseError(luvio, config, errorResponse));
|
|
2023
|
-
});
|
|
2024
|
-
}
|
|
2025
|
-
function validateGraphQlConfig(untrustedConfig) {
|
|
2026
|
-
if (!untrustedIsObject(untrustedConfig)) {
|
|
2027
|
-
return {
|
|
2028
|
-
validatedConfig: null,
|
|
2029
|
-
errors: ["Invalid Config provided isn't an object"],
|
|
2030
|
-
};
|
|
2031
|
-
}
|
|
2032
|
-
if (!('variables' in untrustedConfig && 'query' in untrustedConfig)) {
|
|
2033
|
-
return {
|
|
2034
|
-
validatedConfig: null,
|
|
2035
|
-
errors: [
|
|
2036
|
-
'Missing one or both of the required config parameters "query" and "variables"',
|
|
2037
|
-
],
|
|
2038
|
-
};
|
|
2039
|
-
}
|
|
2040
|
-
const { variables, query } = untrustedConfig;
|
|
2041
|
-
const validationErrors = [];
|
|
2042
|
-
if (isLuvioDocumentNode(query) === false) {
|
|
2043
|
-
validationErrors.push('The config parameter "query" isn\'t a valid LuvioDocumentNode');
|
|
2044
|
-
}
|
|
2045
|
-
const ast = query;
|
|
2046
|
-
if (isGraphQLVariables(variables) === false) {
|
|
2047
|
-
validationErrors.push('The config parameter "variables" isn\'t an object');
|
|
2048
|
-
}
|
|
2049
|
-
if (validationErrors.length > 0) {
|
|
2050
|
-
return {
|
|
2051
|
-
validatedConfig: null,
|
|
2052
|
-
errors: validationErrors,
|
|
2053
|
-
};
|
|
2054
|
-
}
|
|
2055
|
-
validationErrors.push(...validate(ast, variables));
|
|
2056
|
-
const { useUiApiAdapter } = untrustedConfig;
|
|
2057
|
-
if (useUiApiAdapter !== undefined && typeof useUiApiAdapter !== 'boolean') {
|
|
2058
|
-
validationErrors.push('The config parameter "useUiApiAdapter" isn\'t a boolean');
|
|
2059
|
-
}
|
|
2060
|
-
if (validationErrors.length > 0) {
|
|
2061
|
-
return {
|
|
2062
|
-
validatedConfig: null,
|
|
2063
|
-
errors: validationErrors,
|
|
2064
|
-
};
|
|
2065
|
-
}
|
|
2066
|
-
return {
|
|
2067
|
-
validatedConfig: {
|
|
2068
|
-
variables,
|
|
2069
|
-
query,
|
|
2070
|
-
useUiApiAdapter,
|
|
2071
|
-
},
|
|
2072
|
-
errors: [],
|
|
2073
|
-
};
|
|
2074
|
-
}
|
|
2075
|
-
function buildCachedSnapshot(context, storeLookup) {
|
|
2076
|
-
return buildInMemorySnapshot(context, storeLookup);
|
|
2077
|
-
}
|
|
2078
|
-
function buildInMemorySnapshot(context, storeLookup) {
|
|
2079
|
-
const { config, fragment, luvio } = context;
|
|
2080
|
-
const selector = {
|
|
2081
|
-
recordId: GRAPHQL_ROOT_KEY,
|
|
2082
|
-
node: fragment,
|
|
2083
|
-
variables: {},
|
|
2084
|
-
};
|
|
2085
|
-
return storeLookup(selector, buildSnapshotRefresh(luvio, config, fragment));
|
|
2086
|
-
}
|
|
2087
|
-
function buildNetworkSnapshotCachePolicy(context, coercedAdapterRequestContext) {
|
|
2088
|
-
const { config, fragment, luvio } = context;
|
|
2089
|
-
const { networkPriority, requestCorrelator, eventObservers } = coercedAdapterRequestContext;
|
|
2090
|
-
const dispatchOptions = {
|
|
2091
|
-
resourceRequestContext: {
|
|
2092
|
-
requestCorrelator,
|
|
2093
|
-
},
|
|
2094
|
-
eventObservers,
|
|
2095
|
-
};
|
|
2096
|
-
if (networkPriority !== 'normal') {
|
|
2097
|
-
dispatchOptions.overrides = {
|
|
2098
|
-
priority: networkPriority,
|
|
2099
|
-
};
|
|
2100
|
-
}
|
|
2101
|
-
return buildNetworkSnapshot(luvio, config, fragment, dispatchOptions);
|
|
2102
|
-
}
|
|
2103
|
-
const graphQLAdapterFactory = (luvio) => {
|
|
2104
|
-
const uiApiGraphQLAdapter = graphqlAdapterFactory(luvio);
|
|
2105
|
-
function graphql(untrustedConfig, requestContext) {
|
|
2106
|
-
const { validatedConfig, errors } = validateGraphQlConfig(untrustedConfig);
|
|
2107
|
-
if (errors.length > 0 || validatedConfig === null) {
|
|
2108
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
2109
|
-
throw new Error(errors.join(', '));
|
|
2110
|
-
}
|
|
2111
|
-
return null;
|
|
2112
|
-
}
|
|
2113
|
-
const { query, variables, useUiApiAdapter } = validatedConfig;
|
|
2114
|
-
if (useUiApiAdapter === undefined || useUiApiAdapter === true) {
|
|
2115
|
-
// Forward to new adapters
|
|
2116
|
-
const resolvedQuery = astResolver(query);
|
|
2117
|
-
if (resolvedQuery === undefined) {
|
|
2118
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
2119
|
-
throw new Error('Could not resolve standard AST');
|
|
2120
|
-
}
|
|
2121
|
-
return null;
|
|
2122
|
-
}
|
|
2123
|
-
return uiApiGraphQLAdapter({
|
|
2124
|
-
query: resolvedQuery,
|
|
2125
|
-
variables,
|
|
2126
|
-
}, requestContext);
|
|
2127
|
-
}
|
|
2128
|
-
else {
|
|
2129
|
-
const fieldInjectionRequired = shouldInjectFields(query);
|
|
2130
|
-
const validatedConfigWithInjection = fieldInjectionRequired
|
|
2131
|
-
? graphqlConfigWithInjectedAST(validatedConfig)
|
|
2132
|
-
: validatedConfig;
|
|
2133
|
-
const fragment = createFragment(luvio, validatedConfigWithInjection.query, variables);
|
|
2134
|
-
const context = {
|
|
2135
|
-
config: validatedConfigWithInjection,
|
|
2136
|
-
fragment,
|
|
2137
|
-
luvio,
|
|
2138
|
-
};
|
|
2139
|
-
const snapshotOrPromiseFromCachePolicy = luvio.applyCachePolicy(requestContext || {}, context, buildCachedSnapshot, buildNetworkSnapshotCachePolicy);
|
|
2140
|
-
if (storeEval !== undefined) {
|
|
2141
|
-
const observers = requestContext && requestContext.eventObservers
|
|
2142
|
-
? requestContext.eventObservers
|
|
2143
|
-
: [];
|
|
2144
|
-
// uses the original ast to do the eval to avoid fields not needed by users
|
|
2145
|
-
return storeEval(validatedConfig, snapshotOrPromiseFromCachePolicy, observers);
|
|
2146
|
-
}
|
|
2147
|
-
return snapshotOrPromiseFromCachePolicy;
|
|
2148
|
-
}
|
|
2149
|
-
}
|
|
2150
|
-
return graphql;
|
|
2151
|
-
};
|
|
2152
|
-
function graphqlConfigWithInjectedAST(graphqlConfig) {
|
|
2153
|
-
const { query } = graphqlConfig;
|
|
2154
|
-
const astCopy = parse(stringify(query));
|
|
2155
|
-
const modifiedAST = injectFieldsGQL(astCopy);
|
|
2156
|
-
return {
|
|
2157
|
-
...graphqlConfig,
|
|
2158
|
-
query: modifiedAST,
|
|
2159
|
-
};
|
|
2160
|
-
}
|
|
2161
|
-
// make sure to register the configuration whenever this module loads
|
|
1913
|
+
const adapterName = 'graphQL';
|
|
1914
|
+
const RECORD_REPRESENTATION_NAME = 'RecordRepresentation';
|
|
1915
|
+
const GRAPHQL_ROOT_KEY = `${namespace}::${representationName}`;
|
|
1916
|
+
function buildSnapshotRefresh(luvio, config, fragment) {
|
|
1917
|
+
return {
|
|
1918
|
+
config,
|
|
1919
|
+
resolve: () => buildNetworkSnapshot(luvio, config, fragment),
|
|
1920
|
+
};
|
|
1921
|
+
}
|
|
1922
|
+
function createFragment(luvio, query, variables) {
|
|
1923
|
+
return {
|
|
1924
|
+
kind: 'Fragment',
|
|
1925
|
+
synthetic: false,
|
|
1926
|
+
reader: true,
|
|
1927
|
+
version: GRAPHQL_INGEST_VERSION,
|
|
1928
|
+
read: createRead(luvio, query, variables),
|
|
1929
|
+
};
|
|
1930
|
+
}
|
|
1931
|
+
function onFetchResponseSuccess(luvio, config, response, fragment) {
|
|
1932
|
+
const { query, variables } = config;
|
|
1933
|
+
const { body } = response;
|
|
1934
|
+
if (body.errors && body.errors.length > 0) {
|
|
1935
|
+
return Promise.resolve(luvio.storeLookup({
|
|
1936
|
+
recordId: representationName,
|
|
1937
|
+
node: {
|
|
1938
|
+
kind: 'Fragment',
|
|
1939
|
+
synthetic: true,
|
|
1940
|
+
reader: true,
|
|
1941
|
+
read: (reader) => {
|
|
1942
|
+
const sink = {};
|
|
1943
|
+
reader.enterPath('data');
|
|
1944
|
+
reader.assignNonScalar(sink, 'data', body.data);
|
|
1945
|
+
reader.exitPath();
|
|
1946
|
+
reader.enterPath('errors');
|
|
1947
|
+
reader.assignNonScalar(sink, 'errors', deepFreeze(body.errors));
|
|
1948
|
+
reader.exitPath();
|
|
1949
|
+
return sink;
|
|
1950
|
+
},
|
|
1951
|
+
},
|
|
1952
|
+
variables: {},
|
|
1953
|
+
}));
|
|
1954
|
+
}
|
|
1955
|
+
const ingest = createIngest(query, variables);
|
|
1956
|
+
luvio.storeIngest(GRAPHQL_ROOT_KEY, ingest, body.data);
|
|
1957
|
+
const snapshot = luvio.storeLookup({
|
|
1958
|
+
recordId: GRAPHQL_ROOT_KEY,
|
|
1959
|
+
node: fragment,
|
|
1960
|
+
variables: {},
|
|
1961
|
+
}, buildSnapshotRefresh(luvio, config, fragment));
|
|
1962
|
+
return luvio.storeBroadcast().then(() => snapshot);
|
|
1963
|
+
}
|
|
1964
|
+
function getResponseCacheKeys(luvio, config, response, fragment) {
|
|
1965
|
+
// TODO [W-10147827]: make this more efficient
|
|
1966
|
+
// for now we will get the cache keys by actually ingesting then looking at
|
|
1967
|
+
// the seenRecords + recordId
|
|
1968
|
+
const { query, variables } = config;
|
|
1969
|
+
const { body } = response;
|
|
1970
|
+
if (body.errors && body.errors.length > 0) {
|
|
1971
|
+
return new StoreKeyMap();
|
|
1972
|
+
}
|
|
1973
|
+
const ingest = createIngest(query, variables);
|
|
1974
|
+
// ingest mutates the response so we have to make a copy
|
|
1975
|
+
const dataCopy = parse(stringify(body.data));
|
|
1976
|
+
luvio.storeIngest(GRAPHQL_ROOT_KEY, ingest, dataCopy);
|
|
1977
|
+
const snapshot = luvio.storeLookup({
|
|
1978
|
+
recordId: GRAPHQL_ROOT_KEY,
|
|
1979
|
+
node: fragment,
|
|
1980
|
+
variables: {},
|
|
1981
|
+
}, buildSnapshotRefresh(luvio, config, fragment));
|
|
1982
|
+
if (snapshot.state === 'Error') {
|
|
1983
|
+
return new StoreKeyMap();
|
|
1984
|
+
}
|
|
1985
|
+
const keys = [...snapshot.seenRecords.keysAsArray(), snapshot.recordId];
|
|
1986
|
+
const keySet = new StoreKeyMap();
|
|
1987
|
+
for (let i = 0, len = keys.length; i < len; i++) {
|
|
1988
|
+
const key = keys[i];
|
|
1989
|
+
const keyNamespace = key.split('::')[0];
|
|
1990
|
+
const representationName = key.split('::')[1].split(':')[0];
|
|
1991
|
+
keySet.set(key, {
|
|
1992
|
+
namespace: keyNamespace,
|
|
1993
|
+
representationName,
|
|
1994
|
+
mergeable: keyNamespace === namespace || representationName === RECORD_REPRESENTATION_NAME,
|
|
1995
|
+
});
|
|
1996
|
+
}
|
|
1997
|
+
return keySet;
|
|
1998
|
+
}
|
|
1999
|
+
function onFetchResponseError(luvio, config, response) {
|
|
2000
|
+
const errorSnapshot = luvio.errorSnapshot(response);
|
|
2001
|
+
luvio.storeIngestError(GRAPHQL_ROOT_KEY, errorSnapshot);
|
|
2002
|
+
return luvio.storeBroadcast().then(() => errorSnapshot);
|
|
2003
|
+
}
|
|
2004
|
+
function buildNetworkSnapshot(luvio, config, fragment, options) {
|
|
2005
|
+
const { variables: queryVariables, query } = config;
|
|
2006
|
+
const request = {
|
|
2007
|
+
baseUri: '/services/data/v58.0',
|
|
2008
|
+
basePath: '/graphql',
|
|
2009
|
+
method: 'post',
|
|
2010
|
+
priority: 'normal',
|
|
2011
|
+
body: {
|
|
2012
|
+
query: astToString(query),
|
|
2013
|
+
variables: queryVariables,
|
|
2014
|
+
},
|
|
2015
|
+
queryParams: {},
|
|
2016
|
+
urlParams: {},
|
|
2017
|
+
headers: {},
|
|
2018
|
+
};
|
|
2019
|
+
return luvio.dispatchResourceRequest(request, options).then((resp) => {
|
|
2020
|
+
return luvio.handleSuccessResponse(() => onFetchResponseSuccess(luvio, config, resp, fragment), () => getResponseCacheKeys(luvio, config, resp, fragment));
|
|
2021
|
+
}, (errorResponse) => {
|
|
2022
|
+
return luvio.handleErrorResponse(() => onFetchResponseError(luvio, config, errorResponse));
|
|
2023
|
+
});
|
|
2024
|
+
}
|
|
2025
|
+
function validateGraphQlConfig(untrustedConfig) {
|
|
2026
|
+
if (!untrustedIsObject(untrustedConfig)) {
|
|
2027
|
+
return {
|
|
2028
|
+
validatedConfig: null,
|
|
2029
|
+
errors: ["Invalid Config provided isn't an object"],
|
|
2030
|
+
};
|
|
2031
|
+
}
|
|
2032
|
+
if (!('variables' in untrustedConfig && 'query' in untrustedConfig)) {
|
|
2033
|
+
return {
|
|
2034
|
+
validatedConfig: null,
|
|
2035
|
+
errors: [
|
|
2036
|
+
'Missing one or both of the required config parameters "query" and "variables"',
|
|
2037
|
+
],
|
|
2038
|
+
};
|
|
2039
|
+
}
|
|
2040
|
+
const { variables, query } = untrustedConfig;
|
|
2041
|
+
const validationErrors = [];
|
|
2042
|
+
if (isLuvioDocumentNode(query) === false) {
|
|
2043
|
+
validationErrors.push('The config parameter "query" isn\'t a valid LuvioDocumentNode');
|
|
2044
|
+
}
|
|
2045
|
+
const ast = query;
|
|
2046
|
+
if (isGraphQLVariables(variables) === false) {
|
|
2047
|
+
validationErrors.push('The config parameter "variables" isn\'t an object');
|
|
2048
|
+
}
|
|
2049
|
+
if (validationErrors.length > 0) {
|
|
2050
|
+
return {
|
|
2051
|
+
validatedConfig: null,
|
|
2052
|
+
errors: validationErrors,
|
|
2053
|
+
};
|
|
2054
|
+
}
|
|
2055
|
+
validationErrors.push(...validate(ast, variables));
|
|
2056
|
+
const { useUiApiAdapter } = untrustedConfig;
|
|
2057
|
+
if (useUiApiAdapter !== undefined && typeof useUiApiAdapter !== 'boolean') {
|
|
2058
|
+
validationErrors.push('The config parameter "useUiApiAdapter" isn\'t a boolean');
|
|
2059
|
+
}
|
|
2060
|
+
if (validationErrors.length > 0) {
|
|
2061
|
+
return {
|
|
2062
|
+
validatedConfig: null,
|
|
2063
|
+
errors: validationErrors,
|
|
2064
|
+
};
|
|
2065
|
+
}
|
|
2066
|
+
return {
|
|
2067
|
+
validatedConfig: {
|
|
2068
|
+
variables,
|
|
2069
|
+
query,
|
|
2070
|
+
useUiApiAdapter,
|
|
2071
|
+
},
|
|
2072
|
+
errors: [],
|
|
2073
|
+
};
|
|
2074
|
+
}
|
|
2075
|
+
function buildCachedSnapshot(context, storeLookup) {
|
|
2076
|
+
return buildInMemorySnapshot(context, storeLookup);
|
|
2077
|
+
}
|
|
2078
|
+
function buildInMemorySnapshot(context, storeLookup) {
|
|
2079
|
+
const { config, fragment, luvio } = context;
|
|
2080
|
+
const selector = {
|
|
2081
|
+
recordId: GRAPHQL_ROOT_KEY,
|
|
2082
|
+
node: fragment,
|
|
2083
|
+
variables: {},
|
|
2084
|
+
};
|
|
2085
|
+
return storeLookup(selector, buildSnapshotRefresh(luvio, config, fragment));
|
|
2086
|
+
}
|
|
2087
|
+
function buildNetworkSnapshotCachePolicy(context, coercedAdapterRequestContext) {
|
|
2088
|
+
const { config, fragment, luvio } = context;
|
|
2089
|
+
const { networkPriority, requestCorrelator, eventObservers } = coercedAdapterRequestContext;
|
|
2090
|
+
const dispatchOptions = {
|
|
2091
|
+
resourceRequestContext: {
|
|
2092
|
+
requestCorrelator,
|
|
2093
|
+
},
|
|
2094
|
+
eventObservers,
|
|
2095
|
+
};
|
|
2096
|
+
if (networkPriority !== 'normal') {
|
|
2097
|
+
dispatchOptions.overrides = {
|
|
2098
|
+
priority: networkPriority,
|
|
2099
|
+
};
|
|
2100
|
+
}
|
|
2101
|
+
return buildNetworkSnapshot(luvio, config, fragment, dispatchOptions);
|
|
2102
|
+
}
|
|
2103
|
+
const graphQLAdapterFactory = (luvio) => {
|
|
2104
|
+
const uiApiGraphQLAdapter = graphqlAdapterFactory(luvio);
|
|
2105
|
+
function graphql(untrustedConfig, requestContext) {
|
|
2106
|
+
const { validatedConfig, errors } = validateGraphQlConfig(untrustedConfig);
|
|
2107
|
+
if (errors.length > 0 || validatedConfig === null) {
|
|
2108
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
2109
|
+
throw new Error(errors.join(', '));
|
|
2110
|
+
}
|
|
2111
|
+
return null;
|
|
2112
|
+
}
|
|
2113
|
+
const { query, variables, useUiApiAdapter } = validatedConfig;
|
|
2114
|
+
if (useUiApiAdapter === undefined || useUiApiAdapter === true) {
|
|
2115
|
+
// Forward to new adapters
|
|
2116
|
+
const resolvedQuery = astResolver(query);
|
|
2117
|
+
if (resolvedQuery === undefined) {
|
|
2118
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
2119
|
+
throw new Error('Could not resolve standard AST');
|
|
2120
|
+
}
|
|
2121
|
+
return null;
|
|
2122
|
+
}
|
|
2123
|
+
return uiApiGraphQLAdapter({
|
|
2124
|
+
query: resolvedQuery,
|
|
2125
|
+
variables,
|
|
2126
|
+
}, requestContext);
|
|
2127
|
+
}
|
|
2128
|
+
else {
|
|
2129
|
+
const fieldInjectionRequired = shouldInjectFields(query);
|
|
2130
|
+
const validatedConfigWithInjection = fieldInjectionRequired
|
|
2131
|
+
? graphqlConfigWithInjectedAST(validatedConfig)
|
|
2132
|
+
: validatedConfig;
|
|
2133
|
+
const fragment = createFragment(luvio, validatedConfigWithInjection.query, variables);
|
|
2134
|
+
const context = {
|
|
2135
|
+
config: validatedConfigWithInjection,
|
|
2136
|
+
fragment,
|
|
2137
|
+
luvio,
|
|
2138
|
+
};
|
|
2139
|
+
const snapshotOrPromiseFromCachePolicy = luvio.applyCachePolicy(requestContext || {}, context, buildCachedSnapshot, buildNetworkSnapshotCachePolicy);
|
|
2140
|
+
if (storeEval !== undefined) {
|
|
2141
|
+
const observers = requestContext && requestContext.eventObservers
|
|
2142
|
+
? requestContext.eventObservers
|
|
2143
|
+
: [];
|
|
2144
|
+
// uses the original ast to do the eval to avoid fields not needed by users
|
|
2145
|
+
return storeEval(validatedConfig, snapshotOrPromiseFromCachePolicy, observers);
|
|
2146
|
+
}
|
|
2147
|
+
return snapshotOrPromiseFromCachePolicy;
|
|
2148
|
+
}
|
|
2149
|
+
}
|
|
2150
|
+
return graphql;
|
|
2151
|
+
};
|
|
2152
|
+
function graphqlConfigWithInjectedAST(graphqlConfig) {
|
|
2153
|
+
const { query } = graphqlConfig;
|
|
2154
|
+
const astCopy = parse(stringify(query));
|
|
2155
|
+
const modifiedAST = injectFieldsGQL(astCopy);
|
|
2156
|
+
return {
|
|
2157
|
+
...graphqlConfig,
|
|
2158
|
+
query: modifiedAST,
|
|
2159
|
+
};
|
|
2160
|
+
}
|
|
2161
|
+
// make sure to register the configuration whenever this module loads
|
|
2162
2162
|
register({ id: '@salesforce/lds-adapters-graphql', configuration });
|
|
2163
2163
|
|
|
2164
|
-
let graphQL;
|
|
2165
|
-
let unstable_graphQL_imperative;
|
|
2166
|
-
// TODO [W-9992865]: remove this export when lds-worker-api usage has been updated
|
|
2167
|
-
let graphQLImperative;
|
|
2168
|
-
const adapterMetadata = {
|
|
2169
|
-
apiFamily: namespace,
|
|
2170
|
-
name: adapterName,
|
|
2171
|
-
};
|
|
2172
|
-
withDefaultLuvio((luvio) => {
|
|
2173
|
-
const ldsAdapter = createLDSAdapter(luvio, namespace, graphQLAdapterFactory);
|
|
2174
|
-
graphQL = createWireAdapterConstructor(luvio, createInstrumentedAdapter(ldsAdapter, adapterMetadata), adapterMetadata);
|
|
2175
|
-
unstable_graphQL_imperative = createImperativeAdapter(luvio, createInstrumentedAdapter(ldsAdapter, adapterMetadata), adapterMetadata);
|
|
2176
|
-
graphQLImperative = ldsAdapter;
|
|
2164
|
+
let graphQL;
|
|
2165
|
+
let unstable_graphQL_imperative;
|
|
2166
|
+
// TODO [W-9992865]: remove this export when lds-worker-api usage has been updated
|
|
2167
|
+
let graphQLImperative;
|
|
2168
|
+
const adapterMetadata = {
|
|
2169
|
+
apiFamily: namespace,
|
|
2170
|
+
name: adapterName,
|
|
2171
|
+
};
|
|
2172
|
+
withDefaultLuvio((luvio) => {
|
|
2173
|
+
const ldsAdapter = createLDSAdapter(luvio, namespace, graphQLAdapterFactory);
|
|
2174
|
+
graphQL = createWireAdapterConstructor(luvio, createInstrumentedAdapter(ldsAdapter, adapterMetadata), adapterMetadata);
|
|
2175
|
+
unstable_graphQL_imperative = createImperativeAdapter(luvio, createInstrumentedAdapter(ldsAdapter, adapterMetadata), adapterMetadata);
|
|
2176
|
+
graphQLImperative = ldsAdapter;
|
|
2177
2177
|
});
|
|
2178
2178
|
|
|
2179
2179
|
export { graphQL, graphQLImperative, unstable_graphQL_imperative };
|
|
2180
|
-
// version: 1.124.
|
|
2180
|
+
// version: 1.124.3-c058f7d96
|