reym
Example Application

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:

order.graphql
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:

order.graphql
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:

placed_order.sql
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.