Adapters

Sidemantic can import semantic models from other popular semantic layer formats, letting you use your existing metric definitions with Sidemantic’s query engine and features.

Supported Formats

Format Import Notes
Sidemantic (native) Full feature support
Cube No native segments
MetricFlow (dbt) No native segments or hierarchies
LookML (Looker) Liquid templating (not Jinja)
Hex No segments or cross-model derived metrics
Rill No relationships, segments, or cross-model metrics; single-model only
Superset (Apache) No relationships in datasets
Omni Relationships in separate model file

Feature Compatibility

This table shows which Sidemantic features are supported when importing from other formats:

Feature Sidemantic Cube MetricFlow LookML Hex Rill Superset Omni Notes
Models All formats support models/tables
Dimensions All formats support dimensions
Simple Metrics All formats support sum, count, avg, min, max
Time Dimensions All formats support time dimensions with granularity
Relationships Rill/Superset: single-model only; Omni: in model file
Derived Metrics All formats support calculated metrics
Metric Filters ⚠️ Rill has basic support; Superset lacks filters
Ratio Metrics Rill/Superset don’t have native ratio metric type
Segments Only Cube and LookML have native segment support
Cumulative Metrics Cube has rolling_window; MetricFlow has cumulative; others lack native support
Time Comparison Only MetricFlow has native time comparison metrics
Jinja Templates ⚠️ LookML uses Liquid templating
Hierarchies ⚠️ ⚠️ ⚠️ Cube/LookML/Omni: via drill_fields
Inheritance Only LookML has native extends support
Metadata Fields ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ Label and description support varies by format
Parameters Sidemantic-only feature
Ungrouped Queries Sidemantic-only feature

Legend:

  • ✅ Full support - feature fully supported on import
  • ⚠️ Partial support - feature works with limitations
  • ❌ Not supported - feature not available in source format

Importing into Sidemantic

Quick Start: Auto-Discovery

The easiest way to load semantic models from any format:

from sidemantic import SemanticLayer, load_from_directory

# Point at a directory with mixed formats
layer = SemanticLayer(connection="duckdb:///data.db")
load_from_directory(layer, "semantic_models/")

# That's it! Automatically:
# - Discovers all .lkml, .yml, .yaml files
# - Detects format (Cube, Hex, LookML, MetricFlow, etc.)
# - Parses with the right adapter
# - Infers relationships from foreign key naming
# - Builds the join graph

How Relationship Inference Works

load_from_directory() automatically infers relationships based on foreign key naming conventions:

  • orders.customer_idcustomers.id (many-to-one)
  • line_items.order_idorders.id (many-to-one)
  • products.category_idcategories.id (many-to-one)

It tries both singular and plural forms, so customer_id will match both customer and customers tables.

Reverse relationships (one-to-many) are automatically added to the target model.

Manual Adapter Usage

For more control over the import process, you can use adapters directly:

From Cube

Read Cube.js semantic models into Sidemantic:

from sidemantic.adapters.cube import CubeAdapter

# Import from Cube YAML
adapter = CubeAdapter()
graph = adapter.parse("cube/schema/Orders.yml")

# Query with Sidemantic
from sidemantic import SemanticLayer
layer = SemanticLayer(graph=graph)
result = layer.sql("SELECT revenue FROM orders")

From MetricFlow

Read dbt MetricFlow models into Sidemantic:

from sidemantic.adapters.metricflow import MetricFlowAdapter

# Import from MetricFlow YAML
adapter = MetricFlowAdapter()
graph = adapter.parse("models/metrics/")  # Directory of YAML files

# Query with Sidemantic
layer = SemanticLayer(graph=graph)
result = layer.sql("SELECT revenue FROM orders")

From LookML

Read Looker LookML views into Sidemantic:

from sidemantic.adapters.lookml import LookMLAdapter

# Import from LookML
adapter = LookMLAdapter()
graph = adapter.parse("views/orders.lkml")  # Single file or directory

# Query with Sidemantic
from sidemantic import SemanticLayer
layer = SemanticLayer(graph=graph)
result = layer.sql("SELECT revenue FROM orders")

From Hex

Read Hex semantic models into Sidemantic:

from sidemantic.adapters.hex import HexAdapter

# Import from Hex YAML
adapter = HexAdapter()
graph = adapter.parse("hex/models/")  # Directory of YAML files

# Query with Sidemantic
from sidemantic import SemanticLayer
layer = SemanticLayer(graph=graph)
result = layer.sql("SELECT revenue FROM orders")

From Rill

Read Rill metrics views into Sidemantic:

from sidemantic.adapters.rill import RillAdapter

# Import from Rill YAML
adapter = RillAdapter()
graph = adapter.parse("rill/metrics/")  # Directory of YAML files

# Query with Sidemantic
from sidemantic import SemanticLayer
layer = SemanticLayer()
layer.graph = graph
result = layer.compile(metrics=["orders.revenue"])

From Superset

Read Apache Superset datasets into Sidemantic:

from sidemantic.adapters.superset import SupersetAdapter

# Import from Superset YAML
adapter = SupersetAdapter()
graph = adapter.parse("superset/datasets/")  # Directory of YAML files

# Query with Sidemantic
from sidemantic import SemanticLayer
layer = SemanticLayer(graph=graph)
result = layer.sql("SELECT total_revenue FROM orders")

From Omni

Read Omni Analytics views into Sidemantic:

from sidemantic.adapters.omni import OmniAdapter

# Import from Omni YAML views
adapter = OmniAdapter()
graph = adapter.parse("omni/")  # Directory with views/ subdirectory and model.yaml

# Query with Sidemantic
from sidemantic import SemanticLayer
layer = SemanticLayer(graph=graph)
result = layer.sql("SELECT total_revenue FROM orders")

Import Mapping

These sections describe how each format’s concepts map to Sidemantic when importing.

Cube

  • cubesmodels
  • dimensionsdimensions
  • measuresmetrics
  • joinsrelationships (inferred from join definitions)
  • ${CUBE} placeholder → {model} placeholder
  • segmentssegments (native support)
  • Calculated measures (type=number) → derived metrics
  • rolling_window → cumulative metrics

MetricFlow

  • semantic_modelsmodels
  • entities → inferred relationships
  • dimensionsdimensions
  • measures → model-level metrics
  • metrics (graph-level) → graph-level metrics
  • Segments/hierarchies from meta field → preserved

LookML

  • viewsmodels
  • exploresrelationships (parsed from join definitions)
  • dimensionsdimensions
  • dimension_group → multiple time dimensions (one per timeframe)
  • measuresmetrics
  • filters (view-level) → segments
  • derived_table → model with SQL
  • ${TABLE} placeholder → {model} placeholder
  • Measure filters parsed from filters__all
  • Foreign keys extracted from sql_on in explore joins

Hex

  • Model id and base_sql_table/base_sql_querymodels
  • dimensions with expr_sql or expr_calcdimensions
  • measures with func/func_sql/func_calcmetrics
  • relations with join_sqlrelationships
  • Measure filters (inline or referenced) → metric filters
  • unique: true dimensions → primary key detection
  • timestamp_tz/timestamp_naive/date types → time dimensions

Rill

  • metrics_view (type) → models
  • dimensions with column/expressiondimensions
  • measures with expressionmetrics
  • timeseries column → time dimension
  • smallest_time_grain → time dimension granularity
  • Derived measures (type: derived) → derived metrics
  • Simple aggregation expressions parsed with sqlglot

Superset

  • table_name → model name
  • schema + table_name → model table
  • sql → model sql (for virtual datasets)
  • columnsdimensions
  • metrics → model metrics
  • main_dttm_col → time dimension detection
  • verbose_namelabel field
  • is_dttm flag → time dimension type
  • metric_type → aggregation mapping (count, sum, avg, etc.)

Omni

  • name (view) → model name
  • schema + table_name → model table
  • sql → model sql (for SQL-based views)
  • dimensionsdimensions
  • measures with aggregate_typemetrics
  • timeframes → time dimension granularity
  • label → model description (if no description field)
  • ${TABLE} placeholder → {model} placeholder
  • ${view.field} references → simplified field references
  • Measure filters → metric filters
  • relationships (from model.yaml) → model relationships

Validating Imports

Always validate after importing:

# Import
graph = adapter.parse("source.yml")

# Verify models loaded
print(f"Loaded {len(graph.models)} models")
for name, model in graph.models.items():
    print(f"  {name}: {len(model.metrics)} metrics, {len(model.dimensions)} dimensions")

# Verify metrics
print(f"Loaded {len(graph.metrics)} graph-level metrics")

# Test query generation
layer = SemanticLayer(graph=graph)
sql = layer.compile(metrics=["orders.revenue"])
print("Generated SQL:", sql)

Getting Help

If you encounter issues with format conversion:

  1. Check the compatibility table for known limitations
  2. Validate your source format is correctly structured
  3. Test with a simple model first before converting complex definitions
  4. File an issue at github.com/sidequery/sidemantic with:
    • Source format and file
    • Expected vs actual behavior
    • Generated SQL or error messages