Advanced Tutorial
Overview
This tutorial walks through core Modeling Definition Language (MDL) concepts in Wren Engine, using a progressively richer example. You will start with basic models, add relationships, and then define calculated fields on top of those relationships.
NOTE: This tutorial assumes you have access to a running Wren Engine. If not, check out the manual MCP setup guide. This guide focuses on MDL concepts and raw file structure. If you are following the Docker-based MCP quickstart, your workspace layout will be different.
MDL is the primary way to define models, relationships, and reusable analytical logic in Wren Engine. For a broader introduction, see Modeling Overview.
Prepare the MDL file
Create an mdl.json file under etc/mdl.
├── etc
│ ├── mdl
│ │ └── mdl.json
│ ├── config.properties
Set wren.directory=etc/mdl in etc/config.properties.
wren.directory=etc/mdl
All MDL definitions in this tutorial will be stored in etc/mdl/mdl.json.
What is Modeling Definition Language (MDL)
What is Modeling Definition Language (MDL)?
At minimum, the MDL examples in this tutorial use these top-level fields:
catalog: A logical catalog name that abstracts the original catalog.schema: A logical schema name that abstracts the original schema.models: The models exposed by Wren Engine.
{
"catalog": "my_catalog",
"schema": "my_schema",
"models": [
{
"name": "Orders",
"properties": {},
"refSql": "select * from tpch.orders",
"columns": [
{
"name": "orderkey",
"expression": "o_orderkey",
"type": "integer"
},
{
"name": "custkey",
"type": "integer",
"expression": "o_custkey"
}
],
"primaryKey": "orderkey"
},
{
"name": "Customer",
"refSql": "select * from tpch.customer",
"columns": [
{
"name": "custkey",
"expression": "c_custkey",
"type": "integer"
},
{
"name": "name",
"expression": "c_name",
"type": "varchar"
}
],
"primaryKey": "custkey"
}
]
}
What is a Model?
A model is a logical representation of a physical table or query result. It lets you expose business-facing structure without changing the underlying data source.
In practice, a model defines which fields are available, how they should be named, and how downstream queries should interpret them.
For the full model definition, see Model.
Query a model
Once a model is defined, you can query it through Wren Engine.
All datasets in the MDL, including models, metrics, and views, are placed into the search path my_catalog.my_schema. For example:
SELECT orderkey FROM my_catalog.my_schema.Orders
You can query modeled datasets much like tables in a traditional RDBMS. Wren Engine then compiles the query into executable SQL for the configured data source.
Add more dataset types
Wren Engine supports several dataset types:
- Model
- Relationship
- Metric
- View
In this tutorial, the next step is to add a Relationship to the MDL. For a broader overview, see Data Modeling - Overview.
What is a Relationship?
A relationship defines how two models are connected. Wren Engine uses the relationship metadata, including joinType and condition, to plan joins and support relationship-aware calculations. For a detailed reference, see Relationship.
"relationships": [
{
"name": "CustomerOrders",
"models": [ "Orders", "Customer" ],
"joinType": "MANY_TO_ONE",
"condition": "Orders.custkey = Customer.custkey"
}
]
After defining the relationship, add a relationship field to the model so it can reference the related model.
{
"name": "Orders",
"refSql": "select * from tpch.orders",
"columns": [
{
"name": "orderkey",
"type": "integer",
"expression": "o_orderkey"
},
{
"name": "custkey",
"type": "integer",
"expression": "o_custkey"
},
{
"name": "customer",
"type": "Customer",
// add relationship field here
"relationship": "CustomerOrders"
}
],
"primaryKey": "orderkey"
}
Calculated field
You can then add a calculated field by setting isCalculated: true. In this example, the calculated field references a column from the related Customer model.
{
"name": "Orders",
"refSql": "select * from tpch.orders",
"columns": [
{
"name": "orderkey",
"type": "integer",
"expression": "o_orderkey"
},
{
"name": "custkey",
"type": "integer",
"expression": "o_custkey"
},
{
"name": "customer",
"type": "Customer",
"relationship": "CustomerOrders"
},
{
"name": "customer_name",
"type": "varchar",
// add `isCalculated` field
"isCalculated": true,
// reference to `customer.name` column
"expression": "customer.name"
}
],
"primaryKey": "orderkey"
}
Putting these pieces together, the complete MDL looks like this:
{
"catalog": "my_catalog",
"schema": "my_schema",
"models": [
{
"name": "Orders",
"refSql": "select * from tpch.orders",
"columns": [
{
"name": "orderkey",
"type": "integer",
"expression": "o_orderkey"
},
{
"name": "custkey",
"type": "integer",
"expression": "o_custkey"
},
{
"name": "customer",
"type": "Customer",
"relationship": "CustomerOrders"
},
{
"name": "customer_name",
"type": "varchar",
"isCalculated": true,
"expression": "customer.name"
}
],
"primaryKey": "orderkey"
},
{
"name": "Customer",
"refSql": "select * from tpch.customer",
"columns": [
{
"name": "custkey",
"expression": "c_custkey",
"type": "integer"
},
{
"name": "name",
"expression": "c_name",
"type": "varchar"
}
],
"primaryKey": "custkey"
}
],
"relationships": [
{
"name": "CustomerOrders",
"models": [ "Orders", "Customer" ],
"joinType": "MANY_TO_ONE",
"condition": "Orders.custkey = Customer.custkey"
}
]
}
With that MDL in place, you can query the customer name directly from Orders:
SELECT customer_name FROM Orders;
customer_name
--------------------
Customer#000000370
Customer#000000781
Customer#000001234
Customer#000001369
Customer#000000557
Customer#000000392
...
Without the modeled relationship and calculated field, you would need to write the join manually in the source database:
SELECT
Customer.c_name
FROM
tpch.orders AS Orders
JOIN
tpch.customer AS Customer ON Orders.o_custkey = Customer.c_custkey;
This is the core benefit of modeling in Wren Engine: once relationships and calculated fields are defined centrally, downstream queries become simpler, more consistent, and easier to reuse across metrics and KPIs.
What’s Next?
- If you want to learn more about data modeling, see Data Modeling - Overview.