Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor query reading to use graphql-anywhere #747

Merged
merged 14 commits into from
Oct 6, 2016
Merged
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ Expect active development and potentially significant breaking changes in the `0

### vNEXT

- **Refactor**: Reimplement internal store reading in terms of the [graphql-anywhere](https://github.com/apollostack/graphql-anywhere) package, which cleanly separates the GraphQL execution logic from Apollo's specific cache format. This will allow us to make the store reading much more extensible, including enabling developers to write their own custom client-side resolvers to implement client-side computed fields, read from Redux with GraphQL, and redirect cache reads.
- **Feature removal**: Remove query diffing functionality to make client more predictable and simplify implementation. Queries will still read from the store, and if the store does not have all of the necessary data the entire query will fetch from the server. Read justification and discussion in [Issue #615](https://github.com/apollostack/apollo-client/issues/615) [PR #693](https://github.com/apollostack/apollo-client/pull/693)
- **Breaking change**: Move batching to network interface and split off query merging into separate package [PR #734](https://github.com/apollostack/apollo-client/pull/734)
- **Feature removal**: No more `(read|diff)(Fragment|SelectionSet)FromStore`.

### v0.4.20
- Fix: Warn but do not fail when refetchQueries includes an unknown query name [PR #700](https://github.com/apollostack/apollo-client/pull/700)
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"license": "MIT",
"dependencies": {
"es6-promise": "^4.0.3",
"graphql-anywhere": "^0.1.11",
"graphql-tag": "^0.1.13",
"lodash.assign": "^4.0.8",
"lodash.clonedeep": "^4.3.2",
Expand Down
60 changes: 41 additions & 19 deletions src/core/QueryManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,17 @@ import {
/* tslint:disable */
SelectionSet,
/* tslint:enable */
OperationDefinition,
} from 'graphql';

import { print } from 'graphql-tag/printer';

import {
readSelectionSetFromStore,
readQueryFromStore,
} from '../data/readFromStore';

import {
diffSelectionSetAgainstStore,
diffQueryAgainstStore,
} from '../data/diffAgainstStore';

import {
Expand Down Expand Up @@ -343,13 +344,12 @@ export class QueryManager {
} else {
try {
const resultFromStore = {
data: readSelectionSetFromStore({
data: readQueryFromStore({
store: this.getDataWithOptimisticResults(),
rootId: queryStoreValue.query.id,
selectionSet: queryStoreValue.query.selectionSet,
query: makeDocument(
queryStoreValue.query.selectionSet, 'ROOT_QUERY', queryStoreValue.fragmentMap),
variables: queryStoreValue.previousVariables || queryStoreValue.variables,
returnPartialData: options.returnPartialData || options.noFetch,
fragmentMap: queryStoreValue.fragmentMap,
}),
loading: queryStoreValue.loading,
};
Expand Down Expand Up @@ -619,22 +619,20 @@ export class QueryManager {
// results including previous optimistic updates. Otherwise, apply it
// on top of the real data only.
store: isOptimistic ? this.getDataWithOptimisticResults() : this.getApolloState().data,
rootId: 'ROOT_QUERY',
selectionSet: querySelectionSet,
query: makeDocument(querySelectionSet, 'ROOT_QUERY', createFragmentMap(queryFragments || [])),
variables: queryVariables,
fragmentMap: createFragmentMap(queryFragments || []),
returnPartialData: false,
};
try {
// first try reading the full result from the store
const data = readSelectionSetFromStore(readOptions);
const data = readQueryFromStore(readOptions);
return { data, partial: false };
} catch (e) {
// next, try reading partial results, if we want them
if (queryOptions.returnPartialData || queryOptions.noFetch) {
try {
readOptions.returnPartialData = true;
const data = readSelectionSetFromStore(readOptions);
const data = readQueryFromStore(readOptions);
return { data, partial: true };
} catch (e) {
// fall through
Expand Down Expand Up @@ -838,13 +836,11 @@ export class QueryManager {
// ensure result is combined with data already in store
// this will throw an error if there are missing fields in
// the results if returnPartialData is false.
resultFromStore = readSelectionSetFromStore({
resultFromStore = readQueryFromStore({
store: this.getApolloState().data,
rootId: querySS.id,
selectionSet: querySS.selectionSet,
variables,
returnPartialData: returnPartialData || noFetch,
fragmentMap,
query,
});
// ensure multiple errors don't get thrown
/* tslint:disable */
Expand Down Expand Up @@ -898,13 +894,11 @@ export class QueryManager {
// If this is not a force fetch, we want to diff the query against the
// store before we fetch it from the network interface.
if (!forceFetch) {
const { isMissing, result } = diffSelectionSetAgainstStore({
selectionSet: queryDef.selectionSet,
const { isMissing, result } = diffQueryAgainstStore({
query: queryDoc,
store: this.reduxRootSelector(this.store.getState()).data,
throwOnMissingField: false,
rootId: querySS.id,
variables,
fragmentMap,
});

// If we're in here, only fetch if we have missing fields
Expand Down Expand Up @@ -1001,3 +995,31 @@ export class QueryManager {
return requestId;
}
}

// Shim to use graphql-anywhere, to be removed
function makeDocument(
selectionSet: SelectionSet,
rootId: string,
fragmentMap: FragmentMap
): Document {
if (rootId !== 'ROOT_QUERY') {
throw new Error('only supports query');
}

const op: OperationDefinition = {
kind: 'OperationDefinition',
operation: 'query',
selectionSet,
};

const frags: FragmentDefinition[] = fragmentMap ?
Object.keys(fragmentMap).map((name) => fragmentMap[name]) :
[];

const doc: Document = {
kind: 'Document',
definitions: [op, ...frags],
};

return doc;
}
1 change: 0 additions & 1 deletion src/data/debug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import isObject = require('lodash.isobject');
import omit = require('lodash.omit');
import mapValues = require('lodash.mapvalues');


export function stripLoc(obj: Object) {
if (isArray(obj)) {
return obj.map(stripLoc);
Expand Down
Loading