mirror of
https://github.com/Kaelio/ktx.git
synced 2026-06-07 07:55:13 +02:00
90 lines
2.7 KiB
Python
90 lines
2.7 KiB
Python
from __future__ import annotations
|
|
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
import sqlglot
|
|
import yaml
|
|
|
|
from semantic_layer.engine import SemanticEngine
|
|
from semantic_layer.loader import SourceLoader
|
|
from semantic_layer.models import SourceDefinition
|
|
|
|
SOURCES_DIR = Path(__file__).parent.parent / "sources" / "ecommerce"
|
|
TPCH_DIR = Path(__file__).parent.parent / "sources" / "tpch"
|
|
|
|
|
|
@pytest.fixture
|
|
def ecommerce_sources() -> dict[str, SourceDefinition]:
|
|
loader = SourceLoader(SOURCES_DIR)
|
|
return loader.load_all()
|
|
|
|
|
|
@pytest.fixture
|
|
def tpch_sources() -> dict[str, SourceDefinition]:
|
|
loader = SourceLoader(TPCH_DIR)
|
|
return loader.load_all()
|
|
|
|
|
|
# ── Shared test helpers ──────────────────────────────────────────────
|
|
|
|
|
|
def make_engine(
|
|
sources_dict: dict[str, dict], dialect: str = "postgres"
|
|
) -> SemanticEngine:
|
|
"""Build a SemanticEngine from inline source dicts (writes temp YAML files)."""
|
|
tmpdir = tempfile.mkdtemp()
|
|
for name, data in sources_dict.items():
|
|
with open(Path(tmpdir) / f"{name}.yaml", "w") as f:
|
|
yaml.dump(data, f)
|
|
return SemanticEngine(tmpdir, dialect=dialect)
|
|
|
|
|
|
def assert_valid_sql(sql: str):
|
|
try:
|
|
sqlglot.parse(sql)
|
|
except Exception as e:
|
|
pytest.fail(f"Generated SQL is not valid: {e}\n\nSQL:\n{sql}")
|
|
|
|
|
|
@pytest.fixture
|
|
def make_bq_fct_orders_engine() -> SemanticEngine:
|
|
"""BigQuery-dialect engine with fct_orders source mirroring the production YAML."""
|
|
source = {
|
|
"name": "fct_orders",
|
|
"table": "analytics.fct_orders",
|
|
"grain": ["order_id"],
|
|
"columns": [
|
|
{"name": "order_id", "type": "number"},
|
|
{"name": "status", "type": "string"},
|
|
{"name": "transaction_date", "type": "time"},
|
|
],
|
|
"segments": [
|
|
{"name": "non_cancelled", "expr": "status != 'cancelled'"},
|
|
{
|
|
"name": "last_30_days",
|
|
"expr": "transaction_date >= timestamp(date_sub(current_date(), interval 30 day))",
|
|
},
|
|
],
|
|
"measures": [
|
|
{
|
|
"name": "daily_active_orders",
|
|
"expr": "count(distinct order_id)",
|
|
"segments": ["non_cancelled", "last_30_days"],
|
|
},
|
|
],
|
|
}
|
|
return make_engine({"fct_orders": source}, dialect="bigquery")
|
|
|
|
|
|
@pytest.fixture
|
|
def make_engine_factory():
|
|
"""Factory fixture: pass a sources-dict + dialect, get a SemanticEngine."""
|
|
|
|
def _make(
|
|
sources_dict: dict[str, dict], dialect: str = "postgres"
|
|
) -> SemanticEngine:
|
|
return make_engine(sources_dict, dialect=dialect)
|
|
|
|
return _make
|