mirror of
https://github.com/wassname/talk.git
synced 2026-07-10 16:14:26 +08:00
Preoptimize mutation, fragments and batched subscription documents
This commit is contained in:
@@ -9,7 +9,7 @@ class TalkProvider extends React.Component {
|
||||
pym: this.props.pym,
|
||||
plugins: this.props.plugins,
|
||||
rest: this.props.rest,
|
||||
graphqlRegistry: this.props.graphqlRegistry,
|
||||
graphql: this.props.graphql,
|
||||
notification: this.props.notification,
|
||||
storage: this.props.storage,
|
||||
history: this.props.history,
|
||||
@@ -32,7 +32,7 @@ TalkProvider.childContextTypes = {
|
||||
eventEmitter: PropTypes.object,
|
||||
plugins: PropTypes.object,
|
||||
rest: PropTypes.func,
|
||||
graphqlRegistry: PropTypes.object,
|
||||
graphql: PropTypes.object,
|
||||
notification: PropTypes.object,
|
||||
storage: PropTypes.object,
|
||||
history: PropTypes.object,
|
||||
|
||||
@@ -179,7 +179,9 @@ export default function reduceDocument(document, options = {}) {
|
||||
const mainDefinition = getMainDefinition(document);
|
||||
const fragments = getFragmentDefinitions(document);
|
||||
const operationDefinition = getOperationDefinition(document);
|
||||
const path = operationDefinition.operation;
|
||||
const path = operationDefinition
|
||||
? operationDefinition.operation
|
||||
: `type.${mainDefinition.typeCondition.name.value}`;
|
||||
|
||||
const execContext = {
|
||||
fragmentMap: createFragmentMap(fragments),
|
||||
@@ -224,6 +226,17 @@ export function createTypeGetter(introspectionData) {
|
||||
const parts = path.split('.');
|
||||
for (let i = 0; i < parts.length; i++) {
|
||||
const part = parts[i];
|
||||
|
||||
// Handle special path e.g. 'type.ROOT_QUERY.fieldName'
|
||||
if (part === 'type') {
|
||||
const type = parts[i + 1];
|
||||
const nextPath = `type.${type}`;
|
||||
result[nextPath] = type;
|
||||
currentPath = nextPath;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const nextPath = currentPath ? `${currentPath}.${part}` : part;
|
||||
if (nextPath in result) {
|
||||
currentPath = nextPath;
|
||||
|
||||
@@ -64,18 +64,15 @@ function hasEqualLeaves(a, b, path = '') {
|
||||
export default (fragments) => hoistStatics((BaseComponent) => {
|
||||
class WithFragments extends React.Component {
|
||||
static contextTypes = {
|
||||
graphqlRegistry: PropTypes.object,
|
||||
graphql: PropTypes.object,
|
||||
};
|
||||
|
||||
get graphqlRegistry() {
|
||||
return this.context.graphqlRegistry;
|
||||
return this.context.graphql.registry;
|
||||
}
|
||||
|
||||
resolveDocument(documentOrCallback) {
|
||||
const document = typeof documentOrCallback === 'function'
|
||||
? documentOrCallback(this.props, this.context)
|
||||
: documentOrCallback;
|
||||
return this.graphqlRegistry.resolveFragments(document);
|
||||
return this.context.graphql.resolveDocument(documentOrCallback, this.props, this.context);
|
||||
}
|
||||
|
||||
fragments = mapValues(fragments, (val) => this.resolveDocument(val));
|
||||
|
||||
@@ -42,18 +42,15 @@ export default (document, config = {}) => hoistStatics((WrappedComponent) => {
|
||||
static contextTypes = {
|
||||
eventEmitter: PropTypes.object,
|
||||
store: PropTypes.object,
|
||||
graphqlRegistry: PropTypes.object,
|
||||
graphql: PropTypes.object,
|
||||
};
|
||||
|
||||
get graphqlRegistry() {
|
||||
return this.context.graphqlRegistry;
|
||||
return this.context.graphql.registry;
|
||||
}
|
||||
|
||||
resolveDocument(documentOrCallback) {
|
||||
const document = typeof documentOrCallback === 'function'
|
||||
? documentOrCallback(this.props, this.context)
|
||||
: documentOrCallback;
|
||||
return this.graphqlRegistry.resolveFragments(document);
|
||||
return this.context.graphql.resolveDocument(documentOrCallback, this.props, this.context);
|
||||
}
|
||||
|
||||
// Lazily resolve fragments from graphRegistry to support circular dependencies.
|
||||
|
||||
@@ -4,12 +4,7 @@ import {getDefinitionName, separateDataAndRoot, getResponseErrors} from '../util
|
||||
import PropTypes from 'prop-types';
|
||||
import hoistStatics from 'recompose/hoistStatics';
|
||||
import {getOperationName} from 'apollo-client/queries/getFromAST';
|
||||
import {addTypenameToDocument} from 'apollo-client/queries/queryTransform';
|
||||
import throttle from 'lodash/throttle';
|
||||
import reduceDocument, {createTypeGetter} from '../graphql/reduceDocument';
|
||||
import introspectionData from '../graphql/introspection.json';
|
||||
|
||||
const typeGetter = createTypeGetter(introspectionData);
|
||||
|
||||
const withSkipOnErrors = (reducer) => (prev, action, ...rest) => {
|
||||
if (action.type === 'APOLLO_MUTATION_RESULT' && getResponseErrors(action.result)) {
|
||||
@@ -46,7 +41,7 @@ export default (document, config = {}) => hoistStatics((WrappedComponent) => {
|
||||
return class WithQuery extends React.Component {
|
||||
static contextTypes = {
|
||||
eventEmitter: PropTypes.object,
|
||||
graphqlRegistry: PropTypes.object,
|
||||
graphql: PropTypes.object,
|
||||
client: PropTypes.object,
|
||||
};
|
||||
|
||||
@@ -61,7 +56,7 @@ export default (document, config = {}) => hoistStatics((WrappedComponent) => {
|
||||
subscriptionQueue = [];
|
||||
|
||||
get graphqlRegistry() {
|
||||
return this.context.graphqlRegistry;
|
||||
return this.context.graphql.registry;
|
||||
}
|
||||
|
||||
get client() {
|
||||
@@ -69,15 +64,7 @@ export default (document, config = {}) => hoistStatics((WrappedComponent) => {
|
||||
}
|
||||
|
||||
resolveDocument(documentOrCallback) {
|
||||
let document = typeof documentOrCallback === 'function'
|
||||
? documentOrCallback(this.props, this.context)
|
||||
: documentOrCallback;
|
||||
document = reduceDocument(this.graphqlRegistry.resolveFragments(document), {typeGetter});
|
||||
|
||||
// We also add typenames to the document which apollo would usually do,
|
||||
// but we also use the network interface in subscriptions directly
|
||||
// which require the resolved typenames.
|
||||
return addTypenameToDocument(document);
|
||||
return this.context.graphql.resolveDocument(documentOrCallback, this.props, this.context);
|
||||
}
|
||||
|
||||
emitWhenNeeded(data) {
|
||||
@@ -124,7 +111,7 @@ export default (document, config = {}) => hoistStatics((WrappedComponent) => {
|
||||
subscribeToMoreThrottled = ({document, variables, updateQuery}) => {
|
||||
|
||||
// We need to add the typenames and resolve fragments.
|
||||
const query = addTypenameToDocument(this.graphqlRegistry.resolveFragments(document));
|
||||
const query = this.resolveDocument(document);
|
||||
const handler = (error, data) => {
|
||||
if (error) {
|
||||
|
||||
|
||||
+9
-5
@@ -12,6 +12,7 @@ import {BASE_PATH} from 'coral-framework/constants/url';
|
||||
import {createPluginsService} from './plugins';
|
||||
import {createNotificationService} from './notification';
|
||||
import {createGraphQLRegistry} from './graphqlRegistry';
|
||||
import {createGraphQLService} from './graphql';
|
||||
import globalFragments from 'coral-framework/graphql/fragments';
|
||||
import {createStorage, createPymStorage} from 'coral-framework/services/storage';
|
||||
import {createHistory} from 'coral-framework/services/history';
|
||||
@@ -121,7 +122,10 @@ export async function createContext({
|
||||
introspectionData,
|
||||
});
|
||||
const plugins = createPluginsService(pluginsConfig);
|
||||
const graphqlRegistry = createGraphQLRegistry(plugins.getSlotFragments.bind(plugins));
|
||||
const graphql = createGraphQLService(
|
||||
createGraphQLRegistry(plugins.getSlotFragments.bind(plugins)),
|
||||
introspectionData,
|
||||
);
|
||||
if (!notification) {
|
||||
|
||||
// Use default notification service (pym based)
|
||||
@@ -134,7 +138,7 @@ export async function createContext({
|
||||
plugins,
|
||||
eventEmitter,
|
||||
rest,
|
||||
graphqlRegistry,
|
||||
graphql,
|
||||
notification,
|
||||
storage,
|
||||
history,
|
||||
@@ -143,13 +147,13 @@ export async function createContext({
|
||||
};
|
||||
|
||||
// Load framework fragments.
|
||||
Object.keys(globalFragments).forEach((key) => graphqlRegistry.addFragment(key, globalFragments[key]));
|
||||
Object.keys(globalFragments).forEach((key) => graphql.registry.addFragment(key, globalFragments[key]));
|
||||
|
||||
// Register graphql extension
|
||||
graphqlRegistry.add(graphqlExtension);
|
||||
graphql.registry.add(graphqlExtension);
|
||||
|
||||
// Register plugin graphql extensions.
|
||||
plugins.getGraphQLExtensions().forEach((ext) => graphqlRegistry.add(ext));
|
||||
plugins.getGraphQLExtensions().forEach((ext) => graphql.registry.add(ext));
|
||||
|
||||
// Load plugin translations.
|
||||
plugins.getTranslations().forEach((t) => loadTranslations(t));
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import reduceDocument, {createTypeGetter} from '../graphql/reduceDocument';
|
||||
import {addTypenameToDocument} from 'apollo-client/queries/queryTransform';
|
||||
|
||||
/**
|
||||
* createHistory returns the history service for react router
|
||||
* @param {string} basename base path of the url
|
||||
* @return {Object} histor service
|
||||
*/
|
||||
export function createGraphQLService(registry, introspectionData) {
|
||||
const typeGetter = createTypeGetter(introspectionData);
|
||||
|
||||
return {
|
||||
registry,
|
||||
resolveDocument(documentOrCallback, props, context) {
|
||||
let document = typeof documentOrCallback === 'function'
|
||||
? documentOrCallback(props, context)
|
||||
: documentOrCallback;
|
||||
document = reduceDocument(registry.resolveFragments(document), {typeGetter});
|
||||
|
||||
// We also add typenames to the document which apollo would usually do,
|
||||
// but we also use the network interface in subscriptions directly
|
||||
// which require the resolved typenames.
|
||||
return addTypenameToDocument(document);
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user