@@ -208,25 +208,35 @@ def test_properties(self):
208208 self .cursor .arraysize = 10
209209 self .assertEqual (self .cursor .arraysize , 10 )
210210
211- @patch ("psqlpy_sqlalchemy.connection.await_only" )
212- def test_execute (self , mock_await_only ):
211+ @patch .object (
212+ AsyncAdapt_psqlpy_cursor , "_prepare_execute" , new_callable = AsyncMock
213+ )
214+ def test_execute (self , mock_prepare_execute ):
213215 """Test cursor execute method"""
214216 operation = "SELECT * FROM table"
215217 parameters = {"id" : 123 }
216218
217- self .cursor .execute (operation , parameters )
219+ # Since execute is now async, we need to run it in an async context
220+ import asyncio
218221
219- mock_await_only . assert_called_once ( )
222+ asyncio . run ( self . cursor . execute ( operation , parameters ) )
220223
221- @patch ("psqlpy_sqlalchemy.connection.await_only" )
222- def test_executemany (self , mock_await_only ):
224+ mock_prepare_execute .assert_called_once_with (operation , parameters )
225+
226+ @patch .object (
227+ AsyncAdapt_psqlpy_cursor , "_executemany" , new_callable = AsyncMock
228+ )
229+ def test_executemany (self , mock_executemany ):
223230 """Test cursor executemany method"""
224231 operation = "INSERT INTO table VALUES ($1, $2)"
225232 seq_of_parameters = [[1 , "a" ], [2 , "b" ]]
226233
227- self .cursor .executemany (operation , seq_of_parameters )
234+ # Since executemany is now async, we need to run it in an async context
235+ import asyncio
236+
237+ asyncio .run (self .cursor .executemany (operation , seq_of_parameters ))
228238
229- mock_await_only . assert_called_once ( )
239+ mock_executemany . assert_called_once_with ( operation , seq_of_parameters )
230240
231241 def test_setinputsizes (self ):
232242 """Test setinputsizes method raises NotImplementedError"""
@@ -288,15 +298,185 @@ def test_convert_named_params_remaining_matches(self):
288298
289299 self .assertIn ("Conversion incomplete" , str (cm .exception ))
290300
291- def test_executemany_coverage (self ):
301+ @patch .object (
302+ AsyncAdapt_psqlpy_cursor , "_executemany" , new_callable = AsyncMock
303+ )
304+ def test_executemany_coverage (self , mock_executemany ):
292305 """Test executemany method for coverage"""
293306 operation = "INSERT INTO test VALUES ($1, $2)"
294307 seq_of_parameters = [[1 , "a" ], [2 , "b" ]]
295308
296- # Test the sync wrapper by mocking await_only
297- with patch ("psqlpy_sqlalchemy.connection.await_only" ) as mock_await :
298- self .cursor .executemany (operation , seq_of_parameters )
299- mock_await .assert_called_once ()
309+ # Since executemany is now async, we need to run it in an async context
310+ import asyncio
311+
312+ asyncio .run (self .cursor .executemany (operation , seq_of_parameters ))
313+
314+ mock_executemany .assert_called_once_with (operation , seq_of_parameters )
315+
316+ # UPDATE operation tests
317+ @patch .object (
318+ AsyncAdapt_psqlpy_cursor , "_prepare_execute" , new_callable = AsyncMock
319+ )
320+ def test_execute_update_basic (self , mock_prepare_execute ):
321+ """Test basic UPDATE operation with execute method"""
322+ operation = "UPDATE users SET name = 'John' WHERE id = 1"
323+
324+ import asyncio
325+
326+ asyncio .run (self .cursor .execute (operation ))
327+
328+ mock_prepare_execute .assert_called_once_with (operation , None )
329+
330+ @patch .object (
331+ AsyncAdapt_psqlpy_cursor , "_prepare_execute" , new_callable = AsyncMock
332+ )
333+ def test_execute_update_with_named_parameters (self , mock_prepare_execute ):
334+ """Test UPDATE operation with named parameters"""
335+ operation = (
336+ "UPDATE users SET name = :name, email = :email WHERE id = :id"
337+ )
338+ parameters = {"name" : "John Doe" , "email" : "john@example.com" , "id" : 1 }
339+
340+ import asyncio
341+
342+ asyncio .run (self .cursor .execute (operation , parameters ))
343+
344+ mock_prepare_execute .assert_called_once_with (operation , parameters )
345+
346+ @patch .object (
347+ AsyncAdapt_psqlpy_cursor , "_prepare_execute" , new_callable = AsyncMock
348+ )
349+ def test_execute_update_with_positional_parameters (
350+ self , mock_prepare_execute
351+ ):
352+ """Test UPDATE operation with positional parameters"""
353+ operation = "UPDATE users SET name = $1, email = $2 WHERE id = $3"
354+ parameters = ["John Doe" , "john@example.com" , 1 ]
355+
356+ import asyncio
357+
358+ asyncio .run (self .cursor .execute (operation , parameters ))
359+
360+ mock_prepare_execute .assert_called_once_with (operation , parameters )
361+
362+ @patch .object (
363+ AsyncAdapt_psqlpy_cursor , "_prepare_execute" , new_callable = AsyncMock
364+ )
365+ def test_execute_update_multiple_columns (self , mock_prepare_execute ):
366+ """Test UPDATE operation with multiple columns"""
367+ operation = "UPDATE users SET name = :name, email = :email, age = :age, updated_at = NOW() WHERE id = :id"
368+ parameters = {
369+ "name" : "Jane Smith" ,
370+ "email" : "jane@example.com" ,
371+ "age" : 30 ,
372+ "id" : 2 ,
373+ }
374+
375+ import asyncio
376+
377+ asyncio .run (self .cursor .execute (operation , parameters ))
378+
379+ mock_prepare_execute .assert_called_once_with (operation , parameters )
380+
381+ @patch .object (
382+ AsyncAdapt_psqlpy_cursor , "_prepare_execute" , new_callable = AsyncMock
383+ )
384+ def test_execute_update_with_where_clause (self , mock_prepare_execute ):
385+ """Test UPDATE operation with complex WHERE clause"""
386+ operation = "UPDATE users SET status = :status WHERE age > :min_age AND created_at < :date"
387+ parameters = {"status" : "active" , "min_age" : 18 , "date" : "2023-01-01" }
388+
389+ import asyncio
390+
391+ asyncio .run (self .cursor .execute (operation , parameters ))
392+
393+ mock_prepare_execute .assert_called_once_with (operation , parameters )
394+
395+ @patch .object (
396+ AsyncAdapt_psqlpy_cursor , "_executemany" , new_callable = AsyncMock
397+ )
398+ def test_executemany_update_operations (self , mock_executemany ):
399+ """Test UPDATE operations with executemany method"""
400+ operation = "UPDATE users SET name = $1, email = $2 WHERE id = $3"
401+ seq_of_parameters = [
402+ ["John Doe" , "john@example.com" , 1 ],
403+ ["Jane Smith" , "jane@example.com" , 2 ],
404+ ["Bob Johnson" , "bob@example.com" , 3 ],
405+ ]
406+
407+ import asyncio
408+
409+ asyncio .run (self .cursor .executemany (operation , seq_of_parameters ))
410+
411+ mock_executemany .assert_called_once_with (operation , seq_of_parameters )
412+
413+ @patch .object (
414+ AsyncAdapt_psqlpy_cursor , "_executemany" , new_callable = AsyncMock
415+ )
416+ def test_executemany_update_with_dict_parameters (self , mock_executemany ):
417+ """Test UPDATE operations with executemany using dict parameters"""
418+ operation = "UPDATE users SET name = :name WHERE id = :id"
419+ seq_of_parameters = [
420+ {"name" : "John Updated" , "id" : 1 },
421+ {"name" : "Jane Updated" , "id" : 2 },
422+ ]
423+
424+ import asyncio
425+
426+ asyncio .run (self .cursor .executemany (operation , seq_of_parameters ))
427+
428+ mock_executemany .assert_called_once_with (operation , seq_of_parameters )
429+
430+ @patch .object (
431+ AsyncAdapt_psqlpy_cursor , "_prepare_execute" , new_callable = AsyncMock
432+ )
433+ def test_execute_update_with_uuid_parameter (self , mock_prepare_execute ):
434+ """Test UPDATE operation with UUID parameter (tests the async fix)"""
435+ test_uuid = uuid .uuid4 ()
436+ operation = "UPDATE users SET profile_id = :profile_id WHERE id = :id"
437+ parameters = {"profile_id" : test_uuid , "id" : 1 }
438+
439+ import asyncio
440+
441+ asyncio .run (self .cursor .execute (operation , parameters ))
442+
443+ mock_prepare_execute .assert_called_once_with (operation , parameters )
444+
445+ @patch .object (
446+ AsyncAdapt_psqlpy_cursor , "_prepare_execute" , new_callable = AsyncMock
447+ )
448+ def test_execute_update_async_greenlet_fix (self , mock_prepare_execute ):
449+ """Test that UPDATE operations work with the async/greenlet fix"""
450+ # This test specifically verifies that the async fix works for UPDATE operations
451+ # that were causing the original greenlet switching issue
452+ operation = "UPDATE test_table SET name = :name WHERE id = :id"
453+ parameters = {"name" : "test_update" , "id" : 1 }
454+
455+ import asyncio
456+
457+ # This should not raise any greenlet-related errors
458+ asyncio .run (self .cursor .execute (operation , parameters ))
459+
460+ mock_prepare_execute .assert_called_once_with (operation , parameters )
461+
462+ # Verify that the method was called without await_only issues
463+ self .assertTrue (mock_prepare_execute .called )
464+
465+ @patch .object (
466+ AsyncAdapt_psqlpy_cursor , "_prepare_execute" , new_callable = AsyncMock
467+ )
468+ def test_execute_update_with_null_values (self , mock_prepare_execute ):
469+ """Test UPDATE operation with NULL values"""
470+ operation = (
471+ "UPDATE users SET email = :email, phone = :phone WHERE id = :id"
472+ )
473+ parameters = {"email" : None , "phone" : None , "id" : 1 }
474+
475+ import asyncio
476+
477+ asyncio .run (self .cursor .execute (operation , parameters ))
478+
479+ mock_prepare_execute .assert_called_once_with (operation , parameters )
300480
301481
302482class TestAsyncAdaptPsqlpySSCursor (unittest .TestCase ):
0 commit comments