apollo-client
Version:
A simple yet functional GraphQL client.
158 lines • 6.36 kB
JavaScript
var __assign = (this && this.__assign) || Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
import graphqlAnywhere from 'graphql-anywhere';
import { isJsonValue, isIdValue, } from './storeUtils';
import { storeKeyNameFromFieldNameAndArgs, } from './storeUtils';
import { getQueryDefinition, } from '../queries/getFromAST';
import { isEqual, } from '../util/isEqual';
import { isTest, } from '../util/environment';
export var ID_KEY = typeof Symbol !== 'undefined' ? Symbol('id') : '@@id';
export function readQueryFromStore(options) {
var optsPatch = {
returnPartialData: ((options.returnPartialData !== undefined) ? options.returnPartialData : false),
};
return diffQueryAgainstStore(__assign({}, options, optsPatch)).result;
}
var haveWarned = false;
var fragmentMatcher = function (idValue, typeCondition, context) {
assertIdValue(idValue);
var obj = context.store[idValue.id];
if (!obj) {
return false;
}
if (!obj.__typename) {
if (!haveWarned) {
console.warn("You're using fragments in your queries, but don't have the addTypename:\ntrue option set in Apollo Client. Please turn on that option so that we can accurately\nmatch fragments.");
if (!isTest()) {
haveWarned = true;
}
}
context.returnPartialData = true;
return true;
}
if (obj.__typename === typeCondition) {
return true;
}
context.returnPartialData = true;
return true;
};
var readStoreResolver = function (fieldName, idValue, args, context, _a) {
var resultKey = _a.resultKey;
assertIdValue(idValue);
var objId = idValue.id;
var obj = context.store[objId];
var storeKeyName = storeKeyNameFromFieldNameAndArgs(fieldName, args);
var fieldValue = (obj || {})[storeKeyName];
if (typeof fieldValue === 'undefined') {
if (context.customResolvers && obj && (obj.__typename || objId === 'ROOT_QUERY')) {
var typename = obj.__typename || 'Query';
var type = context.customResolvers[typename];
if (type) {
var resolver = type[fieldName];
if (resolver) {
return resolver(obj, args);
}
}
}
if (!context.returnPartialData) {
throw new Error("Can't find field " + storeKeyName + " on object (" + objId + ") " + JSON.stringify(obj, null, 2) + ".\nPerhaps you want to use the `returnPartialData` option?");
}
context.hasMissingField = true;
return fieldValue;
}
if (isJsonValue(fieldValue)) {
if (idValue.previousResult && isEqual(idValue.previousResult[resultKey], fieldValue.json)) {
return idValue.previousResult[resultKey];
}
return fieldValue.json;
}
if (idValue.previousResult) {
fieldValue = addPreviousResultToIdValues(fieldValue, idValue.previousResult[resultKey]);
}
return fieldValue;
};
export function diffQueryAgainstStore(_a) {
var store = _a.store, query = _a.query, variables = _a.variables, _b = _a.returnPartialData, returnPartialData = _b === void 0 ? true : _b, previousResult = _a.previousResult, config = _a.config;
getQueryDefinition(query);
var context = {
store: store,
returnPartialData: returnPartialData,
customResolvers: (config && config.customResolvers) || {},
hasMissingField: false,
};
var rootIdValue = {
type: 'id',
id: 'ROOT_QUERY',
previousResult: previousResult,
};
var result = graphqlAnywhere(readStoreResolver, query, rootIdValue, context, variables, {
fragmentMatcher: fragmentMatcher,
resultMapper: resultMapper,
});
return {
result: result,
isMissing: context.hasMissingField,
};
}
function assertIdValue(idValue) {
if (!isIdValue(idValue)) {
throw new Error("Encountered a sub-selection on the query, but the store doesn't have an object reference. This should never happen during normal use unless you have custom code that is directly manipulating the store; please file an issue.");
}
}
function addPreviousResultToIdValues(value, previousResult) {
if (isIdValue(value)) {
return __assign({}, value, { previousResult: previousResult });
}
else if (Array.isArray(value)) {
var idToPreviousResult_1 = {};
if (Array.isArray(previousResult)) {
previousResult.forEach(function (item) {
if (item[ID_KEY]) {
idToPreviousResult_1[item[ID_KEY]] = item;
}
});
}
return value.map(function (item, i) {
var itemPreviousResult = previousResult && previousResult[i];
if (isIdValue(item)) {
itemPreviousResult = idToPreviousResult_1[item.id] || itemPreviousResult;
}
return addPreviousResultToIdValues(item, itemPreviousResult);
});
}
return value;
}
function resultMapper(resultFields, idValue) {
if (idValue.previousResult) {
var currentResultKeys_1 = Object.keys(resultFields);
var sameAsPreviousResult = Object.keys(idValue.previousResult)
.reduce(function (sameKeys, key) { return sameKeys && currentResultKeys_1.indexOf(key) > -1; }, true) &&
currentResultKeys_1.reduce(function (same, key) { return (same && areNestedArrayItemsStrictlyEqual(resultFields[key], idValue.previousResult[key])); }, true);
if (sameAsPreviousResult) {
return idValue.previousResult;
}
}
Object.defineProperty(resultFields, ID_KEY, {
enumerable: false,
configurable: false,
writable: false,
value: idValue.id,
});
return resultFields;
}
function areNestedArrayItemsStrictlyEqual(a, b) {
if (a === b) {
return true;
}
if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) {
return false;
}
return a.reduce(function (same, item, i) { return same && areNestedArrayItemsStrictlyEqual(item, b[i]); }, true);
}
//# sourceMappingURL=readFromStore.js.map