4 // Updating the Schema
We already knew that we want to add more logic to the Order projection. Now we can start implementing this:
Up to this point, we haven't needed to modify the code of our demo application. From now on, we'll need to make changes to the code to implement the new features.
Let's imagine we want to add a price to our Pizza orders. For simplicity, we'll assume the base price of an order is 8 (no currency specified), and each additional ingredient adds 1 to the price.
We can leverage the projection to automatically calculate the price of an order based on its ingredients.
To achieve this, we'll update the Order
projection schema to include a price
field:
type Order
@upsertOn(on: { topic: "demo", eventTypes: ["PlaceOrder"] }, identifyBy: { payload: ["id"] }) {
customer: Customer!
ingredients: [Ingredient!]!
price: Int!
@readonly
@from(events: ["PlaceOrder"], value: "8 + len(payload.ingredients)")
}
Notice the @from
directive on the price
field. This directive uses an expression to dynamically calculate the price based on the number of ingredients in the order. By doing so, the price remains consistent with the order's ingredients, ensuring data integrity.
For more information about the @from
directive, its expressions, and usage, refer to the @from documentation.
Additionally, the price
field is marked as @readonly
. This designation ensures that the field cannot be modified directly through the API. Instead, it will always reflect the calculated value derived from the order's ingredients.
Since the price
field is now part of the Order
projection, we must also update the view projection schema to include the price
field. This ensures that the optimized view projection used to display placed orders reflects the updated schema accurately:
type PlacedOrder @view(sqlFile: "./placed_order.sql") {
id: ID!
name: String!
date: DateTime! @index
ingredients: [String!]!
price: Int!
}
To ensure the price
field in the view projection is populated correctly, we need to update the SQL query in placed_order.sql
to include the price
field:
SELECT
o.id as id,
c.name as name,
o.createdat as date,
jsonb_agg(i.name) AS ingredients,
o.price as price
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, o.price
ORDER BY o.createdat ASC
To apply these changes to our Freym instance, execute the deployment command:
make deploy
This command processes the updated schema files in the schema
directory and applies the changes to your Freym instance. Once deployed, Freym automatically updates its APIs to reflect the new projection schema, including the price
field in the Order
projection.
If you encounter any issues during deployment, you can easily perform a rollback to restore the previous state. For detailed instructions, refer to our rollback command documentation.