Semolina¶
Semolina: the ORM for your Semantic Layer.
Typed models in Python, supporting IDE autocomplete, and a Django-like fluent query interface for the semantic layer of your data warehouse backend.
Start here¶
Six tutorials, in order, building one application. They run on a local DuckDB database, so you can follow all of them without a warehouse.
Install Semolina and the extra for your backend.
Define a model, register an engine, and read the rows back.
Narrow, sort, and trim the result with .where(), .order_by() and
.limit().
A FastAPI service that answers GET /revenue with a typed JSON body.
Run your real query code against a semantic view built inside the test process.
Stop hand-writing the model and the DTO: semolina codegen and
codegen-dto read them off the warehouse.
Go further¶
The how-to guides extend the tutorials one topic at a time, and the explanation pages cover the ideas underneath. Read them when you hit the thing they cover.
What they are, and why AGG(), MEASURE() and semantic_view() are three
spellings of the same idea.
Snowflake, Databricks and DuckDB connection settings, and the
.semolina.toml that holds them.
Chain .metrics(), .dimensions(), .where(), .order_by(), .limit().
Convert rows into Pydantic models with .into(), or generate the class with
semolina codegen-dto.
Auto-generated reference for every public class, function, and field.
Quick example¶
from semolina import (
SemanticView,
Metric,
Dimension,
create_engine,
)
class Sales(SemanticView, view="sales"):
revenue = Metric()
country = Dimension()
# reads .semolina.toml
create_engine("default", register=True)
with (
Sales.query()
.metrics(Sales.revenue)
.dimensions(Sales.country)
.limit(10)
.execute()
) as cursor:
for row in cursor.fetchall_rows():
print(row.country, row.revenue)
Write the query once. Change the type in your .semolina.toml and the
same code runs on Databricks.
Each selected column comes back under its field name on every backend, so
row.country and row.revenue read the same on Snowflake, Databricks and
DuckDB.