#
The store
The store is a document store. It can get
and set
documents (JavaScript objects) based on a type and unique key.
The store is formed of two parts:
- a GraphQL schema: defines types and fields.
- a
mocks
object: to generate mock values for every field.
This article assumes the following schema and mocks:
type Book {
id: Int
title: String
author: String
}
const mocks = {
String: () => faker.lorem.words(4),
Int: () => faker.datatype.number({ min:1, max:999 }),
Book: {
author: () => `${faker.name.firstName()} ${faker.name.lastName()}`
}
}
#
Entities
The store has a concept of "entities": each type can have any number of entities. You can think of types as "tables" and entities as "rows". Entities are referenced by a unique field. By default the fields id
or _id
will be used as the unique field.
A very distinct feature of this store is that it will always return a value, even when it is empty:
store.get('Book', 1, 'title');
This returns the value of the field: title
for entity: Book
with id: 1
.
The store will first check its cache for a value for Book
with an id
of 1
. If this exists, that value is returned. If not, it will generate a value using the mocks: it will first try to use a mock for Book.id
, if none is provided, it will use the mock for the type of the field declare in mocks
above (Int
).
#
References
When using the get
method without specifying a field the store will return a reference to the requested entity, not values:
store.get('Book', 1);
The above will return:
{
$ref: {
typeName: 'Book',
key: 1
}
}
To get values, we can also use a reference:
const $book = store.get('Book', 1);
// some time later
const title = store.get($book, 'title');
We recommend prefixing variables that contain references with a $
. This convention helps differentiate between values and references.
#
Mutations
The store can also be modified using mutations. Values can be set for any entity, regardless of it already exists in the store.
store.set('Book', 1, 'author', 'John Doe');
This snippet sets the field: author
to 'John Doe'
for the entity: Book
with id: 1
.
#
Default resolvers
All resolvers are auto-mocked by default and use the store to return values. Assuming the following schema and mocks:
type Query {
books: [Book]
}
type Book {
id: Int
title: String
author: String
}
const mocks = {
String: () => faker.lorem.words(4),
Int: () => faker.datatype.number({ min:1, max:999 }),
Book: {
author: () => `${faker.name.firstName()} ${faker.name.lastName()}`
}
}
The default implementation for the books
query will be:
const resolvers = {
Query: {
books: () => {
return store.get('Query', 'ROOT', 'books');
}
}
}
It's important to note that the store considers Query
the same as any other type (such as Book
). The Query
and Mutation
types have one key difference: they have a single "entity" with the unique key "ROOT"
.
When the call store.get('Query', 'ROOT', 'books')
happens, the store uses the schema to identify what to return: Query.books
returns the type [Book]
aka an array of Book
. Note: The default for any auto-mocked "array of things" is to return two of those things.
The store generates two Book
entities with only an id
field as no other fields were specified on the request. Data for fields is only generated when requested (through queries). The call store.get('Query', 'ROOT', 'books')
then returns two references.
The resolver return references to these entities in the store. The engine will then continue to execute the graph, querying the store for the specific fields for these entities.
API Reference: see the store reference