Skip to content

Instantly share code, notes, and snippets.

@viniciussbs
Last active February 9, 2017 23:27
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save viniciussbs/7fa917f921443af2f29abc7a7d91d724 to your computer and use it in GitHub Desktop.
Save viniciussbs/7fa917f921443af2f29abc7a7d91d724 to your computer and use it in GitHub Desktop.
Relay-style GraphQL pagination using Apollo Client on Ember (ember-apollo-client).
// app/routes/users/user.js
import Ember from 'ember';
import gql from 'graphql-tag';
import ObservableQuery from '../../mixins/observable-query';
const { Route } = Ember;
export default Route.extend(ObservableQuery, {
query: gql`
query User($id: ID) {
users(id: $id) {
id
name
}
}
`,
queryVariables: { id: null },
model({ user_id }) {
this.set('queryVariables.id', user_id);
return this._super(...arguments);
}
});
// app/routes/users/index.js without pagination
import Ember from 'ember';
import gql from 'graphql-tag';
import ObservableQuery from '../../mixins/observable-query';
const { Route } = Ember;
export default Route.extend(ObservableQuery, {
query: gql`
query AllUsers($first: Int) {
viewer {
users(first: $first, after: "") {
edges {
node {
id
name
}
}
}
}
}
`,
queryVariables: { first: 30 }
});
// app/routes/users/index.js with pagination
import Ember from 'ember';
import gql from 'graphql-tag';
import ObservableQuery from '../../mixins/observable-query';
import RelayPagination from '../../mixins/relay-pagination';
const { Route } = Ember;
export default Route.extend(ObservableQuery, RelayPagination, {
paginatedConnection: 'viewer.users',
query: gql`
query AllUsers($cursor: String, $first: Int) {
viewer {
users(first: $first, after: $cursor) {
edges {
node {
id
name
}
}
pageInfo {
endCursor
}
}
}
}
`,
queryVariables: { cursor: null, first: 30 },
model({ first }) {
if (first) this.set('queryVariables.first', first);
return this._super(...arguments);
}
});
// app/mixins/observable-query.js
import Ember from 'ember';
const {
Mixin,
inject: { service }
} = Ember;
export default Mixin.create({
apollo: service(),
beforeModel() {
this._super(...arguments);
let options = { query: this.get('query') };
if (this.forceFetch) {
options.forceFetch = this.get('forceFetchQuery');
}
let observableQuery = this.get('apollo.client').watchQuery(options);
this.set('observableQuery', observableQuery);
this.set('queryOptions', options);
},
model() {
if (this.queryVariables) {
this.set('queryOptions.variables', this.get('queryVariables'));
}
return this.get('observableQuery').setOptions(this.get('queryOptions')).then(this.updateModel.bind(this));
},
afterModel() {
this._super(...arguments);
let route = this;
let observer = {
next(queryResult) {
if (route.get('controller.model')) {
route.set('controller.model', route.updateModel(queryResult));
}
}
};
this.set('queryResultSubscription', this.get('observableQuery').subscribe(observer));
},
deactivate() {
this._super(...arguments);
this.get('queryResultSubscription').unsubscribe();
},
// Custom Hook
updateModel(newResult) {
return newResult;
}
});
// app/mixins/relay-pagination.js
import Ember from 'ember';
const {
Mixin,
inject: { service }
} = Ember;
export default Mixin.create({
actions: {
fetchMore() {
let observableQuery = this.get('observableQuery');
let connection = this.getPaginatedConnection(observableQuery.currentResult().data);
observableQuery.fetchMore({
variables: { cursor: connection.pageInfo.endCursor },
updateQuery: this.updateQuery.bind(this)
});
}
},
updateQuery(previousResult, { fetchMoreResult }) {
if (fetchMoreResult.data) {
const newResult = Object.assign({}, previousResult);
const newResultConnection = this.getPaginatedConnection(newResult);
const previousResultConnection = this.getPaginatedConnection(previousResult);
const fetchMoreResultConnection = this.getPaginatedConnection(fetchMoreResult.data);
const newCursor = fetchMoreResultConnection.pageInfo.endCursor;
const newEdges = fetchMoreResultConnection.edges;
const previousEdges = previousResultConnection.edges;
if (newCursor) {
newResultConnection.pageInfo.endCursor = newCursor;
}
newResultConnection.edges = [ ...previousEdges, ...newEdges ];
return newResult;
} else {
return previousResult;
}
},
getPaginatedConnection(data) {
const paths = this.get('paginatedConnection').split('.');
return paths.reduce((memo, path) => memo[path], data);
}
});
@jhonathas
Copy link

Muito bom, parabéns.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment