@apollo/client
Version:
A fully-featured caching GraphQL client.
94 lines (93 loc) • 4.93 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.equalByQuery = equalByQuery;
const equality_1 = require("@wry/equality");
const createFragmentMap_js_1 = require("./createFragmentMap.cjs");
const getFragmentDefinitions_js_1 = require("./getFragmentDefinitions.cjs");
const getFragmentFromSelection_js_1 = require("./getFragmentFromSelection.cjs");
const getMainDefinition_js_1 = require("./getMainDefinition.cjs");
const isField_js_1 = require("./isField.cjs");
const resultKeyNameFromField_js_1 = require("./resultKeyNameFromField.cjs");
const shouldInclude_js_1 = require("./shouldInclude.cjs");
// Returns true if aResult and bResult are deeply equal according to the fields
// selected by the given query, ignoring any fields marked as @nonreactive.
function equalByQuery(query, { data: aData, ...aRest }, { data: bData, ...bRest }, variables) {
return ((0, equality_1.equal)(aRest, bRest) &&
equalBySelectionSet((0, getMainDefinition_js_1.getMainDefinition)(query).selectionSet, aData, bData, {
fragmentMap: (0, createFragmentMap_js_1.createFragmentMap)((0, getFragmentDefinitions_js_1.getFragmentDefinitions)(query)),
variables,
}));
}
function equalBySelectionSet(selectionSet, aResult, bResult, context) {
if (aResult === bResult) {
return true;
}
const seenSelections = new Set();
// Returning true from this Array.prototype.every callback function skips the
// current field/subtree. Returning false aborts the entire traversal
// immediately, causing equalBySelectionSet to return false.
return selectionSet.selections.every((selection) => {
// Avoid re-processing the same selection at the same level of recursion, in
// case the same field gets included via multiple indirect fragment spreads.
if (seenSelections.has(selection))
return true;
seenSelections.add(selection);
// Ignore @skip(if: true) and @include(if: false) fields.
if (!(0, shouldInclude_js_1.shouldInclude)(selection, context.variables))
return true;
// If the field or (named) fragment spread has a @nonreactive directive on
// it, we don't care if it's different, so we pretend it's the same.
if (selectionHasNonreactiveDirective(selection))
return true;
if ((0, isField_js_1.isField)(selection)) {
const resultKey = (0, resultKeyNameFromField_js_1.resultKeyNameFromField)(selection);
const aResultChild = aResult && aResult[resultKey];
const bResultChild = bResult && bResult[resultKey];
const childSelectionSet = selection.selectionSet;
if (!childSelectionSet) {
// These are scalar values, so we can compare them with deep equal
// without redoing the main recursive work.
return (0, equality_1.equal)(aResultChild, bResultChild);
}
const aChildIsArray = Array.isArray(aResultChild);
const bChildIsArray = Array.isArray(bResultChild);
if (aChildIsArray !== bChildIsArray)
return false;
if (aChildIsArray && bChildIsArray) {
const length = aResultChild.length;
if (bResultChild.length !== length) {
return false;
}
for (let i = 0; i < length; ++i) {
if (!equalBySelectionSet(childSelectionSet, aResultChild[i], bResultChild[i], context)) {
return false;
}
}
return true;
}
return equalBySelectionSet(childSelectionSet, aResultChild, bResultChild, context);
}
else {
const fragment = (0, getFragmentFromSelection_js_1.getFragmentFromSelection)(selection, context.fragmentMap);
if (fragment) {
// The fragment might === selection if it's an inline fragment, but
// could be !== if it's a named fragment ...spread.
if (selectionHasNonreactiveDirective(fragment))
return true;
return equalBySelectionSet(fragment.selectionSet,
// Notice that we reuse the same aResult and bResult values here,
// since the fragment ...spread does not specify a field name, but
// consists of multiple fields (within the fragment's selection set)
// that should be applied to the current result value(s).
aResult, bResult, context);
}
}
});
}
function selectionHasNonreactiveDirective(selection) {
return (!!selection.directives && selection.directives.some(directiveIsNonreactive));
}
function directiveIsNonreactive(dir) {
return dir.name.value === "nonreactive";
}
//# sourceMappingURL=equalByQuery.cjs.map