SQLGlot-based semantic layer with multi-format adapter support
Project description
Sidemantic
SQLGlot-based semantic layer with multi-format adapter support.
Features
- Simple API: Define measures once, use them everywhere
- SQL query interface: Write familiar SQL that gets rewritten to use semantic layer
- Automatic joins: Define relationships, joins happen automatically via graph traversal
- Multi-format adapters: Import/export from Cube, MetricFlow (dbt), and native YAML
- Rich measure types: Aggregations, ratios, formulas, cumulative, time comparisons, conversions
- SQLGlot-powered: Dialect-agnostic SQL generation with transpilation support
- Multi-hop joins: Automatic 2+ hop join discovery with intermediate models
- Type-safe: Pydantic models with validation
Quick Start
Define your semantic layer (YAML)
# semantic_layer.yml
# yaml-language-server: $schema=./sidemantic-schema.json
models:
- name: orders
table: orders
primary_key: id
dimensions:
- name: status
type: categorical
sql: status
- name: order_date
type: time
sql: order_date
granularity: day
measures:
- name: revenue
agg: sum
expr: amount
- name: order_count
agg: count
Query with SQL
from sidemantic import SemanticLayer
# Load semantic layer
layer = SemanticLayer.from_yaml("semantic_layer.yml")
# Query with familiar SQL - automatically rewritten
result = layer.sql("""
SELECT revenue, status
FROM orders
WHERE status = 'completed'
""")
df = result.fetchdf()
Alternative: Python API
from sidemantic import SemanticLayer, Model, Measure, Dimension
layer = SemanticLayer()
orders = Model(
name="orders",
table="orders",
primary_key="id",
dimensions=[
Dimension(name="status", type="categorical", sql="status"),
Dimension(name="order_date", type="time", sql="order_date", granularity="day"),
],
measures=[
Measure(name="revenue", agg="sum", expr="amount"),
Measure(name="order_count", agg="count"),
]
)
layer.add_model(orders)
# Programmatic query
result = layer.query(
metrics=["orders.revenue"],
dimensions=["orders.status"],
filters=["orders.status = 'completed'"]
)
df = result.fetchdf()
Editor Support
Generate JSON Schema for autocomplete in VS Code, IntelliJ, etc:
uv run python -m sidemantic.schema
Add to your YAML files:
# yaml-language-server: $schema=./sidemantic-schema.json
Adapters
Import
from sidemantic.adapters import CubeAdapter, MetricFlowAdapter, SidemanticAdapter
# From Cube
cube_adapter = CubeAdapter()
graph = cube_adapter.parse("cube_schema.yml")
# From MetricFlow (dbt)
mf_adapter = MetricFlowAdapter()
graph = mf_adapter.parse("semantic_models.yml")
# From native Sidemantic
native_adapter = SidemanticAdapter()
graph = native_adapter.parse("semantic_layer.yml")
Export
# Export to Cube
cube_adapter.export(sl.graph, "output_cube.yml")
# Export to MetricFlow
mf_adapter.export(sl.graph, "output_metricflow.yml")
# Export to native
sl.to_yaml("output_sidemantic.yml")
Full round-trip support: Sidemantic ↔ Cube ↔ MetricFlow
Advanced Features
Complex Measures
Define ratios, formulas, cumulative metrics:
models:
- name: orders
table: orders
primary_key: id
measures:
# Simple aggregation
- name: revenue
agg: sum
expr: amount
# Ratio
- name: conversion_rate
type: ratio
numerator: completed_revenue
denominator: total_revenue
# Formula
- name: profit_margin
type: derived
expr: "(revenue - cost) / revenue"
# Cumulative
- name: running_total
type: cumulative
expr: revenue
window: "7 days"
Python alternative
Measure(name="conversion_rate", type="ratio",
numerator="completed_revenue", denominator="total_revenue")
Measure(name="profit_margin", type="derived",
expr="(revenue - cost) / revenue")
Measure(name="running_total", type="cumulative",
expr="revenue", window="7 days")
Automatic Joins
Define relationships once, query across models:
models:
- name: orders
table: orders
primary_key: id
joins:
- name: customers
type: belongs_to
foreign_key: customer_id
- name: customers
table: customers
primary_key: id
joins:
- name: regions
type: belongs_to
foreign_key: region_id
Query spans 2 hops automatically:
# Automatically joins orders -> customers -> regions
result = layer.sql("""
SELECT orders.revenue, regions.region_name
FROM orders
""")
Test Coverage
- 117 passing tests
- Real DuckDB integration
- SQL query rewriting
- Round-trip adapter tests
- Multi-hop join verification
- Formula parsing validation
Run tests:
uv run pytest -v
Status
See docs/STATUS.md for detailed implementation status.
Completed:
- ✅ SQL query interface with automatic rewriting
- ✅ Core semantic layer with SQLGlot generation
- ✅ Entity-based automatic joins
- ✅ Multi-hop join discovery
- ✅ Derived metrics with formula parsing
- ✅ Native YAML format with import/export
- ✅ Cube and MetricFlow adapters (import/export)
- ✅ DuckDB integration
In Progress:
- ⚠️ Cumulative metrics (basic structure exists, needs subquery pattern)
Future:
- Query optimization
- Pre-aggregations/caching
- LookML adapter (requires grammar parser)
Examples
See examples/ directory:
sql_query_example.py- SQL query interface demonstrationbasic_example.py- Core usage patternsexport_example.py- Multi-format export demonstrationsidemantic/orders.yml- Native YAML examplecube/orders.yml- Cube format examplemetricflow/semantic_models.yml- MetricFlow format example
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sidemantic-0.1.0.tar.gz.
File metadata
- Download URL: sidemantic-0.1.0.tar.gz
- Upload date:
- Size: 42.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.4.30
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8dedd213d3aba411137d5543470100a5c743a9e5972955d31d391ff677489059
|
|
| MD5 |
744245d37ebb3ef2928fb8d905977e6c
|
|
| BLAKE2b-256 |
466830eb1d61c2b9a3903dcfac4a484f5a2ade1813fe755430b2170aa18cbae7
|
File details
Details for the file sidemantic-0.1.0-py3-none-any.whl.
File metadata
- Download URL: sidemantic-0.1.0-py3-none-any.whl
- Upload date:
- Size: 53.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.4.30
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fde9578fe7deef7aaf7c7d956fe6ffbd3b0da9061cc79352516c9f21934c74d4
|
|
| MD5 |
3451a182c3b8e8097e85a8bff0cbf042
|
|
| BLAKE2b-256 |
3c51f12b392a265e74d1da3e5227f86ba458836d2d38ce7c978469e4d96ec68f
|