apollo-progressive-fragment-matcher
Version:
A smart alternative to the introspection fragment matcher.
202 lines (161 loc) • 7.46 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ProgressiveFragmentMatcher = void 0;
var _apolloLink = require("apollo-link");
var _invariant = _interopRequireDefault(require("invariant"));
var _transform = require("./transform");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
var defaultOptions = {
strategy: 'introspection' // 'introspection' | 'extension'
};
var strategies = {
/**
* Uses GraphQL extensions to share possibleTypes from server to client.
*
* Upsides: fast.
* Downsides: requires server contol (add extension).
*/
extension: {
link: function link() {
var _this = this;
return new _apolloLink.ApolloLink(function (operation, forward) {
// enable possible types fetching.
operation.extensions.possibleTypes = true;
return forward(operation).map(function (result) {
if (result.extensions && result.extensions.possibleTypes) {
var types = result.extensions.possibleTypes;
for (var type in types) {
if (types.hasOwnProperty(type) && !_this.possibleTypesMap[type]) {
_this.possibleTypesMap[type] = types[type];
}
}
}
return result;
});
});
}
},
/**
* Alters operations to send small and specific introespection requests.
*
* Upsides: easy to use.
* Downsides: query manipulation (might be slow).
*/
introspection: {
link: function link() {
var _this2 = this;
return new _apolloLink.ApolloLink(function (operation, forward) {
var originalQuery = operation.query;
var _addTypeIntrospection = (0, _transform.addTypeIntrospections)(originalQuery, {
possibleTypes: _this2.possibleTypesMap
}),
types = _addTypeIntrospection.types,
query = _addTypeIntrospection.query;
operation.query = query; // enable possible types fetching.
return forward(operation).map(function (result) {
operation.query = originalQuery;
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = types[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var type = _step.value;
var alias = "__".concat(type, "__");
if (!_this2.possibleTypesMap[type]) {
_this2.possibleTypesMap[type] = [];
}
if (result.data[alias] && result.data[alias].possibleTypes) {
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = result.data[alias].possibleTypes[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var name = _step2.value.name;
_this2.possibleTypesMap[name] = _this2.possibleTypesMap[name] || [];
if (!_this2.possibleTypesMap[name].includes(type)) {
_this2.possibleTypesMap[name].push(type);
}
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
}
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return != null) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
return result;
});
});
}
}
};
var ProgressiveFragmentMatcher =
/*#__PURE__*/
function () {
function ProgressiveFragmentMatcher(options) {
_classCallCheck(this, ProgressiveFragmentMatcher);
var _defaultOptions$optio = _objectSpread({}, defaultOptions, options),
name = _defaultOptions$optio.strategy;
if (!strategies[name]) {
var strategyNames = Object.keys(strategies).map(function (name) {
return "\"".concat(name, "\"");
}).join(', ');
throw new Error("ProgressiveFragmentMatcher: unknown strategy \"".concat(name, "\" (must be one of ").concat(strategyNames, ")."));
}
var strategy = strategies[name]; // initiate type map.
this.possibleTypesMap = {};
this.match = this.match.bind(this); // set strategy based methods.
this.link = strategy.link.bind(this);
}
_createClass(ProgressiveFragmentMatcher, [{
key: "match",
value: function match(idValue, typeCondition, context) {
var obj = context.store.get(idValue.id);
if (!obj) {
// https://github.com/apollographql/apollo-client/pull/4620
return idValue.id === 'ROOT_QUERY';
}
(0, _invariant.default)(obj.__typename, "Cannot match fragment because __typename property is missing: ".concat(JSON.stringify(obj)));
if (obj.__typename === typeCondition) {
return true;
}
var possibleTypes = this.possibleTypesMap[obj.__typename];
if (possibleTypes && possibleTypes.indexOf(typeCondition) > -1) {
return true;
}
return false;
}
}]);
return ProgressiveFragmentMatcher;
}();
exports.ProgressiveFragmentMatcher = ProgressiveFragmentMatcher;