@@ -738,7 +738,7 @@ defmodule Ecto.Adapters.LibSql.Connection do
738738 { join , wheres } = using_join ( query , :update_all , "FROM" , sources )
739739 where = where ( % { query | wheres: wheres } , sources )
740740
741- [ "UPDATE " , from , " AS " , name , " SET " , fields , join , where ]
741+ [ "UPDATE " , from , " AS " , name , " SET " , fields , join , where | returning ( query , sources ) ]
742742 end
743743
744744 @ impl true
@@ -749,7 +749,7 @@ defmodule Ecto.Adapters.LibSql.Connection do
749749 { join , wheres } = using_join ( query , :delete_all , "USING" , sources )
750750 where = where ( % { query | wheres: wheres } , sources )
751751
752- [ "DELETE FROM " , from , " AS " , name , join , where ]
752+ [ "DELETE FROM " , from , " AS " , name , join , where | returning ( query , sources ) ]
753753 end
754754
755755 @ impl true
@@ -1359,6 +1359,53 @@ defmodule Ecto.Adapters.LibSql.Connection do
13591359 [ " RETURNING " | intersperse_map ( returning , ?, , & quote_name / 1 ) ]
13601360 end
13611361
1362+ # Generate RETURNING clause from query select (for update_all/delete_all).
1363+ # Returns empty list if no select clause is present.
1364+ defp returning ( % { select: nil } , _sources ) , do: [ ]
1365+
1366+ defp returning ( % { select: % { fields: fields } } = query , sources ) do
1367+ [ " RETURNING " | returning_fields ( fields , sources , query ) ]
1368+ end
1369+
1370+ # Format fields for RETURNING clause.
1371+ # SQLite's RETURNING clause doesn't support table aliases, so we use bare column names.
1372+ defp returning_fields ( [ ] , _sources , _query ) , do: [ "1" ]
1373+
1374+ defp returning_fields ( fields , sources , query ) do
1375+ intersperse_map ( fields , ", " , fn
1376+ { :& , _ , [ idx ] } ->
1377+ # Selecting all fields from a source - list all schema fields.
1378+ { _source , _name , schema } = elem ( sources , idx )
1379+
1380+ if schema do
1381+ Enum . map_join ( schema . __schema__ ( :fields ) , ", " , & quote_name / 1 )
1382+ else
1383+ "*"
1384+ end
1385+
1386+ { key , value } when is_atom ( key ) ->
1387+ # Key-value pair (for maps) - return as "expr AS key".
1388+ # Use returning_expr to avoid table aliases.
1389+ [ returning_expr ( value , sources , query ) , " AS " , quote_name ( key ) ]
1390+
1391+ value ->
1392+ returning_expr ( value , sources , query )
1393+ end )
1394+ end
1395+
1396+ # Generate expressions for RETURNING clause without table aliases.
1397+ # SQLite doesn't support table aliases in RETURNING.
1398+ defp returning_expr ( { { :. , _ , [ { :& , _ , [ _idx ] } , field ] } , _ , [ ] } , _sources , _query )
1399+ when is_atom ( field ) do
1400+ # Simple field reference like u.name - return just the quoted field name.
1401+ quote_name ( field )
1402+ end
1403+
1404+ defp returning_expr ( value , sources , query ) do
1405+ # For other expressions, fall back to the normal expr function.
1406+ expr ( value , sources , query )
1407+ end
1408+
13621409 defp intersperse_map ( list , separator , mapper ) do
13631410 intersperse_map ( list , separator , mapper , [ ] )
13641411 end
0 commit comments