Lazily resolve fragments in queries and mutations

This commit is contained in:
Chi Vinh Le
2017-05-08 21:30:25 +07:00
parent ce38b9da64
commit 4c17cec4fd
6 changed files with 69 additions and 17 deletions
@@ -8,7 +8,6 @@ import REMOVE_COMMENT_TAG from './removeCommentTag.graphql';
import IGNORE_USER from './ignoreUser.graphql';
import STOP_IGNORING_USER from './stopIgnoringUser.graphql';
import withMutation from '../../hocs/withMutation';
import {getFragmentDocument} from '../../services/registry';
export const withPostComment = withMutation(
gql`
@@ -17,7 +16,6 @@ export const withPostComment = withMutation(
...CreateCommentResponse
}
}
${getFragmentDocument('CreateCommentResponse')}
`, {
props: ({mutate}) => ({
postComment: comment => {
+3 -5
View File
@@ -5,8 +5,7 @@ import flattenDeep from 'lodash/flattenDeep';
import uniq from 'lodash/uniq';
import pick from 'lodash/pick';
import plugins from 'pluginsConfig';
import {gql} from 'react-apollo';
import {getDefinitionName} from 'coral-framework/utils';
import {getDefinitionName, mergeDocuments} from 'coral-framework/utils';
export const pluginReducers = merge(
...plugins
@@ -44,8 +43,7 @@ function getComponentFragments(components) {
// Assemble arguments for `gql` to call it directly without using template literals.
res[key].spreads = `...${res[key].spreads.join('\n...')}\n`;
const literals = ['', ...res[key].definitions.map(() => '\n')];
res[key].definitions = gql.apply(null, [literals, ...res[key].definitions]);
res[key].definitions = mergeDocuments(res[key].definitions);
});
return res;
@@ -86,7 +84,7 @@ export function getSlotsFragments(slots) {
export function getGraphQLConfigs() {
return plugins
.map(o => o.module.mutations && pick(o.module, ['mutations', 'queries', 'fragments']))
.map(o => pick(o.module, ['mutations', 'queries', 'fragments']))
.filter(o => o);
}
+16 -3
View File
@@ -1,7 +1,8 @@
import * as React from 'react';
import {graphql} from 'react-apollo';
import merge from 'lodash/merge';
import uniq from 'lodash/uniq';
import {getMutationOptions} from 'coral-framework/services/registry';
import {getMutationOptions, resolveFragments} from 'coral-framework/services/registry';
import {store} from 'coral-framework/services/store';
import {getDefinitionName} from '../utils';
@@ -73,6 +74,18 @@ export default (document, config) => WrappedComponent => {
};
return config.props({...data, mutate});
};
const wrapped = graphql(document, {...config, props: wrappedProps})(WrappedComponent);
return wrapped;
// Lazily resolve fragments from registry to support circular dependencies.
let memoized = null;
const getWrapped = () => {
if (!memoized) {
memoized = graphql(resolveFragments(document), {...config, props: wrappedProps})(WrappedComponent);
}
return memoized;
};
return (props) => {
const Wrapped = getWrapped();
return <Wrapped {...props} />;
};
};
+14 -3
View File
@@ -1,5 +1,6 @@
import * as React from 'react';
import {graphql} from 'react-apollo';
import {getQueryOptions} from 'coral-framework/services/registry';
import {getQueryOptions, resolveFragments} from 'coral-framework/services/registry';
import {getDefinitionName, separateDataAndRoot} from '../utils';
/**
@@ -33,6 +34,16 @@ export default (document, config) => WrappedComponent => {
};
};
const wrapped = graphql(document, {...config, options: wrappedOptions})(WrappedComponent);
return wrapped;
let memoized = null;
const getWrapped = () => {
if (!memoized) {
memoized = graphql(resolveFragments(document), {...config, options: wrappedOptions})(WrappedComponent);
}
return memoized;
};
return (props) => {
const Wrapped = getWrapped();
return <Wrapped {...props} />;
};
};
+26 -4
View File
@@ -1,7 +1,7 @@
import {gql} from 'react-apollo';
import {getDefinitionName} from 'coral-framework/utils';
import {getDefinitionName, mergeDocuments} from 'coral-framework/utils';
import {getGraphQLConfigs} from 'coral-framework/helpers/plugins';
import globalFragments from 'coral-framework/graphql/fragments';
import uniq from 'lodash/uniq';
const fragments = {};
const mutationOptions = {};
@@ -144,6 +144,11 @@ export function getQueryOptions(key) {
*/
export function getFragmentDocument(key) {
init();
if (!(key in fragments)) {
return '';
}
let documents = fragments[key] ? fragments[key].documents : [];
let fields = fragments[key] ? `...${fragments[key].names.join('\n...')}\n` : ' __typename';
@@ -153,8 +158,7 @@ export function getFragmentDocument(key) {
${fields}
}
`;
const literals = [main, ...documents.map(() => '\n')];
return gql.apply(null, [literals, ...documents]);
return mergeDocuments([main, ...documents]);
}
// The fragments and configs are lazily loaded to allow circular dependencies to work.
@@ -174,3 +178,21 @@ function init() {
getGraphQLConfigs().forEach(cfg => registerConfig(cfg));
}
export function resolveFragments(document) {
if (document.loc.source) {
// resolve fragments from registry
const matchedSubFragments = document.loc.source.body.match(/\.\.\.(.*)/g) || [];
const subFragments =
uniq(matchedSubFragments.map(f => f.replace('...', '')))
.map(key => getFragmentDocument(key))
.filter(i => i);
if (subFragments.length > 0) {
return mergeDocuments([document, ...subFragments]);
}
} else {
console.warn('Can only resolve fragments from documents definied using the gql tag.');
}
return document;
}
+10
View File
@@ -1,3 +1,5 @@
import {gql} from 'react-apollo';
export const getTotalActionCount = (type, comment) => {
return comment.action_summaries
.filter(s => s.__typename === type)
@@ -61,3 +63,11 @@ export function separateDataAndRoot(
root,
};
}
export function mergeDocuments(documents) {
const main = typeof documents[0] === 'string' ? documents[0] : documents[0].loc.source.body;
const substitutions = documents.slice(1);
const literals = [main, ...substitutions.map(() => '\n')];
return gql.apply(null, [literals, ...substitutions]);
}