Package Exports
- resolve-query
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (resolve-query) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
🔍 resolve-query 
Provides a function to execute a query and get required information from a read model.
Usage
When initializing a query, pass the following arguments:
eventStore
- configured eventStore instance.readModels
- array of read models.
After the query is initialized, you get a function that is used to get data from read models by GraphQL request. This function receives the following arguments:
readModelName
(required) - read model name.qraphQLQuery
(required) - GraphQL query to get data.graphQLVariables
- specify it, ifgraphQLQuery
contains variables.getJwt
- callback to retrieve actual client state stored in verified JWT token.
Example
Let's implement the Read Model for building News state with custom GraphQL resolvers. It will handle the same events that are produced in Aggregate example.
Implement a read model for building News state with custom GraphQL resolvers and use the resolve-query
library to get the first page of news. It handles events produced by an aggregate shown in the resolve-command documentation.
import createQueryExecutor from 'resolve-query'
import createEventStore from 'resolve-es'
import createStorageDriver from 'resolve-storage-memory'
import createBusDriver from 'resolve-bus-memory'
import newsReadModel from './news-read-model.js'
const eventStore = createEventStore({
storage: createStorageDriver(),
bus: createBusDriver()
})
const readModels = [newsReadModel]
const query = createQueryExecutor({ eventStore, readModels })
// Request by GraphQL query with paramaters
query(
'news',
'query ($page: ID!) { news(page: $page) { title, text } }',
{ page: 1 }
).then(state => {
console.log(state)
})
news-read-model.js
import Immutable from 'seamless-immutable'
export default {
name: 'news',
initialState: Immutable([]),
eventHandlers: {
NEWS_CREATED: (state, {
aggregateId,
timestamp,
payload: {
title, link, userId, text
}
}) => {
const type = !link ? 'ask' : /^(Show HN)/.test(title) ? 'show' : 'story'
return Immutable(
[
{
id: aggregateId,
type,
title,
text,
createdBy: userId,
createdAt: timestamp,
link,
comments: [],
commentsCount: 0,
votes: []
}
].concat(state)
)
},
NEWS_UPVOTED: (state, { aggregateId, payload: { userId } }) => {
const index = state.findIndex(({ id }) => id === aggregateId)
if (index < 0) {
return state
}
return state.updateIn([index, 'votes'], votes => votes.concat(userId))
},
NEWS_UNVOTED: (state, { aggregateId, payload: { userId } }) => {
const index = state.findIndex(({ id }) => id === aggregateId)
if (index < 0) {
return state
}
return state.updateIn([index, 'votes'], votes =>
votes.filter(id => id !== userId)
)
},
NEWS_DELETED: (state, { aggregateId }) =>
state.filter(({ id }) => id !== aggregateId),
COMMENT_CREATED: (state, { aggregateId, payload: { parentId, commentId } }) => {
const newsIndex = state.findIndex(({ id }) => id === aggregateId)
if (newsIndex < 0) {
return state
}
let newState = state.updateIn(
[newsIndex, 'commentsCount'],
count => count + 1
)
const parentIndex = state.findIndex(({ id }) => id === parentId)
if (parentIndex < 0) {
return newState
}
return newState.updateIn([parentIndex, 'comments'], comments =>
comments.concat(commentId)
)
},
COMMENT_REMOVED: (state, { aggregateId, payload: { parentId, commentId } }) => {
const newsIndex = state.findIndex(({ id }) => id === aggregateId)
if (newsIndex < 0) {
return state
}
let newState = state.updateIn(
[newsIndex, 'commentsCount'],
count => count - 1
)
const parentIndex = state.findIndex(({ id }) => id === parentId)
if (parentIndex < 0) {
return newState
}
return newState.updateIn([parentIndex, 'comments'], comments =>
comments.filter(id => id !== commentId)
)
}
},
gqlSchema: `
type News {
id: ID!
type: String!
title: String!
text: String
createdBy: String!
createdAt: String!
link: String
comments: [String]
commentsCount: Int!
votes: [String]
}
type Query {
news(page: Int, aggregateId: ID, type: String): [News]
}
`,
gqlResolvers: {
news: (root, { page, aggregateId, type }) =>
aggregateId
? root
: page
? (type ? root.filter(news => news.type === type) : root).slice(
+page * NUMBER_OF_ITEMS_PER_PAGE - NUMBER_OF_ITEMS_PER_PAGE,
+page * NUMBER_OF_ITEMS_PER_PAGE + 1
)
: root
}
}