Files
30-seconds-of-code/node_modules/relay-runtime/lib/RelayModernSelector.js
2019-08-20 15:52:05 +02:00

292 lines
11 KiB
JavaScript

/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
* @format
*/
'use strict';
/**
* @public
*
* Given the result `item` from a parent that fetched `fragment`, creates a
* selector that can be used to read the results of that fragment for that item.
*
* Example:
*
* Given two fragments as follows:
*
* ```
* fragment Parent on User {
* id
* ...Child
* }
* fragment Child on User {
* name
* }
* ```
*
* And given some object `parent` that is the results of `Parent` for id "4",
* the results of `Child` can be accessed by first getting a selector and then
* using that selector to `lookup()` the results against the environment:
*
* ```
* const childSelector = getSelector(queryVariables, Child, parent);
* const childData = environment.lookup(childSelector).data;
* ```
*/
function getSelector(operationVariables, fragment, item) {
!(typeof item === 'object' && item !== null && !Array.isArray(item)) ? process.env.NODE_ENV !== "production" ? require("fbjs/lib/invariant")(false, 'RelayModernSelector: Expected value for fragment `%s` to be an object, got ' + '`%s`.', fragment.name, JSON.stringify(item)) : require("fbjs/lib/invariant")(false) : void 0;
var dataID = item[require("./RelayStoreUtils").ID_KEY];
var fragments = item[require("./RelayStoreUtils").FRAGMENTS_KEY];
var owner = item[require("./RelayStoreUtils").FRAGMENT_OWNER_KEY];
if (typeof dataID === 'string' && typeof fragments === 'object' && fragments !== null && typeof fragments[fragment.name] === 'object' && fragments[fragment.name] !== null) {
var argumentVariables = fragments[fragment.name];
if (owner != null && typeof owner === 'object') {
// $FlowFixMe - TODO T39154660
var typedOwner = owner;
var ownerOperationVariables = typedOwner.variables;
var _fragmentVariables = require("./RelayConcreteVariables").getFragmentVariables(fragment, ownerOperationVariables, argumentVariables);
return {
owner: typedOwner,
selector: {
dataID: dataID,
node: fragment,
variables: _fragmentVariables
}
};
}
var fragmentVariables = require("./RelayConcreteVariables").getFragmentVariables(fragment, operationVariables, argumentVariables);
return {
owner: null,
selector: {
dataID: dataID,
node: fragment,
variables: fragmentVariables
}
};
}
process.env.NODE_ENV !== "production" ? require("fbjs/lib/warning")(false, 'RelayModernSelector: Expected object to contain data for fragment `%s`, got ' + '`%s`. Make sure that the parent operation/fragment included fragment ' + '`...%s` without `@relay(mask: false)`.', fragment.name, JSON.stringify(item), fragment.name) : void 0;
return null;
}
/**
* @public
*
* Given the result `items` from a parent that fetched `fragment`, creates a
* selector that can be used to read the results of that fragment on those
* items. This is similar to `getSelector` but for "plural" fragments that
* expect an array of results and therefore return an array of selectors.
*/
function getSelectorList(operationVariables, fragment, items) {
var selectors = null;
items.forEach(function (item) {
var selector = item != null ? getSelector(operationVariables, fragment, item) : null;
if (selector != null) {
selectors = selectors || [];
selectors.push(selector);
}
});
return selectors;
}
/**
* @public
*
* Given a mapping of keys -> results and a mapping of keys -> fragments,
* extracts the selectors for those fragments from the results.
*
* The canonical use-case for this function is ReactRelayFragmentContainer, which
* uses this function to convert (props, fragments) into selectors so that it
* can read the results to pass to the inner component.
*/
function getSelectorsFromObject(operationVariables, fragments, object) {
var selectors = {};
for (var _key in fragments) {
if (fragments.hasOwnProperty(_key)) {
var fragment = fragments[_key];
var item = object[_key];
if (item == null) {
selectors[_key] = item;
} else if (fragment.metadata && fragment.metadata.plural === true) {
!Array.isArray(item) ? process.env.NODE_ENV !== "production" ? require("fbjs/lib/invariant")(false, 'RelayModernSelector: Expected value for key `%s` to be an array, got `%s`. ' + 'Remove `@relay(plural: true)` from fragment `%s` to allow the prop to be an object.', _key, JSON.stringify(item), fragment.name) : require("fbjs/lib/invariant")(false) : void 0;
selectors[_key] = getSelectorList(operationVariables, fragment, item);
} else {
!!Array.isArray(item) ? process.env.NODE_ENV !== "production" ? require("fbjs/lib/invariant")(false, 'RelayModernFragmentSpecResolver: Expected value for key `%s` to be an object, got `%s`. ' + 'Add `@relay(plural: true)` to fragment `%s` to allow the prop to be an array of items.', _key, JSON.stringify(item), fragment.name) : require("fbjs/lib/invariant")(false) : void 0;
selectors[_key] = getSelector(operationVariables, fragment, item);
}
}
}
return selectors;
}
/**
* @public
*
* Given a mapping of keys -> results and a mapping of keys -> fragments,
* extracts a mapping of keys -> id(s) of the results.
*
* Similar to `getSelectorsFromObject()`, this function can be useful in
* determining the "identity" of the props passed to a component.
*/
function getDataIDsFromObject(fragments, object) {
var ids = {};
for (var _key2 in fragments) {
if (fragments.hasOwnProperty(_key2)) {
var fragment = fragments[_key2];
var item = object[_key2];
if (item == null) {
ids[_key2] = item;
} else if (fragment.metadata && fragment.metadata.plural === true) {
!Array.isArray(item) ? process.env.NODE_ENV !== "production" ? require("fbjs/lib/invariant")(false, 'RelayModernSelector: Expected value for key `%s` to be an array, got `%s`. ' + 'Remove `@relay(plural: true)` from fragment `%s` to allow the prop to be an object.', _key2, JSON.stringify(item), fragment.name) : require("fbjs/lib/invariant")(false) : void 0;
ids[_key2] = getDataIDs(fragment, item);
} else {
!!Array.isArray(item) ? process.env.NODE_ENV !== "production" ? require("fbjs/lib/invariant")(false, 'RelayModernFragmentSpecResolver: Expected value for key `%s` to be an object, got `%s`. ' + 'Add `@relay(plural: true)` to fragment `%s` to allow the prop to be an array of items.', _key2, JSON.stringify(item), fragment.name) : require("fbjs/lib/invariant")(false) : void 0;
ids[_key2] = getDataID(fragment, item);
}
}
}
return ids;
}
/**
* @internal
*/
function getDataIDs(fragment, items) {
var ids;
items.forEach(function (item) {
var id = item != null ? getDataID(fragment, item) : null;
if (id != null) {
ids = ids || [];
ids.push(id);
}
});
return ids || null;
}
/**
* @internal
*/
function getDataID(fragment, item) {
!(typeof item === 'object' && item !== null && !Array.isArray(item)) ? process.env.NODE_ENV !== "production" ? require("fbjs/lib/invariant")(false, 'RelayModernSelector: Expected value for fragment `%s` to be an object, got ' + '`%s`.', fragment.name, JSON.stringify(item)) : require("fbjs/lib/invariant")(false) : void 0;
var dataID = item[require("./RelayStoreUtils").ID_KEY];
if (typeof dataID === 'string') {
return dataID;
}
process.env.NODE_ENV !== "production" ? require("fbjs/lib/warning")(false, 'RelayModernSelector: Expected object to contain data for fragment `%s`, got ' + '`%s`. Make sure that the parent operation/fragment included fragment ' + '`...%s` without `@relay(mask: false)`.', fragment.name, JSON.stringify(item), fragment.name) : void 0;
return null;
}
/**
* @public
*
* Given a mapping of keys -> results and a mapping of keys -> fragments,
* extracts the merged variables that would be in scope for those
* fragments/results.
*
* This can be useful in determing what varaibles were used to fetch the data
* for a Relay container, for example.
*/
function getVariablesFromObject(operationVariables, fragments, object) {
var variables = {};
for (var _key3 in fragments) {
if (fragments.hasOwnProperty(_key3)) {
var _ret = function () {
var fragment = fragments[_key3];
var item = object[_key3];
if (item == null) {
return "continue";
} else if (fragment.metadata && fragment.metadata.plural === true) {
!Array.isArray(item) ? process.env.NODE_ENV !== "production" ? require("fbjs/lib/invariant")(false, 'RelayModernSelector: Expected value for key `%s` to be an array, got `%s`. ' + 'Remove `@relay(plural: true)` from fragment `%s` to allow the prop to be an object.', _key3, JSON.stringify(item), fragment.name) : require("fbjs/lib/invariant")(false) : void 0;
item.forEach(function (value) {
if (value != null) {
var itemVariables = getVariables(operationVariables, fragment, value);
if (itemVariables) {
Object.assign(variables, itemVariables);
}
}
});
} else {
!!Array.isArray(item) ? process.env.NODE_ENV !== "production" ? require("fbjs/lib/invariant")(false, 'RelayModernFragmentSpecResolver: Expected value for key `%s` to be an object, got `%s`. ' + 'Add `@relay(plural: true)` to fragment `%s` to allow the prop to be an array of items.', _key3, JSON.stringify(item), fragment.name) : require("fbjs/lib/invariant")(false) : void 0;
var itemVariables = getVariables(operationVariables, fragment, item);
if (itemVariables) {
Object.assign(variables, itemVariables);
}
}
}();
if (_ret === "continue") continue;
}
}
return variables;
}
/**
* @internal
*/
function getVariables(operationVariables, fragment, item) {
var ownedSelector = getSelector(operationVariables, fragment, item);
if (!ownedSelector) {
return null;
}
return ownedSelector.selector.variables;
}
/**
* @public
*
* Determine if two selectors are equal (represent the same selection). Note
* that this function returns `false` when the two queries/fragments are
* different objects, even if they select the same fields.
*/
function areEqualSelectors(thisSelector, thatSelector) {
return thisSelector.selector.dataID === thatSelector.selector.dataID && thisSelector.selector.node === thatSelector.selector.node && require("fbjs/lib/areEqual")(thisSelector.selector.variables, thatSelector.selector.variables);
}
module.exports = {
areEqualSelectors: areEqualSelectors,
getDataIDsFromObject: getDataIDsFromObject,
getSelector: getSelector,
getSelectorList: getSelectorList,
getSelectorsFromObject: getSelectorsFromObject,
getVariablesFromObject: getVariablesFromObject
};