Last active
February 9, 2017 23:27
-
-
Save viniciussbs/7fa917f921443af2f29abc7a7d91d724 to your computer and use it in GitHub Desktop.
Relay-style GraphQL pagination using Apollo Client on Ember (ember-apollo-client).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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); | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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 } | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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); | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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; | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Muito bom, parabéns.