Skip to main content

Store

TypeScript Support

A read model store has an associated TypeScript type:

  • Type Name - ResolveStore
  • Package - @resolve-js/readmodel-base

The table below lists functions that you can use to communicate with a read model store through a store object.

Function NameDescription
defineTableDefines a new table within the store.
findSearches for data items.
findOneSearches for a single data item.
countReturns the number of items that meet a condition.
insertInserts an item into a table.
updateUpdates data items.
deleteDeletes data items.

defineTableā€‹

Defines a new table within the store.

Argumentsā€‹

Argument NameDescription
tableNameThe new table's name.
tableDeclarationAn object that defines the new table's structure.

Exampleā€‹

Init: async store => {
await store.defineTable('Stories', {
indexes: { id: 'string', type: 'string' },
fields: [
'title',
'text',
'link',
'commentCount',
'votes',
'createdAt',
'createdBy',
'createdByName'
]
})

findā€‹

Searches for data items based on the specified expression.

Argumentsā€‹

Argument NameDescription
tableNameA table name.
searchConditionAn object that defines a search expression.
projectionConditionDefines which fields should be included into the resulting data sample.
sortConditionDefines how to sort the resulting data sample.
skipA number of data items to skip.
limitThe maximum number of data items to fetch.

Exampleā€‹

const getStories = async (type, store, { first, offset }) => {
try {
const search = type && type.constructor === String ? { type } : {}
const skip = first || 0
const stories = await store.find(
'Stories',
search,
null,
{ createdAt: -1 },
skip,
offset
)
return Array.isArray(stories) ? stories : []
} catch (error) {
...
throw error
}
}

The projection argument should be an object, in which keys are field names and values are either 1 or 0:

  • 1 - specifies that the field should be included into the resulting data sample;
  • 0 - specifies that a field should be excluded from the resulting sample.

The first field in a projection object defines how the projection is interpreted:

  • If the first field's value is 1, the projection works in inclusive mode. In this mode, you only need to specify included fields. All omitted fields are excluded.
  • If the first field's value is 0, the projection works in exclusive mode. In this mode, only excluded fields should be specified explicitly and all omitted fields are included.

Exampleā€‹

const findResult = await store.find(
'TestTable',
searchCondition,
{ field1: 1, field2: 1, field3: 1 }, // Return the specified fields
//{ field1: 0, field2: 0, field3: 0 }, // Return all fields except for the specified fields
{ id: sortOrder },
skip,
limit
)

findOneā€‹

Searches for a data item based on the specified expression.

Argumentsā€‹

Argument NameDescription
tableNameA table name.
searchConditionAn object that defines a search expression.
projectionConditionDefines which fields should be included into the resulting data sample.

Exampleā€‹

[STORY_UPVOTED]: async (store, { aggregateId, payload: { userId } }) => {
const story = await store.findOne(
'Stories',
{ id: aggregateId },
{ votes: 1 }
)
await store.update(
'Stories',
{ id: aggregateId },
{ $set: { votes: story.votes.concat(userId) } }
)
},

countā€‹

Returns the number of items that meet the specified condition.

Argumentsā€‹

Argument NameDescription
tableNameA table name.
searchConditionAn object that defines a search expression.

Exampleā€‹

const getStoryCount = async (type, store) =>
const count = await store.count('Stories', {})
return count
}

insertā€‹

Inserts an item into the specified table.

Argumentsā€‹

Argument NameDescription
tableNameA table name.
documentAn object that is an item to insert.

Exampleā€‹

[STORY_CREATED]: async (
store, { aggregateId, timestamp, payload: { title, link, userId, userName, text } }
) => {
const isAsk = link == null || link === ''
const type = isAsk ? 'ask' : /^(Show HN)/.test(title) ? 'show' : 'story'

const story = {
id: aggregateId,
type,
title,
text,
link: !isAsk ? link : '',
commentCount: 0,
votes: [],
createdAt: timestamp,
createdBy: userId,
createdByName: userName
}

await store.insert('Stories', story)
},

updateā€‹

Searches for data items and updates them based on the specified update expression.

Argumentsā€‹

Argument NameDescription
tableNameThe name of the table to update.
searchConditionAn object that defines a search expression.
updateConditionAn object that defines an update expression.
updateOptionsSpecifies additional options for the update operation.

Exampleā€‹

[STORY_UPVOTED]: async (store, { aggregateId, payload: { userId } }) => {
const story = await store.findOne(
'Stories',
{ id: aggregateId },
{ votes: 1 }
)
await store.update(
'Stories',
{ id: aggregateId },
{ $set: { votes: story.votes.concat(userId) } }
)
},

deleteā€‹

Deletes data items based on the specified search expression.

Argumentsā€‹

Argument NameDescription
tableNameA table name.
searchConditionAn object that defines a search expression.

Exampleā€‹

[SHOPPING_LIST_REMOVED]: async (store, { aggregateId }) => {
await store.delete('ShoppingLists', { id: aggregateId })
}

Search Expression Operatorsā€‹

Search expressions use operators to compare values and group expression clauses.

The following operators are supported:

Comparison operators:

OperatorDescription
\$eqMatches values that are equal to the specified value.
\$neMatches values that are not equal to the specified value.
\$ltMatches values that are less than the specified value.
\$lteMatches values that are less than or equal to the specified values.
\$gtMatches values that are greater than the specified value.
\$gteMatches values that are greater than or equal to the specified value.

Logical Operators:

OperatorDescription
\$andJoins two expressions with an AND operation.
\$orJoins two expressions with an OR operation.
\$notApplies a NOT operation to invert an expression.

Exampleā€‹

const data = await store.find('Entries', {
$or: [
{ $and: [{ name: 'Second entry', id: 'id-2' }] },
{ $not: { id: { $gte: 'id-1' } } },
],
})