2 // GraphQL Schema Definition
Before you start writing some code, we start by defining the structure of the data in our application.
Remember, we want to build a simple application for pizza orders.
CRUD
An order is placed by a customer. Since the customer data does not involve any complex business logic, we simply need to create and list them.
CRUD types are ideal for this scenario as they offer a straightforward way to handle create, read, update, and delete operations.
To achieve this, we define a Customer
type in schema/crud/customer.graphql
:
type Customer @crudType {
name: String! @index @unique
}
For a detailed explanation please refer to the CRUD Schema Definition.
Projections
Ingredients
In our pizza order application, managing ingredients is crucial as they involve specific business logic. To handle this efficiently, we use projections.
Each ingredient has an amount
property that tracks its availability. This amount
is automatically reduced whenever an order is placed.
To implement this functionality, we define a projection for ingredients in schema/projections/ingredient.graphql
:
type Ingredient
@upsertOn(
on: { topic: "demo", eventTypes: ["CreateIngredient"] }
identifyBy: { payload: ["id"] }
)
@upsertOn(
on: { topic: "demo", eventTypes: ["PlaceOrder"] }
identifyBy: { payload: ["ingredients"] }
) {
name: String! @index
amount: Int!
@from(events: ["CreateIngredient"], value: "payload.amount")
@from(events: ["PlaceOrder"], value: "projection.amount - 1")
@index
}
The Ingredient
projection is designed to handle ingredient management efficiently.
It creates new ingredients when a CreateIngredient
event occurs and automatically decreases the amount
of each ingredient by 1 whenever a PlaceOrder
event is processed.
This ensures accurate tracking of ingredient availability.
For a detailed explanation please refer to the Projections Schema Definition.
Orders
In the future, we anticipate introducing more complex business logic for orders. To accommodate this, we will use a projection for orders.
Currently, we only need orders to be created when PlaceOrder
events occur.
To implement this functionality, we define a projection for orders in schema/projections/order.graphql
:
type Order
@upsertOn(on: { topic: "demo", eventTypes: ["PlaceOrder"] }, identifyBy: { payload: ["id"] }) {
customer: Customer!
ingredients: [Ingredient!]!
}
For a detailed explanation, please refer to the Projections Schema Definition.
Additionally, we need an optimized way to list all placed orders efficiently. To achieve this, we define a view projection for placed orders:
type PlacedOrder @view(sqlFile: "./placed_order.sql") {
id: ID!
name: String!
date: DateTime! @index
ingredients: [String!]!
}
This view projection uses a QSL query to generate its data:
SELECT
o.id as id,
c.name as name,
o.createdat as date,
jsonb_agg(i.name) AS ingredients
FROM orderview AS o
INNER JOIN customerview AS c ON o.customer = c.id
INNER JOIN ingredientview AS i ON o.ingredients::jsonb ? i.id
GROUP BY o.id, c.name, o.createdat
ORDER BY o.createdat ASC
For a detailed explanation please refer to the @view documentation.
Auth Permissions
For the purpose of a simple demo we do not handle permissions and authentication.
Therefore the permission enum in schema/auth/permissions.graphql
is just a placeholder:
enum Permission {
TODO
}