react-redux-provide
Version:
Build your UI with React. Manage application state with Redux providers. Persist and share application state with replication. Use pure functions everywhere.
1,351 lines (1,117 loc) • 39.3 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
exports.default = instantiateProvider;
exports.getTempFauxInstance = getTempFauxInstance;
exports.getFromContextOrProps = getFromContextOrProps;
exports.getProviders = getProviders;
exports.getProviderInstances = getProviderInstances;
exports.getActiveQueries = getActiveQueries;
exports.getQueryResults = getQueryResults;
exports.getPartialStates = getPartialStates;
exports.getFunctionOrObject = getFunctionOrObject;
exports.getQueries = getQueries;
exports.getQuery = getQuery;
exports.getQueryOptions = getQueryOptions;
exports.getQueriesOptions = getQueriesOptions;
exports.getQueryHandlers = getQueryHandlers;
exports.getMergedResult = getMergedResult;
exports.resultsEqual = resultsEqual;
exports.handleQueries = handleQueries;
var _shallowEqual = require('./shallowEqual');
var _shallowEqual2 = _interopRequireDefault(_shallowEqual);
var _getRelevantKeys = require('./getRelevantKeys');
var _getRelevantKeys2 = _interopRequireDefault(_getRelevantKeys);
var _createProviderStore = require('./createProviderStore');
var _createProviderStore2 = _interopRequireDefault(_createProviderStore);
var _keyConcats = require('./keyConcats');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
var isServerSide = typeof window === 'undefined';
var isTesting = typeof process !== 'undefined' && process.env && process.env.NODE_ENV === 'test';
var globalProviderInstances = {};
// TODO: we'll use this at some point to select only component propTypes
/*
function hasReducerKeys(providerInstance, getReducerKeys) {
if (!getReducerKeys) {
return true;
}
const { hasReducerKeys = {} } = providerInstance;
for (let reducerKey in getReducerKeys) {
if (!hasReducerKeys[reducerKey]) {
providerInstance.hasReducerKeys = {
...hasReducerKeys,
...getReducerKeys
};
return false;
}
}
return true;
}*/
/**
* Instantiates a provider with its own store.
*
* @param {Object} fauxInstance resembles { props, context }
* @param {Object} provider
* @param {String|Function} providerKey Optional
* @param {Function} readyCallback Optional
* @param {Object} createState Optional
* @param {Object} getReducerKeys Optional
* @param {Boolean} useCreator Optional
* @return {Object}
* @api public
*/
function instantiateProvider(fauxInstance, provider, providerKey, readyCallback, createState, getReducerKeys, useCreator // TODO: clean this up
) {
if (arguments.length === 1) {
fauxInstance = arguments[0].fauxInstance;
provider = arguments[0].provider;
providerKey = arguments[0].providerKey;
readyCallback = arguments[0].readyCallback;
createState = arguments[0].createState;
getReducerKeys = arguments[0].getReducerKeys;
useCreator = arguments[0].useCreator;
if (!fauxInstance) {
provider = arguments[0];
fauxInstance = {};
}
}
if (!fauxInstance.props) {
fauxInstance.props = {};
}
if (typeof providerKey === 'undefined') {
providerKey = provider.key;
}
if (!provider.actions) {
provider.actions = {};
}
if (!provider.reducers) {
provider.reducers = {};
}
if (getReducerKeys === true) {
getReducerKeys = provider.reducers;
}
var providers = getProviders(fauxInstance);
var providerInstances = getProviderInstances(fauxInstance);
var providerInstance = void 0;
var isStatic = typeof providerKey !== 'function';
var storeKey = void 0;
var creator = void 0;
if (typeof provider.key === 'string') {
if (!providers[provider.key]) {
providers[provider.key] = provider;
}
} else if (provider.defaultKey) {
if (!providers[provider.defaultKey]) {
providers[provider.defaultKey] = provider;
}
} else if (!provider.key || !provider.key.toString) {
console.warn('Missing or invalid provider key!');
} else if (!providers[provider.key.toString()]) {
providers[provider.key.toString()] = provider;
}
if (!isStatic) {
// get actual `providerKey`
providerKey = providerKey(fauxInstance);
// if actual `providerKey` matches `key`, treat as static provider
isStatic = providerKey === provider.key;
}
if (providerKey === null) {
storeKey = null;
providerKey = provider.defaultKey;
isStatic = true;
}
providerInstance = provider.isGlobal ? globalProviderInstances[providerKey] : providerInstances && providerInstances[providerKey];
if (fauxInstance.relevantProviders) {
fauxInstance.relevantProviders[providerKey] = true;
}
if (createState && (typeof createState === 'undefined' ? 'undefined' : _typeof(createState)) === 'object' && provider.state && _typeof(provider.state) === 'object') {
createState = _extends({}, provider.state, createState);
}
// TODO: we'll use this at some point
//if (providerInstance && hasReducerKeys(providerInstance, getReducerKeys)) {
if (providerInstance) {
if (createState) {
if (useCreator) {
// TODO: clean this up
creator = providerInstance;
} else {
providerInstances[providerKey] = providerInstance;
providerInstance.store.setState(createState, false, true);
if (readyCallback) {
if (providerInstance.ready) {
readyCallback(providerInstance);
} else {
(0, _keyConcats.pushOnReady)({ providerInstance: providerInstance }, readyCallback);
}
}
return providerInstance;
}
} else {
providerInstances[providerKey] = providerInstance;
if (readyCallback) {
if (providerInstance.ready) {
readyCallback(providerInstance);
} else {
(0, _keyConcats.pushOnReady)({ providerInstance: providerInstance }, readyCallback);
}
}
return providerInstance;
}
}
if (!provider.hasThunk) {
var findProvider = function findProvider(props) {
if ((0, _getRelevantKeys2.default)(provider.reducers, props).length) {
return provider;
}
for (var key in providers) {
if ((0, _getRelevantKeys2.default)(providers[key].reducers, props).length) {
return providers[key];
}
}
return provider;
};
var getResultInstances = function getResultInstances(result, callback) {
var resultInstances = [];
var semaphore = result && result.length;
function clear() {
if (--semaphore === 0) {
callback(resultInstances);
}
}
if (!semaphore) {
semaphore = 1;
clear();
return;
}
result.forEach(function (resultProps, index) {
resultInstances[index] = null;
instantiateProvider({
fauxInstance: getTempFauxInstance(fauxInstance, resultProps),
provider: findProvider(resultProps),
readyCallback: function readyCallback(resultInstance) {
resultInstances[index] = resultInstance;
clear();
}
});
});
};
var getInstance = function getInstance(props, callback, create, useCreator) {
var provider = void 0;
var providerKey = void 0;
if (typeof props === 'string') {
// key is already known
if (providerInstances[props]) {
providerKey = props;
}
provider = providers[props] || providerInstances[props];
props = {};
} else {
provider = findProvider(props);
}
return instantiateProvider({
fauxInstance: getTempFauxInstance(fauxInstance, props),
provider: provider,
providerKey: providerKey,
readyCallback: callback,
createState: create ? props : null,
useCreator: useCreator
});
};
var getInstances = function getInstances(propsArray, callback, create, useCreator) {
var instances = [];
var getCount = propsArray.length;
var clear = function clear() {
if (--getCount === 0) {
if (callback) {
callback(instances);
}
}
};
propsArray.forEach(function (props, index) {
getInstance(props, function (instance) {
instances[index] = instance;
clear();
}, create);
});
return instances;
};
var createInstance = function createInstance(props, callback, useCreator) {
return getInstance(props, callback, true, useCreator);
};
var createInstances = function createInstances(propsArray, callback, useCreator) {
return getInstances(propsArray, callback, true, useCreator);
};
var setStates = function setStates(states) {
var gettingInstances = [];
var settingStates = [];
var clientStates = null;
if (!isServerSide) {
if (!window.clientStates) {
window.clientStates = {};
}
clientStates = window.clientStates;
}
var _loop = function _loop(_providerKey) {
var state = states[_providerKey];
var providerInstance = providerInstances[_providerKey];
if (providerInstance) {
if (providerInstance.store.setState) {
settingStates.push(function () {
return providerInstance.store.setState(state);
});
}
} else {
if (clientStates) {
clientStates[_providerKey] = state;
}
gettingInstances.push(state);
}
};
for (var _providerKey in states) {
_loop(_providerKey);
}
// now that `clientStates` are cached...
while (gettingInstances.length) {
getInstance(gettingInstances.shift());
}
while (settingStates.length) {
settingStates.shift()();
}
};
var find = function find(props, doInstantiate, callback) {
if (arguments.length === 2) {
callback = doInstantiate;
doInstantiate = false;
}
handleQueries(getTempFauxInstance(fauxInstance, props), function () {
if (!doInstantiate) {
callback(props.query ? props.result : props.results);
return;
}
if (props.query) {
getResultInstances(props.result, callback);
return;
}
var results = props.results;
var resultsInstances = {};
var resultsKeys = results && Object.keys(results);
var semaphore = resultsKeys && resultsKeys.length;
function clear() {
if (--semaphore === 0) {
callback(resultsInstances);
}
}
if (!semaphore) {
semaphore = 1;
clear();
}
resultsKeys.forEach(function (resultKey) {
resultsInstances[resultKey] = [];
getResultInstances(results[resultKey], function (resultInstances) {
resultsInstances[resultKey] = resultInstances;
clear();
});
});
});
};
provider.hasThunk = true;
if (provider.wait && !Array.isArray(provider.wait)) {
provider.wait = [provider.wait];
}
if (provider.clear && !Array.isArray(provider.clear)) {
provider.clear = [provider.clear];
}
var providerApi = {
getInstance: getInstance,
getInstances: getInstances,
createInstance: createInstance,
createInstances: createInstances,
setStates: setStates,
find: find
};
(0, _keyConcats.unshiftMiddleware)({ provider: provider }, function (_ref) {
var dispatch = _ref.dispatch,
getState = _ref.getState;
return function (next) {
return function (action) {
if (typeof action !== 'function') {
return next(action);
}
if (provider.wait) {
provider.wait.forEach(function (fn) {
return fn();
});
}
return action(function (action) {
var state = store.getState();
var storeChanged = false;
dispatch(action);
if (provider.clear) {
storeChanged = state !== store.getState();
provider.clear.forEach(function (fn) {
return fn(storeChanged);
});
}
}, getState, providerApi);
};
};
});
}
if (provider.wait) {
provider.wait.forEach(function (fn) {
return fn();
});
}
providerInstance = Object.create(provider);
providerInstance.providerKey = providerKey;
providerInstance.isStatic = isStatic;
var store = (0, _createProviderStore2.default)(providerInstance, storeKey, createState, createState ? function (state) {
var _providerInstance = providerInstance,
onReady = _providerInstance.onReady;
providerInstance = instantiateProvider({
fauxInstance: getTempFauxInstance(fauxInstance, state),
provider: provider,
readyCallback: function readyCallback(createdInstance) {
if (Array.isArray(onReady)) {
onReady.forEach(function (fn) {
return fn(createdInstance);
});
} else if (onReady) {
onReady(createdInstance);
}
}
});
} : null,
// TODO: we need a better way to create + replicate
creator && creator.store);
var initialState = store.getState();
var _providerInstance2 = providerInstance,
actions = _providerInstance2.actions;
var actionCreators = {};
var setKey = store.setKey;
if (setKey) {
store.setKey = function (newKey, readyCallback) {
if (provider.wait) {
provider.wait.forEach(function (fn) {
return fn();
});
}
setKey(newKey, function () {
if (Array.isArray(providerInstance.onReady)) {
providerInstance.onReady.forEach(function (fn) {
return fn(providerInstance);
});
} else if (providerInstance.onReady) {
providerInstance.onReady(providerInstance);
}
if (readyCallback) {
readyCallback();
}
if (provider.clear) {
provider.clear.forEach(function (fn) {
return fn(true);
});
}
});
};
}
var _loop2 = function _loop2(actionKey) {
actionCreators[actionKey] = function () {
return store.dispatch(actions[actionKey].apply(this, arguments));
};
};
for (var actionKey in actions) {
_loop2(actionKey);
}
providerInstance.store = store;
providerInstance.actionCreators = actionCreators;
if (!createState) {
if (provider.isGlobal) {
globalProviderInstances[providerKey] = providerInstance;
}
if (providerInstances) {
providerInstances[providerKey] = providerInstance;
}
if (!provider.instances) {
provider.instances = [];
}
provider.instances.push(providerInstance);
}
if (provider.subscribers) {
Object.keys(provider.subscribers).forEach(function (key) {
var handler = provider.subscribers[key];
var subProvider = providers[key];
var subKey = provider.defaultKey || (typeof provider.key === 'function' ? provider.key({}) : String(provider.key));
var callHandler = function callHandler() {
var subProviderInstances = subProvider && subProvider.instances;
if (subProviderInstances) {
subProviderInstances.forEach(function (subProviderInstance) {
handler(providerInstance, subProviderInstance);
});
}
};
if (subProvider) {
if (!subProvider.subscribeTo) {
subProvider.subscribeTo = {};
}
if (!subProvider.subscribeTo[subKey]) {
subProvider.subscribeTo[subKey] = handler;
}
}
providerInstance.store.subscribe(callHandler);
callHandler();
});
}
if (provider.subscribeTo) {
Object.keys(provider.subscribeTo).forEach(function (key) {
var handler = provider.subscribeTo[key];
var supProvider = providers[key];
var supKey = provider.defaultKey || (typeof provider.key === 'function' ? provider.key({}) : String(provider.key));
if (!supProvider) {
return;
}
if (!supProvider.subscribers) {
supProvider.subscribers = {};
}
if (!supProvider.subscribers[supKey]) {
supProvider.subscribers[supKey] = handler;
if (supProvider.instances) {
supProvider.instances.forEach(function (supProviderInstance) {
supProviderInstance.store.subscribe(function () {
provider.instances.forEach(function (providerInstance) {
handler(supProviderInstance, providerInstance);
});
});
});
}
}
if (supProvider.instances) {
supProvider.instances.forEach(function (supProviderInstance) {
handler(supProviderInstance, providerInstance);
});
}
});
}
if (!createState) {
if (Array.isArray(providerInstance.onInstantiated)) {
providerInstance.onInstantiated.forEach(function (fn) {
return fn(providerInstance);
});
} else if (providerInstance.onInstantiated) {
providerInstance.onInstantiated(providerInstance);
}
}
(0, _keyConcats.unshiftOnReady)({ providerInstance: providerInstance }, function () {
providerInstance.ready = true;
});
if (readyCallback) {
(0, _keyConcats.pushOnReady)({ providerInstance: providerInstance }, readyCallback);
}
function done() {
if (Array.isArray(providerInstance.onReady)) {
providerInstance.onReady.forEach(function (fn) {
return fn(providerInstance);
});
} else if (providerInstance.onReady) {
providerInstance.onReady(providerInstance);
}
if (provider.clear) {
var storeChanged = initialState !== providerInstance.store.getState();
provider.clear.forEach(function (fn) {
return fn(storeChanged);
});
}
}
if (provider.replication && store.onReady && !store.initializedReplication) {
store.onReady(done);
} else {
done();
}
return providerInstance;
}
function getContext(fauxInstance) {
if (!fauxInstance.context) {
fauxInstance.context = {};
}
return fauxInstance.context;
}
function getTempFauxInstance(fauxInstance, props) {
return {
props: props,
context: getContext(fauxInstance),
providers: getProviders(fauxInstance),
providerInstances: getProviderInstances(fauxInstance),
activeQueries: getActiveQueries(fauxInstance),
queryResults: getQueryResults(fauxInstance),
partialStates: getPartialStates(fauxInstance)
};
}
function getFromContextOrProps(fauxInstance, key, defaultValue) {
if (typeof fauxInstance[key] === 'undefined') {
var props = fauxInstance.props;
var context = getContext(fauxInstance);
if (typeof props[key] !== 'undefined') {
fauxInstance[key] = props[key];
} else if (typeof context[key] !== 'undefined') {
fauxInstance[key] = context[key];
} else {
fauxInstance[key] = defaultValue;
}
}
return fauxInstance[key];
}
function getProviders(fauxInstance) {
return getFromContextOrProps(fauxInstance, 'providers', {});
}
function getProviderInstances(fauxInstance) {
return getFromContextOrProps(fauxInstance, 'providerInstances', {});
}
function getActiveQueries(fauxInstance) {
return getFromContextOrProps(fauxInstance, 'activeQueries', {});
}
function getQueryResults(fauxInstance) {
return getFromContextOrProps(fauxInstance, 'queryResults', {});
}
function getPartialStates(fauxInstance) {
return getFromContextOrProps(fauxInstance, 'partialStates', {});
}
function getFunctionOrObject(fauxInstance, key) {
var defaultValue = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
if (typeof fauxInstance[key] !== 'undefined') {
return fauxInstance[key];
}
var value = fauxInstance.props[key];
if (typeof value === 'function') {
value = value(fauxInstance);
}
fauxInstance[key] = value || defaultValue;
return fauxInstance[key];
}
function getQueries(fauxInstance) {
if (getQueries.disabled) {
return false;
}
if (typeof fauxInstance.queries !== 'undefined') {
return fauxInstance.queries;
}
var props = fauxInstance.props,
relevantProviders = fauxInstance.relevantProviders;
var providers = getProviders(fauxInstance);
var query = getQuery(fauxInstance);
var queries = getFunctionOrObject(fauxInstance, 'queries');
var hasQueries = false;
if (query) {
// we need to map the query to relevant provider(s)
if (!queries) {
queries = {};
} else if (typeof props.queries !== 'function') {
queries = _extends({}, queries);
}
for (var key in providers) {
var provider = providers[key];
var queryKeys = (0, _getRelevantKeys2.default)(provider.reducers, query);
if (queryKeys.length) {
// provider is relevant, so we map it within the queries object
if (!queries[key]) {
queries[key] = {};
}
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = queryKeys[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var queryKey = _step.value;
queries[key][queryKey] = query[queryKey];
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
}
}
}
for (var _key in queries) {
var _query = queries[_key];
if (typeof _query === 'function') {
queries[_key] = _query(fauxInstance);
}
// make sure each provider is instantiated
instantiateProvider(fauxInstance, providers[_key]);
hasQueries = true;
}
if (!hasQueries) {
queries = null;
if (props.query) {
props.result = null;
}
if (props.queries) {
props.results = {};
}
}
fauxInstance.queries = queries;
return queries;
}
function getQuery(fauxInstance) {
return getFunctionOrObject(fauxInstance, 'query');
}
function getQueryOptions(fauxInstance) {
return getFunctionOrObject(fauxInstance, 'queryOptions');
}
function getQueriesOptions(fauxInstance) {
return getFunctionOrObject(fauxInstance, 'queriesOptions', {});
}
// gets all `handleQuery` functions within replicators
function getQueryHandlers(provider) {
var queryHandlers = [];
var replication = provider.replication;
if (replication) {
if (!Array.isArray(replication)) {
replication = [replication];
}
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = replication[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var _ref3 = _step2.value;
var replicator = _ref3.replicator,
reducerKeys = _ref3.reducerKeys,
baseQuery = _ref3.baseQuery,
baseQueryOptions = _ref3.baseQueryOptions;
if (replicator) {
if (!Array.isArray(replicator)) {
replicator = [replicator];
}
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
try {
for (var _iterator3 = replicator[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var _ref5 = _step3.value;
var handleQuery = _ref5.handleQuery;
if (handleQuery) {
queryHandlers.push({
handleQuery: handleQuery,
reducerKeys: reducerKeys || Object.keys(provider.reducers),
baseQuery: baseQuery,
baseQueryOptions: baseQueryOptions
});
}
}
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3.return) {
_iterator3.return();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
}
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
}
return queryHandlers;
}
function getMergedResult(mergedResult, result) {
if (Array.isArray(result)) {
return [].concat(_toConsumableArray(mergedResult || []), _toConsumableArray(result));
} else if (result && (typeof result === 'undefined' ? 'undefined' : _typeof(result)) === 'object' && result.constructor === Object) {
return _extends({}, mergedResult || {}, result);
} else if (typeof result !== 'undefined') {
return result;
} else {
return mergedResult;
}
}
function resultsEqual(result, previousResult) {
if (result === previousResult) {
return true;
}
if ((typeof result === 'undefined' ? 'undefined' : _typeof(result)) !== (typeof previousResult === 'undefined' ? 'undefined' : _typeof(previousResult))) {
return false;
}
if (Array.isArray(result)) {
if (Array.isArray(previousResult)) {
var i = 0;
var length = result.length;
if (length !== previousResult.length) {
return false;
}
while (i < length) {
if (!(0, _shallowEqual2.default)(result[i], previousResult[i])) {
return false;
}
i++;
}
} else {
return false;
}
} else if (Array.isArray(previousResult)) {
return false;
}
return (0, _shallowEqual2.default)(result, previousResult);
}
// this is admittedly a mess... :(
// we're accounting for both synchronous and asynchronous query handling
// where asynchronous results will override the synchronous results
function handleQueries(fauxInstance, callback, previousResults) {
var doUpdate = false;
var queries = getQueries(fauxInstance);
if (!queries) {
if (callback) {
callback(doUpdate);
}
return false;
}
var props = fauxInstance.props;
var context = getContext(fauxInstance);
var originalResult = props.result,
originalResults = props.results;
var validQuery = false;
// for determining whether or not we should update
if (!previousResults) {
previousResults = _extends({}, props.results);
}
// get what we need to handle the queries
var query = getQuery(fauxInstance);
var queryOptions = getQueryOptions(fauxInstance);
var queriesOptions = getQueriesOptions(fauxInstance);
var activeQueries = getActiveQueries(fauxInstance);
var queryResults = getQueryResults(fauxInstance);
var partialStates = getPartialStates(fauxInstance);
var providers = getProviders(fauxInstance);
var providerInstances = getProviderInstances(fauxInstance);
// TODO: we should probably do something better at some point
var setPartialStates = function setPartialStates(provider, result) {
if (!result || typeof result.map !== 'function' || !isServerSide) {
return;
}
var _iteratorNormalCompletion4 = true;
var _didIteratorError4 = false;
var _iteratorError4 = undefined;
try {
for (var _iterator4 = result[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
var partialState = _step4.value;
var providerKey = provider.key;
if (typeof providerKey === 'function') {
providerKey = providerKey({ props: partialState, context: context });
}
if (providerKey !== null && !providerInstances[providerKey]) {
partialStates[providerKey] = partialState;
}
}
} catch (err) {
_didIteratorError4 = true;
_iteratorError4 = err;
} finally {
try {
if (!_iteratorNormalCompletion4 && _iterator4.return) {
_iterator4.return();
}
} finally {
if (_didIteratorError4) {
throw _iteratorError4;
}
}
}
};
// most queries should be async
var queryCount = Object.keys(queries).length;
var queryClear = function queryClear() {
if (--queryCount === 0) {
// at this point we have all our results
if (callback) {
callback(doUpdate);
}
}
};
// merge each result into `props.result` if using `props.query`
var setMergedResult = function setMergedResult(result) {
if (props.query) {
props.result = getMergedResult(props.result, result);
}
};
// go ahead and set null value if using `props.query`
if (props.query) {
props.result = null;
}
// results start out as an empty object
props.results = {};
// check each query
Object.keys(queries).forEach(function (key) {
var provider = providers[key];
var queryHandlers = getQueryHandlers(provider);
var handlerCount = queryHandlers.length;
// no handlers? Y U DO DIS?
if (!handlerCount) {
queryClear();
return;
}
validQuery = true;
// let the provider know we're waiting for all of the handlers to finish
if (Array.isArray(provider.wait)) {
provider.wait.forEach(function (fn) {
return fn();
});
} else if (provider.wait) {
provider.wait();
}
// here we determine the `resultKey` used for caching the results
// in the current context
var query = queries[key];
var options = queryOptions || queriesOptions[key] || {};
var resultKey = JSON.stringify({ query: query, options: options });
var queryResult = queryResults[resultKey];
var queryResultExists = typeof queryResult !== 'undefined';
// subscribe to all of this provider's instances' stores for requeries
subscribeToAll(key, provider, fauxInstance, resultKey, query, callback);
// result handler for both sync and async queries
var setResult = function setResult(result) {
if (!activeQueries[resultKey]) {
console.warn('setResult was called but the following query is no longer active:', { query: query, options: options });
return;
}
var first = activeQueries[resultKey].values().next().value;
var leader = setResult === first;
var previousResult = queryResultExists ? queryResult : previousResults[key];
var asyncReset = setResult.asyncReset;
// if new result, set `doUpdate` flag
if (!doUpdate && !resultsEqual(result, previousResult)) {
doUpdate = true;
}
// a special `asyncReset` flag is set if async handler is detected;
// we want async results to override sync
if (asyncReset) {
// this should only occur once, at the start of setting async results
setResult.asyncReset = false;
props.results = {};
if (props.query) {
props.result = null;
}
}
props.results[key] = result;
previousResults[key] = result;
queryResults[resultKey] = result;
setMergedResult(result);
// if this handler is the leader, we pass the result onto the others
if (leader && activeQueries[resultKey]) {
activeQueries[resultKey].forEach(function (otherSetResult) {
if (otherSetResult !== setResult) {
otherSetResult(result);
}
});
}
if (--handlerCount === 0) {
// handler is done, so remove self
activeQueries[resultKey].delete(setResult);
// if there are no handlers remaining, this query is no longer active
if (!activeQueries[resultKey].size) {
delete activeQueries[resultKey];
setPartialStates(provider, result);
}
// no more query handlers, so let the provider know we're done
if (Array.isArray(provider.clear)) {
provider.clear.forEach(function (fn) {
return fn(doUpdate);
});
} else if (provider.clear) {
provider.clear(doUpdate);
}
// and this query is clear
queryClear();
// we want to remove the cached query results on the client/tests
// so that it will always update
if (!isServerSide || isTesting) {
delete queryResults[resultKey];
}
}
};
var setError = function setError(error) {
console.error(error);
};
// this query is currently taking place, make the handler follow the leader
if (activeQueries[resultKey]) {
activeQueries[resultKey].add(setResult);
return;
}
// this is a new query, so this handler is a leader;
// other handlers matching this `resultKey` will check
// if the query is active and become a follower
activeQueries[resultKey] = new Set();
activeQueries[resultKey].add(setResult);
// already have our query result cached?
// no point in calling any handlers; go ahead and set the result
if (queryResultExists) {
handlerCount = 1;
setResult(queryResult);
return;
}
// now we need to run the query through each `handleQuery` function,
// which may or may not be synchronous
queryHandlers.forEach(function (_ref6) {
var handleQuery = _ref6.handleQuery,
reducerKeys = _ref6.reducerKeys,
baseQuery = _ref6.baseQuery,
baseQueryOptions = _ref6.baseQueryOptions;
// we can determine whether or not its synchronous by checking the
// `handlerCount` immediately after `handleQuery` is called
var handlerCountBefore = handlerCount;
// normalize the query + options so that people can be lazy
var normalizedQuery = _extends({}, baseQuery, query);
var normalizedOptions = _extends({}, baseQueryOptions, options);
if (typeof normalizedOptions.select === 'undefined') {
normalizedOptions.select = reducerKeys === true ? Object.keys(provider.reducers) : reducerKeys;
} else if (!Array.isArray(normalizedOptions.select)) {
normalizedOptions.select = [normalizedOptions.select];
}
if (Array.isArray(normalizedOptions.select)) {
for (var reducerKey in normalizedQuery) {
if (normalizedOptions.select.indexOf(reducerKey) < 0) {
normalizedOptions.select.push(reducerKey);
}
}
}
handleQuery({
query: normalizedQuery,
options: normalizedOptions,
setResult: setResult,
setError: setError
});
if (handlerCount === handlerCountBefore) {
// asynchronous query, so we set the `asyncReset` flags to true
// only if they haven't been set to false yet
activeQueries[resultKey].forEach(function (setResult) {
setResult.asyncReset = setResult.asyncReset !== false;
});
}
});
});
if (!validQuery) {
props.result = originalResult;
props.results = originalResults;
}
return validQuery;
}
function subscribeToAll(key, provider, fauxInstance, resultKey, query, callback) {
if (isServerSide || !fauxInstance.props.__wrapper) {
return;
}
fauxInstance.requeryCallback = callback;
if (!provider.subscribedFauxInstances) {
provider.subscribedFauxInstances = {};
}
if (provider.subscribedFauxInstances[resultKey]) {
provider.subscribedFauxInstances[resultKey].add(fauxInstance);
return;
}
var subscribedFauxInstances = new Set();
provider.subscribedFauxInstances[resultKey] = subscribedFauxInstances;
subscribedFauxInstances.add(fauxInstance);
var timeout = void 0;
var requery = function requery(providerInstance) {
clearTimeout(timeout);
timeout = setTimeout(function () {
var _iteratorNormalCompletion5 = true;
var _didIteratorError5 = false;
var _iteratorError5 = undefined;
try {
for (var _iterator5 = subscribedFauxInstances[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
var _fauxInstance = _step5.value;
if (_fauxInstance.props.__wrapper.unmounted) {
subscribedFauxInstances.delete(_fauxInstance);
} else {
handleQueries(_fauxInstance, _fauxInstance.requeryCallback);
}
}
} catch (err) {
_didIteratorError5 = true;
_iteratorError5 = err;
} finally {
try {
if (!_iteratorNormalCompletion5 && _iterator5.return) {
_iterator5.return();
}
} finally {
if (_didIteratorError5) {
throw _iteratorError5;
}
}
}
});
};
(0, _keyConcats.pushOnReady)({ provider: provider }, requery);
if (!provider.subscriber) {
provider.subscriber = {};
}
var subscriber = provider.subscriber[key];
provider.subscriber[key] = function (providerInstance, providerInstance2) {
if (subscriber) {
subscriber(providerInstance, providerInstance2);
}
if (shouldRequery(providerInstance, query)) {
requery(providerInstance);
}
};
if (provider.instances) {
provider.instances.forEach(function (providerInstance) {
providerInstance.store.subscribe(function () {
if (shouldRequery(providerInstance, query)) {
requery(providerInstance);
}
});
});
}
}
function shouldRequery(providerInstance, query) {
var currentState = providerInstance.store.getState();
var lastQueriedState = providerInstance.lastQueriedState;
providerInstance.lastQueriedState = currentState;
if (!lastQueriedState) {
return true;
}
if (currentState !== lastQueriedState) {
if ((typeof query === 'undefined' ? 'undefined' : _typeof(query)) === 'object') {
for (var key in query) {
if (currentState[key] !== lastQueriedState[key]) {
return true;
}
}
} else {
return true;
}
}
return false;
}