diff --git a/client/coral-framework/graphql/mutations/index.js b/client/coral-framework/graphql/mutations/index.js
index 56f63b372..c9152e904 100644
--- a/client/coral-framework/graphql/mutations/index.js
+++ b/client/coral-framework/graphql/mutations/index.js
@@ -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 => {
diff --git a/client/coral-framework/helpers/plugins.js b/client/coral-framework/helpers/plugins.js
index a21eaba4b..bcf6e4c50 100644
--- a/client/coral-framework/helpers/plugins.js
+++ b/client/coral-framework/helpers/plugins.js
@@ -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);
}
diff --git a/client/coral-framework/hocs/withMutation.js b/client/coral-framework/hocs/withMutation.js
index 9c5bad8fd..f3f092187 100644
--- a/client/coral-framework/hocs/withMutation.js
+++ b/client/coral-framework/hocs/withMutation.js
@@ -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 ;
+ };
};
diff --git a/client/coral-framework/hocs/withQuery.js b/client/coral-framework/hocs/withQuery.js
index 42dfe7b35..6a5fa7c14 100644
--- a/client/coral-framework/hocs/withQuery.js
+++ b/client/coral-framework/hocs/withQuery.js
@@ -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 ;
+ };
};
diff --git a/client/coral-framework/services/registry.js b/client/coral-framework/services/registry.js
index d35861663..8fe934730 100644
--- a/client/coral-framework/services/registry.js
+++ b/client/coral-framework/services/registry.js
@@ -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;
+}
diff --git a/client/coral-framework/utils/index.js b/client/coral-framework/utils/index.js
index 598fb59ab..70ce89bf7 100644
--- a/client/coral-framework/utils/index.js
+++ b/client/coral-framework/utils/index.js
@@ -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]);
+}
+