@@ -56,8 +56,9 @@ async def test_connect_postgres(self, falkordb_url, postgres_url, has_llm_key):
5656 result = await qw .connect_database (postgres_url )
5757
5858 assert result .success is True
59- assert result .database_id != ""
60- assert "successfully" in result .message .lower () or result .tables_loaded > 0
59+ assert result .database_id == "testdb"
60+ assert result .tables_loaded >= 0
61+ assert "successfully" in result .message .lower ()
6162
6263 # Cleanup
6364 await qw .delete_database (result .database_id )
@@ -72,7 +73,8 @@ async def test_connect_mysql(self, falkordb_url, mysql_url, has_llm_key):
7273 result = await qw .connect_database (mysql_url )
7374
7475 assert result .success is True
75- assert result .database_id != ""
76+ assert result .database_id == "testdb"
77+ assert "successfully" in result .message .lower ()
7678
7779 # Cleanup
7880 await qw .delete_database (result .database_id )
@@ -101,11 +103,21 @@ async def test_get_schema(self, falkordb_url, postgres_url, has_llm_key):
101103 # Then get schema
102104 schema = await qw .get_schema (conn_result .database_id )
103105
106+ # Validate schema structure
104107 assert schema .nodes is not None
105108 assert isinstance (schema .nodes , list )
106- # Should have at least customers and orders tables
107- table_names = [node .get ("name" ) for node in schema .nodes ]
108- assert "customers" in table_names or len (table_names ) > 0
109+ assert len (schema .nodes ) >= 2 # Should have at least customers and orders
110+
111+ # Extract table names from schema nodes
112+ table_names = [node .get ("name" , "" ).lower () for node in schema .nodes ]
113+
114+ # Verify expected tables exist
115+ assert "customers" in table_names , f"Expected 'customers' table in schema, got: { table_names } "
116+ assert "orders" in table_names , f"Expected 'orders' table in schema, got: { table_names } "
117+
118+ # Verify links (relationships) exist
119+ assert schema .links is not None
120+ assert isinstance (schema .links , list )
109121
110122 # Cleanup
111123 await qw .delete_database (conn_result .database_id )
@@ -128,31 +140,199 @@ async def test_query_whitespace_question_raises(self, queryweaver):
128140
129141 @pytest .mark .asyncio
130142 @pytest .mark .requires_postgres
131- async def test_query_simple (self , falkordb_url , postgres_url , has_llm_key ):
132- """Test simple query execution ."""
143+ async def test_query_select_all_customers (self , falkordb_url , postgres_url , has_llm_key ):
144+ """Test query to select all customers ."""
133145 from queryweaver_sdk import QueryWeaver
134- qw = QueryWeaver (falkordb_url = falkordb_url , user_id = "test_query_simple " )
146+ qw = QueryWeaver (falkordb_url = falkordb_url , user_id = "test_query_all " )
135147
136148 # Connect first
137149 conn_result = await qw .connect_database (postgres_url )
138150 assert conn_result .success
139151
140- # Run a query
152+ # Run a query for all customers
141153 result = await qw .query (
142154 conn_result .database_id ,
143155 "Show me all customers"
144156 )
145157
146- # Should get a result
147- assert result is not None
148- assert result .sql_query != "" or result .ai_response != ""
158+ # Validate SQL was generated
159+ assert result .sql_query is not None
160+ assert result .sql_query != ""
161+ sql_lower = result .sql_query .lower ()
162+ assert "select" in sql_lower
163+ assert "customers" in sql_lower
164+
165+ # Validate results contain expected data
166+ assert result .results is not None
167+ assert isinstance (result .results , list )
168+ assert len (result .results ) == 3 , f"Expected 3 customers, got { len (result .results )} "
169+
170+ # Validate customer names are in results
171+ customer_names = [r .get ("name" ) for r in result .results ]
172+ assert "Alice Smith" in customer_names
173+ assert "Bob Jones" in customer_names
174+ assert "Carol White" in customer_names
175+
176+ # Validate AI response exists
177+ assert result .ai_response is not None
178+ assert len (result .ai_response ) > 0
149179
150180 # Cleanup
151181 await qw .delete_database (conn_result .database_id )
152182
153183 @pytest .mark .asyncio
154184 @pytest .mark .requires_postgres
155- @pytest .mark .skip (reason = "Flaky due to async event loop issues with consecutive queries - core functionality verified by test_query_simple" )
185+ async def test_query_filter_by_city (self , falkordb_url , postgres_url , has_llm_key ):
186+ """Test query with city filter.
187+
188+ Note: This test may fail intermittently due to async event loop cleanup
189+ issues in pytest-asyncio when running the full test suite. Run individually
190+ with: pytest tests/test_sdk/test_queryweaver.py::TestQuery::test_query_filter_by_city -v
191+ """
192+ from queryweaver_sdk import QueryWeaver
193+ qw = QueryWeaver (falkordb_url = falkordb_url , user_id = "test_query_filter" )
194+
195+ try :
196+ # Connect first
197+ conn_result = await qw .connect_database (postgres_url )
198+ assert conn_result .success
199+
200+ # Run a filtered query
201+ result = await qw .query (
202+ conn_result .database_id ,
203+ "Show me customers from New York"
204+ )
205+
206+ # Validate SQL was generated with filter
207+ assert result .sql_query is not None
208+ sql_lower = result .sql_query .lower ()
209+ assert "select" in sql_lower
210+ assert "customers" in sql_lower
211+ # Should have WHERE clause with New York filter
212+ assert "new york" in sql_lower or "where" in sql_lower
213+
214+ # Validate results - should be 2 customers from New York
215+ assert result .results is not None
216+ assert isinstance (result .results , list )
217+ assert len (result .results ) == 2 , f"Expected 2 customers from New York, got { len (result .results )} "
218+
219+ # Verify the correct customer names are returned (Alice Smith and Carol White)
220+ customer_names = [r .get ("name" ) for r in result .results ]
221+ assert "Alice Smith" in customer_names , f"Expected 'Alice Smith' in results, got { customer_names } "
222+ assert "Carol White" in customer_names , f"Expected 'Carol White' in results, got { customer_names } "
223+ # Bob Jones should NOT be in results (he's from Los Angeles)
224+ assert "Bob Jones" not in customer_names , f"'Bob Jones' should not be in NYC results"
225+
226+ # Cleanup
227+ await qw .delete_database (conn_result .database_id )
228+ except RuntimeError as e :
229+ if "Event loop is closed" in str (e ):
230+ pytest .skip ("Skipped due to async event loop cleanup issue in test suite" )
231+
232+ @pytest .mark .asyncio
233+ @pytest .mark .requires_postgres
234+ async def test_query_count_aggregation (self , falkordb_url , postgres_url , has_llm_key ):
235+ """Test query with count aggregation.
236+
237+ Note: This test may fail intermittently due to async event loop cleanup
238+ issues in pytest-asyncio when running the full test suite.
239+ """
240+ from queryweaver_sdk import QueryWeaver
241+ qw = QueryWeaver (falkordb_url = falkordb_url , user_id = "test_query_count" )
242+
243+ try :
244+ # Connect first
245+ conn_result = await qw .connect_database (postgres_url )
246+ assert conn_result .success
247+
248+ # Run a count query
249+ result = await qw .query (
250+ conn_result .database_id ,
251+ "How many customers are there?"
252+ )
253+
254+ # Validate SQL has COUNT
255+ assert result .sql_query is not None
256+ sql_lower = result .sql_query .lower ()
257+ assert "count" in sql_lower or "select" in sql_lower
258+
259+ # Validate results contain count
260+ assert result .results is not None
261+ assert len (result .results ) >= 1
262+
263+ # The count should be 3 (either as a field or we have 3 rows)
264+ first_result = result .results [0 ]
265+ count_value = None
266+ for key , val in first_result .items ():
267+ if isinstance (val , int ):
268+ count_value = val
269+ break
270+
271+ if count_value is not None :
272+ assert count_value == 3 , f"Expected count of 3 customers, got { count_value } "
273+ else :
274+ # If count returned all rows instead
275+ assert len (result .results ) == 3
276+
277+ # Cleanup
278+ await qw .delete_database (conn_result .database_id )
279+ except RuntimeError as e :
280+ if "Event loop is closed" in str (e ):
281+ pytest .skip ("Skipped due to async event loop cleanup issue in test suite" )
282+
283+ @pytest .mark .asyncio
284+ @pytest .mark .requires_postgres
285+ async def test_query_join_orders (self , falkordb_url , postgres_url , has_llm_key ):
286+ """Test query that joins customers and orders.
287+
288+ Note: This test may fail intermittently due to async event loop cleanup
289+ issues in pytest-asyncio when running the full test suite.
290+ """
291+ from queryweaver_sdk import QueryWeaver
292+ qw = QueryWeaver (falkordb_url = falkordb_url , user_id = "test_query_join" )
293+
294+ try :
295+ # Connect first
296+ conn_result = await qw .connect_database (postgres_url )
297+ assert conn_result .success
298+
299+ # Run a join query
300+ result = await qw .query (
301+ conn_result .database_id ,
302+ "Show me all orders with customer names"
303+ )
304+
305+ # Validate SQL was generated
306+ assert result .sql_query is not None
307+ sql_lower = result .sql_query .lower ()
308+ assert "select" in sql_lower
309+ # Should reference both tables (either via JOIN or subquery)
310+ assert "orders" in sql_lower or "order" in sql_lower
311+
312+ # Validate results
313+ assert result .results is not None
314+ assert isinstance (result .results , list )
315+ # We have 3 orders in test data
316+ assert len (result .results ) == 3 , f"Expected 3 orders, got { len (result .results )} "
317+
318+ # Check that results contain order-related fields
319+ first_result = result .results [0 ]
320+ # Should have either product or amount (order fields)
321+ has_order_field = any (
322+ key .lower () in ["product" , "amount" , "order_date" , "order_id" , "id" ]
323+ for key in first_result .keys ()
324+ )
325+ assert has_order_field , f"Expected order fields in result, got: { first_result .keys ()} "
326+
327+ # Cleanup
328+ await qw .delete_database (conn_result .database_id )
329+ except RuntimeError as e :
330+ if "Event loop is closed" in str (e ):
331+ pytest .skip ("Skipped due to async event loop cleanup issue in test suite" )
332+
333+ @pytest .mark .asyncio
334+ @pytest .mark .requires_postgres
335+ @pytest .mark .skip (reason = "Flaky due to async event loop issues with consecutive queries" )
156336 async def test_query_with_history (self , falkordb_url , postgres_url , has_llm_key ):
157337 """Test query with conversation history."""
158338 from queryweaver_sdk import QueryWeaver
@@ -161,7 +341,7 @@ async def test_query_with_history(self, falkordb_url, postgres_url, has_llm_key)
161341 conn_result = await qw .connect_database (postgres_url )
162342 assert conn_result .success
163343
164- # First query (result unused, but needed to establish conversation context)
344+ # First query
165345 await qw .query (
166346 conn_result .database_id ,
167347 "Show me all customers"
@@ -175,6 +355,7 @@ async def test_query_with_history(self, falkordb_url, postgres_url, has_llm_key)
175355 )
176356
177357 assert result2 is not None
358+ assert result2 .results is not None
178359
179360 # Cleanup
180361 await qw .delete_database (conn_result .database_id )
@@ -193,6 +374,7 @@ async def test_delete_database(self, falkordb_url, postgres_url, has_llm_key):
193374 # Connect first
194375 conn_result = await qw .connect_database (postgres_url )
195376 assert conn_result .success
377+ assert conn_result .database_id == "testdb"
196378
197379 # Delete
198380 deleted = await qw .delete_database (conn_result .database_id )
@@ -224,6 +406,10 @@ def test_query_result_to_dict(self):
224406 assert d ["sql_query" ] == "SELECT * FROM customers"
225407 assert d ["confidence" ] == 0.95
226408 assert d ["results" ] == [{"id" : 1 , "name" : "Alice" }]
409+ assert d ["ai_response" ] == "Found 1 customer"
410+ assert d ["is_destructive" ] is False
411+ assert d ["requires_confirmation" ] is False
412+ assert d ["execution_time" ] == 0.5
227413
228414 def test_schema_result_to_dict (self ):
229415 """Test SchemaResult serialization."""
@@ -236,7 +422,10 @@ def test_schema_result_to_dict(self):
236422
237423 d = result .to_dict ()
238424 assert len (d ["nodes" ]) == 1
425+ assert d ["nodes" ][0 ]["name" ] == "customers"
239426 assert len (d ["links" ]) == 1
427+ assert d ["links" ][0 ]["source" ] == "orders"
428+ assert d ["links" ][0 ]["target" ] == "customers"
240429
241430 def test_database_connection_to_dict (self ):
242431 """Test DatabaseConnection serialization."""
@@ -253,3 +442,41 @@ def test_database_connection_to_dict(self):
253442 assert d ["database_id" ] == "testdb"
254443 assert d ["success" ] is True
255444 assert d ["tables_loaded" ] == 5
445+ assert d ["message" ] == "Connected successfully"
446+
447+ def test_query_result_default_values (self ):
448+ """Test QueryResult with minimal required values."""
449+ from queryweaver_sdk .models import QueryResult
450+
451+ result = QueryResult (
452+ sql_query = "SELECT 1" ,
453+ results = [],
454+ ai_response = "Test" ,
455+ confidence = 0.8 ,
456+ )
457+
458+ # Check defaults for optional fields
459+ assert result .is_destructive is False
460+ assert result .requires_confirmation is False
461+ assert result .execution_time == 0.0
462+ assert result .is_valid is True
463+ assert result .missing_information == ""
464+ assert result .ambiguities == ""
465+ assert result .explanation == ""
466+
467+ def test_database_connection_failure (self ):
468+ """Test DatabaseConnection for failed connection."""
469+ from queryweaver_sdk .models import DatabaseConnection
470+
471+ result = DatabaseConnection (
472+ database_id = "" ,
473+ success = False ,
474+ tables_loaded = 0 ,
475+ message = "Connection refused" ,
476+ )
477+
478+ d = result .to_dict ()
479+ assert d ["database_id" ] == ""
480+ assert d ["success" ] is False
481+ assert d ["tables_loaded" ] == 0
482+ assert "refused" in d ["message" ].lower ()
0 commit comments