1313- Edge cases and error conditions
1414"""
1515
16-
1716from sqlspec import sql
1817
1918
@@ -64,11 +63,13 @@ def test_where_any_uses_column_name_with_any_suffix() -> None:
6463
6564def test_multiple_where_conditions_preserve_column_names () -> None :
6665 """Test that multiple WHERE conditions preserve individual column names."""
67- query = (sql .select ("*" )
68- .from_ ("orders" )
69- .where_eq ("status" , "pending" )
70- .where_gt ("total" , 100.0 )
71- .where_like ("customer_email" , "%@company.com" ))
66+ query = (
67+ sql .select ("*" )
68+ .from_ ("orders" )
69+ .where_eq ("status" , "pending" )
70+ .where_gt ("total" , 100.0 )
71+ .where_like ("customer_email" , "%@company.com" )
72+ )
7273 stmt = query .build ()
7374
7475 assert "status" in stmt .parameters
@@ -81,10 +82,7 @@ def test_multiple_where_conditions_preserve_column_names() -> None:
8182
8283def test_parameter_collision_handling () -> None :
8384 """Test that parameter name collisions are resolved with numbering."""
84- query = (sql .select ("*" )
85- .from_ ("products" )
86- .where_gt ("price" , 10 )
87- .where_lt ("price" , 100 ))
85+ query = sql .select ("*" ).from_ ("products" ).where_gt ("price" , 10 ).where_lt ("price" , 100 )
8886 stmt = query .build ()
8987
9088 # Should have both price parameters with collision resolution
@@ -100,11 +98,13 @@ def test_parameter_collision_handling() -> None:
10098
10199def test_table_prefixed_columns_extract_column_name () -> None :
102100 """Test that table-prefixed columns extract just the column name."""
103- query = (sql .select ("*" )
104- .from_ ("users u" )
105- .join ("profiles p" , "u.id = p.user_id" )
106- .
where_eq (
"u.email" ,
"[email protected] " )
107- .where_eq ("p.status" , "active" ))
101+ query = (
102+ sql .select ("*" )
103+ .from_ ("users u" )
104+ .join ("profiles p" , "u.id = p.user_id" )
105+ .
where_eq (
"u.email" ,
"[email protected] " )
106+ .where_eq ("p.status" , "active" )
107+ )
108108 stmt = query .build ()
109109
110110 # Should extract column names without table prefix
@@ -126,10 +126,7 @@ def test_update_set_single_column_uses_column_name() -> None:
126126
127127def test_update_set_multiple_columns_preserve_names () -> None :
128128 """Test that UPDATE SET with multiple columns preserves all names."""
129- query = (sql .update ("products" )
130- .set ("name" , "Updated Product" )
131- .set ("price" , 49.99 )
132- .set ("in_stock" , True ))
129+ query = sql .update ("products" ).set ("name" , "Updated Product" ).set ("price" , 49.99 ).set ("in_stock" , True )
133130 stmt = query .build ()
134131
135132 assert "name" in stmt .parameters
@@ -142,11 +139,7 @@ def test_update_set_multiple_columns_preserve_names() -> None:
142139
143140def test_update_set_with_dict_uses_column_names () -> None :
144141 """Test that UPDATE SET with dictionary uses column names."""
145- query = sql .update ("accounts" ).set ({
146- "balance" : 1500.75 ,
147- "last_transaction" : "2023-01-15" ,
148- "is_verified" : True
149- })
142+ query = sql .update ("accounts" ).set ({"balance" : 1500.75 , "last_transaction" : "2023-01-15" , "is_verified" : True })
150143 stmt = query .build ()
151144
152145 # Should use dictionary keys as parameter names
@@ -163,9 +156,9 @@ def test_update_set_with_dict_uses_column_names() -> None:
163156
164157def test_insert_with_columns_uses_column_names () -> None :
165158 """Test that INSERT with specified columns uses column names."""
166- query = (sql . insert ( "employees" )
167- . columns ("first_name" , "last_name" , "department" )
168- . values ( "John" , "Smith" , "Engineering" ) )
159+ query = (
160+ sql . insert ( "employees" ). columns ("first_name" , "last_name" , "department" ). values ( "John" , "Smith" , "Engineering " )
161+ )
169162 stmt = query .build ()
170163
171164 # Should use column names for parameters
@@ -179,31 +172,29 @@ def test_insert_with_columns_uses_column_names() -> None:
179172
180173def test_insert_values_from_dict_preserves_keys () -> None :
181174 """Test that INSERT values_from_dict preserves dictionary keys."""
182- query = sql .insert ("orders" ).values_from_dict ({
183- "customer_id" : 12345 ,
184- "product_name" : "Widget" ,
185- "quantity" : 3 ,
186- "order_date" : "2023-01-01"
187- })
175+ query = sql .insert ("orders" ).values_from_dict (
176+ {"customer_id" : 12345 , "product_name" : "Widget" , "quantity" : 3 , "order_date" : "2023-01-01" }
177+ )
188178 stmt = query .build ()
189179
190180 # Should preserve dictionary keys in parameter names
191181 expected_keys = ["customer_id" , "product_name" , "quantity" , "order_date" ]
192182 for key in expected_keys :
193183 # Check if key exists directly or as part of parameter name
194- assert (key in stmt .parameters or
195- any (key in param_key for param_key in stmt .parameters .keys ()))
184+ assert key in stmt .parameters or any (key in param_key for param_key in stmt .parameters .keys ())
196185
197186
198187def test_complex_query_preserves_all_column_names () -> None :
199188 """Test that complex queries preserve column names across all operations."""
200- query = (sql .select ("u.username" , "p.title" )
201- .from_ ("users u" )
202- .join ("posts p" , "u.id = p.author_id" )
203- .where_eq ("u.status" , "active" )
204- .where_in ("p.category" , ["tech" , "science" ])
205- .where_between ("p.views" , 100 , 10000 )
206- .where_like ("p.title" , "%python%" ))
189+ query = (
190+ sql .select ("u.username" , "p.title" )
191+ .from_ ("users u" )
192+ .join ("posts p" , "u.id = p.author_id" )
193+ .where_eq ("u.status" , "active" )
194+ .where_in ("p.category" , ["tech" , "science" ])
195+ .where_between ("p.views" , 100 , 10000 )
196+ .where_like ("p.title" , "%python%" )
197+ )
207198 stmt = query .build ()
208199
209200 params = stmt .parameters
@@ -233,9 +224,7 @@ def test_subquery_parameters_are_preserved() -> None:
233224 """Test that subquery parameters maintain their names."""
234225 subquery = sql .select ("user_id" ).from_ ("subscriptions" ).where_eq ("plan_type" , "premium" )
235226
236- query = (sql .select ("name" , "email" )
237- .from_ ("users" )
238- .where_in ("id" , subquery ))
227+ query = sql .select ("name" , "email" ).from_ ("users" ).where_in ("id" , subquery )
239228 stmt = query .build ()
240229
241230 # Subquery parameter should be preserved
@@ -245,15 +234,19 @@ def test_subquery_parameters_are_preserved() -> None:
245234
246235def test_mixed_parameter_types_preserve_names () -> None :
247236 """Test that mixed parameter types preserve proper column names."""
248- query = (sql .update ("user_profiles" )
249- .set ({
250- "username" : "john_doe" , # string
251- "age" : 28 , # int
252- "salary" : 75000.50 , # float
253- "is_active" : True , # bool
254- "last_seen" : None # None
255- })
256- .where_eq ("user_id" , 12345 ))
237+ query = (
238+ sql .update ("user_profiles" )
239+ .set (
240+ {
241+ "username" : "john_doe" , # string
242+ "age" : 28 , # int
243+ "salary" : 75000.50 , # float
244+ "is_active" : True , # bool
245+ "last_seen" : None , # None
246+ }
247+ )
248+ .where_eq ("user_id" , 12345 )
249+ )
257250 stmt = query .build ()
258251
259252 params = stmt .parameters
@@ -323,10 +316,9 @@ def test_no_generic_param_names_in_insert_operations() -> None:
323316
324317def test_parameter_names_are_sql_safe () -> None :
325318 """Test that generated parameter names are safe for SQL usage."""
326- query = (sql .select ("*" )
327- .from_ ("test_table" )
328- .where_eq ("column_name" , "value" )
329- .where_in ("other_column" , ["a" , "b" , "c" ]))
319+ query = (
320+ sql .select ("*" ).from_ ("test_table" ).where_eq ("column_name" , "value" ).where_in ("other_column" , ["a" , "b" , "c" ])
321+ )
330322 stmt = query .build ()
331323
332324 for param_name in stmt .parameters .keys ():
@@ -342,13 +334,17 @@ def test_parameter_names_are_sql_safe() -> None:
342334
343335def test_empty_and_null_values_preserve_column_names () -> None :
344336 """Test that empty and null values still preserve column names."""
345- query = (sql .update ("users" )
346- .set ({
347- "middle_name" : "" , # empty string
348- "phone" : None , # null
349- "notes" : " " , # whitespace
350- })
351- .where_eq ("id" , 1 ))
337+ query = (
338+ sql .update ("users" )
339+ .set (
340+ {
341+ "middle_name" : "" , # empty string
342+ "phone" : None , # null
343+ "notes" : " " , # whitespace
344+ }
345+ )
346+ .where_eq ("id" , 1 )
347+ )
352348 stmt = query .build ()
353349
354350 params = stmt .parameters
@@ -367,9 +363,7 @@ def test_empty_and_null_values_preserve_column_names() -> None:
367363
368364def test_original_user_example_works_correctly () -> None :
369365 """Test the exact user example that was originally failing."""
370- query = (sql .select ("id" , "name" , "slug" )
371- .from_ ("test_table" )
372- .where_eq ("slug" , "test-item" ))
366+ query = sql .select ("id" , "name" , "slug" ).from_ ("test_table" ).where_eq ("slug" , "test-item" )
373367 stmt = query .build ()
374368
375369 # Should use :slug parameter, not :param_1
@@ -383,10 +377,12 @@ def test_original_user_example_works_correctly() -> None:
383377
384378def test_parameter_naming_with_special_characters_in_values () -> None :
385379 """Test that parameter naming works with special characters in values."""
386- query = (sql .select ("*" )
387- .from_ ("logs" )
388- .where_eq ("message" , "Error: Connection failed!" )
389- .where_like ("details" , "%SQL injection attempt: DROP TABLE%" ))
380+ query = (
381+ sql .select ("*" )
382+ .from_ ("logs" )
383+ .where_eq ("message" , "Error: Connection failed!" )
384+ .where_like ("details" , "%SQL injection attempt: DROP TABLE%" )
385+ )
390386 stmt = query .build ()
391387
392388 # Should preserve column names despite special characters in values
0 commit comments