Skip to content

Commit 69629cf

Browse files
committed
Add comprehensive BigQuery SemanticLayer integration tests
- 6 BigQuery tests using SemanticLayer (not just raw SQL) - test_semantic_layer_basic_metric: sum, avg, count metrics - test_semantic_layer_dimension_grouping: GROUP BY dimensions - test_semantic_layer_joins: relationships and joins - test_semantic_layer_multiple_metrics: multiple metrics in one query - test_semantic_layer_filters: WHERE clause filtering - test_semantic_layer_sql_generation: SQL compilation and dialect Integration tests: 16 passed (6 BigQuery + 10 Postgres) in 3.82s Regular tests: 570 passed, 3 skipped, 16 deselected
1 parent a64e6ae commit 69629cf

1 file changed

Lines changed: 175 additions & 30 deletions

File tree

tests/db/test_bigquery_integration.py

Lines changed: 175 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
import pytest
99

10+
from sidemantic import Dimension, Metric, Model, Relationship, SemanticLayer
11+
1012
# Mark all tests in this module as integration tests
1113
pytestmark = [
1214
pytest.mark.integration,
@@ -22,43 +24,186 @@
2224

2325

2426
@pytest.fixture(scope="module")
25-
def bigquery_adapter():
26-
"""Create BigQuery adapter connected to emulator."""
27-
from sidemantic.db.bigquery import BigQueryAdapter
28-
29-
# For emulator, we need to set BIGQUERY_EMULATOR_HOST
27+
def bigquery_layer():
28+
"""Create SemanticLayer with BigQuery connection."""
29+
# Set emulator host
3030
emulator_host = os.getenv("BIGQUERY_EMULATOR_HOST", "localhost:9050")
3131
os.environ["BIGQUERY_EMULATOR_HOST"] = emulator_host
3232

33-
adapter = BigQueryAdapter(project_id=BIGQUERY_PROJECT, dataset_id=BIGQUERY_DATASET)
34-
yield adapter
35-
adapter.close()
33+
# Create layer with BigQuery URL
34+
layer = SemanticLayer(connection=f"bigquery://{BIGQUERY_PROJECT}/{BIGQUERY_DATASET}")
35+
yield layer
36+
layer.adapter.close()
37+
38+
39+
def test_semantic_layer_basic_metric(bigquery_layer):
40+
"""Test basic metric query with SemanticLayer."""
41+
# Define a model using a CTE as table
42+
orders = Model(
43+
name="orders",
44+
table="(SELECT 1 as order_id, 100.0 as amount UNION ALL SELECT 2, 200.0 UNION ALL SELECT 3, 150.0)",
45+
primary_key="order_id",
46+
metrics=[
47+
Metric(name="total_revenue", agg="sum", sql="amount"),
48+
Metric(name="avg_revenue", agg="avg", sql="amount"),
49+
Metric(name="order_count", agg="count", sql="order_id"),
50+
],
51+
)
52+
bigquery_layer.add_model(orders)
3653

54+
# Test sum
55+
result = bigquery_layer.query(metrics=["orders.total_revenue"])
56+
row = result.fetchone()
57+
assert row[0] == 450.0
58+
59+
# Test avg
60+
result = bigquery_layer.query(metrics=["orders.avg_revenue"])
61+
row = result.fetchone()
62+
assert row[0] == 150.0
3763

38-
def test_bigquery_adapter_execute(bigquery_adapter):
39-
"""Test basic query execution."""
40-
result = bigquery_adapter.execute("SELECT 1 as x, 2 as y")
64+
# Test count
65+
result = bigquery_layer.query(metrics=["orders.order_count"])
4166
row = result.fetchone()
42-
assert row == (1, 2)
43-
44-
45-
def test_bigquery_adapter_aggregations(bigquery_adapter):
46-
"""Test aggregations in queries."""
47-
result = bigquery_adapter.execute("""
48-
SELECT
49-
SUM(x) as total,
50-
AVG(x) as average,
51-
MAX(x) as maximum,
52-
MIN(x) as minimum,
53-
COUNT(*) as count
54-
FROM (SELECT 1 as x UNION ALL SELECT 2 UNION ALL SELECT 3)
55-
""")
67+
assert row[0] == 3
68+
69+
70+
def test_semantic_layer_dimension_grouping(bigquery_layer):
71+
"""Test querying with dimensions and grouping."""
72+
sales = Model(
73+
name="sales",
74+
table="""(
75+
SELECT 'Electronics' as category, 'US' as region, 100 as amount UNION ALL
76+
SELECT 'Electronics', 'EU', 150 UNION ALL
77+
SELECT 'Clothing', 'US', 200 UNION ALL
78+
SELECT 'Clothing', 'EU', 250
79+
)""",
80+
primary_key="category",
81+
dimensions=[
82+
Dimension(name="category", type="categorical"),
83+
Dimension(name="region", type="categorical"),
84+
],
85+
metrics=[Metric(name="total_sales", agg="sum", sql="amount")],
86+
)
87+
bigquery_layer.add_model(sales)
88+
89+
# Group by one dimension
90+
result = bigquery_layer.query(metrics=["sales.total_sales"], dimensions=["sales.category"])
91+
rows = result.fetchall()
92+
cols = [desc[0] for desc in result.description]
93+
results = [dict(zip(cols, row)) for row in rows]
94+
results_dict = {r["category"]: r["total_sales"] for r in results}
95+
96+
assert results_dict["Electronics"] == 250
97+
assert results_dict["Clothing"] == 450
98+
99+
100+
def test_semantic_layer_joins(bigquery_layer):
101+
"""Test joins between models."""
102+
customers_join = Model(
103+
name="customers_join",
104+
table="""(
105+
SELECT 1 as customer_id, 'Alice' as name, 'US' as region UNION ALL
106+
SELECT 2, 'Bob', 'EU'
107+
)""",
108+
primary_key="customer_id",
109+
dimensions=[Dimension(name="region", type="categorical")],
110+
)
111+
112+
orders_join = Model(
113+
name="orders_join",
114+
table="""(
115+
SELECT 1 as order_id, 1 as customer_id, 100.0 as amount UNION ALL
116+
SELECT 2, 1, 150.0 UNION ALL
117+
SELECT 3, 2, 200.0
118+
)""",
119+
primary_key="order_id",
120+
metrics=[Metric(name="total_revenue", agg="sum", sql="amount")],
121+
relationships=[Relationship(name="customers_join", type="many_to_one", foreign_key="customer_id")],
122+
)
123+
124+
bigquery_layer.add_model(customers_join)
125+
bigquery_layer.add_model(orders_join)
126+
127+
# Query with join
128+
result = bigquery_layer.query(metrics=["orders_join.total_revenue"], dimensions=["customers_join.region"])
129+
rows = result.fetchall()
130+
cols = [desc[0] for desc in result.description]
131+
results_dict = {dict(zip(cols, row))["region"]: dict(zip(cols, row))["total_revenue"] for row in rows}
132+
133+
assert results_dict["US"] == 250.0
134+
assert results_dict["EU"] == 200.0
135+
136+
137+
def test_semantic_layer_multiple_metrics(bigquery_layer):
138+
"""Test multiple metrics in one query."""
139+
products = Model(
140+
name="products",
141+
table="""(
142+
SELECT 1 as product_id, 100 as price, 5 as quantity UNION ALL
143+
SELECT 2, 200, 3 UNION ALL
144+
SELECT 3, 150, 7
145+
)""",
146+
primary_key="product_id",
147+
metrics=[
148+
Metric(name="total_price", agg="sum", sql="price"),
149+
Metric(name="avg_price", agg="avg", sql="price"),
150+
Metric(name="total_quantity", agg="sum", sql="quantity"),
151+
Metric(name="product_count", agg="count", sql="product_id"),
152+
],
153+
)
154+
bigquery_layer.add_model(products)
155+
156+
result = bigquery_layer.query(
157+
metrics=["products.total_price", "products.avg_price", "products.total_quantity", "products.product_count"]
158+
)
56159
row = result.fetchone()
57160
cols = [desc[0] for desc in result.description]
58161
row_dict = dict(zip(cols, row))
59162

60-
assert row_dict["total"] == 6
61-
assert row_dict["average"] == 2.0
62-
assert row_dict["maximum"] == 3
63-
assert row_dict["minimum"] == 1
64-
assert row_dict["count"] == 3
163+
assert row_dict["total_price"] == 450
164+
assert row_dict["avg_price"] == 150.0
165+
assert row_dict["total_quantity"] == 15
166+
assert row_dict["product_count"] == 3
167+
168+
169+
def test_semantic_layer_filters(bigquery_layer):
170+
"""Test filtering with WHERE clause."""
171+
inventory = Model(
172+
name="inventory",
173+
table="""(
174+
SELECT 1 as item_id, 'A' as category, 100 as quantity UNION ALL
175+
SELECT 2, 'A', 200 UNION ALL
176+
SELECT 3, 'B', 150 UNION ALL
177+
SELECT 4, 'B', 250
178+
)""",
179+
primary_key="item_id",
180+
dimensions=[Dimension(name="category", type="categorical")],
181+
metrics=[Metric(name="total_quantity", agg="sum", sql="quantity")],
182+
)
183+
bigquery_layer.add_model(inventory)
184+
185+
# Test with filter in SQL
186+
result = bigquery_layer.query(
187+
metrics=["inventory.total_quantity"],
188+
dimensions=["inventory.category"],
189+
filters=["inventory.category = 'A'"],
190+
)
191+
rows = result.fetchall()
192+
assert len(rows) == 1
193+
assert rows[0][1] == 300 # Total for category A
194+
195+
196+
def test_semantic_layer_sql_generation(bigquery_layer):
197+
"""Test SQL generation without executing."""
198+
metrics_model = Model(
199+
name="metrics_sql",
200+
table="(SELECT 1 as id, 100 as value)",
201+
primary_key="id",
202+
metrics=[Metric(name="total", agg="sum", sql="value")],
203+
)
204+
bigquery_layer.add_model(metrics_model)
205+
206+
sql = bigquery_layer.compile(metrics=["metrics_sql.total"])
207+
assert "SELECT" in sql.upper()
208+
assert "SUM" in sql.upper()
209+
assert bigquery_layer.dialect == "bigquery"

0 commit comments

Comments
 (0)