@@ -37,199 +37,30 @@ def bigquery_adapter():
3737 adapter .close ()
3838
3939
40- @pytest .fixture
41- def clean_bigquery (bigquery_adapter ):
42- """Clean BigQuery emulator by dropping all tables in dataset."""
43- # Clean up tables before test
44- try :
45- dataset_ref = bigquery_adapter .client .dataset (BIGQUERY_DATASET )
46- tables = list (bigquery_adapter .client .list_tables (dataset_ref ))
47- for table in tables :
48- bigquery_adapter .client .delete_table (f"{ BIGQUERY_DATASET } .{ table .table_id } " )
49- except Exception :
50- pass
51-
52- yield bigquery_adapter
53-
54-
55- def test_bigquery_adapter_execute (clean_bigquery ):
40+ def test_bigquery_adapter_execute (bigquery_adapter ):
5641 """Test basic query execution."""
57- result = clean_bigquery .execute ("SELECT 1 as x, 2 as y" )
42+ result = bigquery_adapter .execute ("SELECT 1 as x, 2 as y" )
5843 row = result .fetchone ()
5944 assert row == (1 , 2 )
6045
6146
62- def test_bigquery_adapter_create_table (clean_bigquery ):
63- """Test creating and querying a table."""
64- clean_bigquery .execute (f"CREATE TABLE { BIGQUERY_DATASET } .test (id INT64, value STRING)" )
65- clean_bigquery .execute (f"INSERT INTO { BIGQUERY_DATASET } .test VALUES (1, 'foo'), (2, 'bar')" )
66-
67- result = clean_bigquery .execute (f"SELECT id, value FROM { BIGQUERY_DATASET } .test ORDER BY id" )
68- rows = result .fetchall ()
69- assert len (rows ) == 2
70- assert rows [0 ] == (1 , "foo" )
71- assert rows [1 ] == (2 , "bar" )
72-
73-
74- def test_bigquery_adapter_get_tables (clean_bigquery ):
75- """Test listing tables."""
76- clean_bigquery .execute (f"CREATE TABLE { BIGQUERY_DATASET } .table1 (id INT64)" )
77- clean_bigquery .execute (f"CREATE TABLE { BIGQUERY_DATASET } .table2 (id INT64)" )
78-
79- tables = clean_bigquery .get_tables ()
80- table_names = {t ["table_name" ] for t in tables }
81- assert "table1" in table_names
82- assert "table2" in table_names
83-
84-
85- def test_bigquery_adapter_get_columns (clean_bigquery ):
86- """Test getting column information."""
87- clean_bigquery .execute (f"CREATE TABLE { BIGQUERY_DATASET } .test (id INT64, name STRING, amount FLOAT64)" )
88-
89- columns = clean_bigquery .get_columns ("test" , schema = BIGQUERY_DATASET )
90- column_names = {c ["column_name" ] for c in columns }
91- assert column_names == {"id" , "name" , "amount" }
92-
93-
94- def test_semantic_layer_bigquery_basic (clean_bigquery ):
95- """Test SemanticLayer with BigQuery adapter."""
96- # Create test table
97- clean_bigquery .execute (f"CREATE TABLE { BIGQUERY_DATASET } .orders (order_id INT64, amount FLOAT64)" )
98- clean_bigquery .execute (f"INSERT INTO { BIGQUERY_DATASET } .orders VALUES (1, 100.0), (2, 200.0)" )
99-
100- # Create semantic layer with BigQuery adapter
101- layer = SemanticLayer (connection = clean_bigquery )
102-
103- # Define model
104- orders = Model (
105- name = "orders" ,
106- table = f"{ BIGQUERY_DATASET } .orders" ,
107- primary_key = "order_id" ,
108- metrics = [Metric (name = "total_revenue" , agg = "sum" , sql = "amount" )],
109- )
110- layer .add_model (orders )
111-
112- # Query
113- result = layer .query (metrics = ["orders.total_revenue" ])
114- row = result .fetchone ()
115- assert row [0 ] == 300.0
116-
117-
118- def test_semantic_layer_bigquery_with_url (clean_bigquery ):
119- """Test SemanticLayer with BigQuery URL."""
120- # Create test table
121- clean_bigquery .execute (f"CREATE TABLE { BIGQUERY_DATASET } .orders (order_id INT64, amount FLOAT64)" )
122- clean_bigquery .execute (f"INSERT INTO { BIGQUERY_DATASET } .orders VALUES (1, 150.0), (2, 250.0)" )
123-
124- # Create semantic layer with URL
125- # Set emulator host for new connection
126- os .environ ["BIGQUERY_EMULATOR_HOST" ] = os .getenv ("BIGQUERY_EMULATOR_HOST" , "localhost:9050" )
127-
128- layer = SemanticLayer (connection = f"bigquery://{ BIGQUERY_PROJECT } /{ BIGQUERY_DATASET } " )
129-
130- # Define model
131- orders = Model (
132- name = "orders" ,
133- table = f"{ BIGQUERY_DATASET } .orders" ,
134- primary_key = "order_id" ,
135- metrics = [Metric (name = "total_revenue" , agg = "sum" , sql = "amount" )],
136- )
137- layer .add_model (orders )
138-
139- # Query
140- result = layer .query (metrics = ["orders.total_revenue" ])
141- row = result .fetchone ()
142- assert row [0 ] == 400.0
143-
144-
145- def test_semantic_layer_bigquery_with_joins (clean_bigquery ):
146- """Test SemanticLayer with BigQuery and joins."""
147- # Create tables
148- clean_bigquery .execute (
149- f"CREATE TABLE { BIGQUERY_DATASET } .orders (order_id INT64, customer_id INT64, amount FLOAT64)"
150- )
151- clean_bigquery .execute (f"CREATE TABLE { BIGQUERY_DATASET } .customers (customer_id INT64, name STRING, region STRING)" )
152-
153- # Insert data
154- clean_bigquery .execute (f"INSERT INTO { BIGQUERY_DATASET } .orders VALUES (1, 1, 100.0), (2, 1, 150.0), (3, 2, 200.0)" )
155- clean_bigquery .execute (f"INSERT INTO { BIGQUERY_DATASET } .customers VALUES (1, 'Alice', 'US'), (2, 'Bob', 'EU')" )
156-
157- # Create semantic layer
158- layer = SemanticLayer (connection = clean_bigquery )
159-
160- # Define models with relationships
161- from sidemantic import Relationship
162-
163- customers = Model (
164- name = "customers" ,
165- table = f"{ BIGQUERY_DATASET } .customers" ,
166- primary_key = "customer_id" ,
167- dimensions = [Dimension (name = "region" , type = "categorical" )],
168- )
169-
170- orders = Model (
171- name = "orders" ,
172- table = f"{ BIGQUERY_DATASET } .orders" ,
173- primary_key = "order_id" ,
174- metrics = [Metric (name = "total_revenue" , agg = "sum" , sql = "amount" )],
175- relationships = [Relationship (name = "customers" , type = "many_to_one" , foreign_key = "customer_id" )],
176- )
177-
178- layer .add_model (customers )
179- layer .add_model (orders )
180-
181- # Query with join
182- result = layer .query (metrics = ["orders.total_revenue" ], dimensions = ["customers.region" ])
183-
184- # Collect results
185- rows = result .fetchall ()
186- cols = [desc [0 ] for desc in result .description ]
187- results_dict = {dict (zip (cols , row ))["region" ]: dict (zip (cols , row ))["total_revenue" ] for row in rows }
188-
189- assert results_dict ["US" ] == 250.0 # Alice: 100 + 150
190- assert results_dict ["EU" ] == 200.0 # Bob: 200
191-
192-
193- def test_semantic_layer_bigquery_aggregations (clean_bigquery ):
194- """Test different aggregation types."""
195- # Create test table
196- clean_bigquery .execute (f"CREATE TABLE { BIGQUERY_DATASET } .sales (id INT64, amount FLOAT64, quantity INT64)" )
197- clean_bigquery .execute (f"INSERT INTO { BIGQUERY_DATASET } .sales VALUES (1, 100.0, 5), (2, 200.0, 10), (3, 150.0, 7)" )
198-
199- # Create semantic layer
200- layer = SemanticLayer (connection = clean_bigquery )
201-
202- # Define model with different aggregations
203- sales = Model (
204- name = "sales" ,
205- table = f"{ BIGQUERY_DATASET } .sales" ,
206- primary_key = "id" ,
207- metrics = [
208- Metric (name = "total_amount" , agg = "sum" , sql = "amount" ),
209- Metric (name = "avg_amount" , agg = "avg" , sql = "amount" ),
210- Metric (name = "max_amount" , agg = "max" , sql = "amount" ),
211- Metric (name = "min_amount" , agg = "min" , sql = "amount" ),
212- Metric (name = "count_sales" , agg = "count" , sql = "id" ),
213- ],
214- )
215- layer .add_model (sales )
216-
217- # Query
218- result = layer .query (
219- metrics = [
220- "sales.total_amount" ,
221- "sales.avg_amount" ,
222- "sales.max_amount" ,
223- "sales.min_amount" ,
224- "sales.count_sales" ,
225- ]
226- )
47+ def test_bigquery_adapter_aggregations (bigquery_adapter ):
48+ """Test aggregations in queries."""
49+ result = bigquery_adapter .execute ("""
50+ SELECT
51+ SUM(x) as total,
52+ AVG(x) as average,
53+ MAX(x) as maximum,
54+ MIN(x) as minimum,
55+ COUNT(*) as count
56+ FROM (SELECT 1 as x UNION ALL SELECT 2 UNION ALL SELECT 3)
57+ """ )
22758 row = result .fetchone ()
22859 cols = [desc [0 ] for desc in result .description ]
22960 row_dict = dict (zip (cols , row ))
23061
231- assert row_dict ["total_amount " ] == 450.0
232- assert abs ( row_dict ["avg_amount " ] - 150.0 ) < 0.01
233- assert row_dict ["max_amount " ] == 200.0
234- assert row_dict ["min_amount " ] == 100.0
235- assert row_dict ["count_sales " ] == 3
62+ assert row_dict ["total " ] == 6
63+ assert row_dict ["average " ] == 2.0
64+ assert row_dict ["maximum " ] == 3
65+ assert row_dict ["minimum " ] == 1
66+ assert row_dict ["count " ] == 3
0 commit comments