@@ -1310,7 +1310,98 @@ defmodule AshPostgres.DataLayer do
1310
1310
end
1311
1311
end
1312
1312
1313
- defp bulk_updatable_query ( query , resource , atomics , calculations , context ) do
1313
+ defp bulk_updatable_query ( query , resource , atomics , calculations , context , type \\ :update ) do
1314
+ requires_adding_inner_join? =
1315
+ case type do
1316
+ :update ->
1317
+ # could potentially optimize this to avoid the subquery by shuffling free
1318
+ # inner joins to the top of the query
1319
+ has_inner_join_to_start? =
1320
+ case Enum . at ( query . joins , 0 ) do
1321
+ nil ->
1322
+ false
1323
+
1324
+ % { qual: :inner } ->
1325
+ true
1326
+
1327
+ _ ->
1328
+ false
1329
+ end
1330
+
1331
+ cond do
1332
+ has_inner_join_to_start? ->
1333
+ false
1334
+
1335
+ Enum . any? ( query . joins , & ( & 1 . qual != :inner ) ) ->
1336
+ true
1337
+
1338
+ Enum . any? ( atomics ++ calculations , fn { _ , expr } ->
1339
+ Ash.Filter . list_refs ( expr ) |> Enum . any? ( & ( & 1 . relationship_path != [ ] ) )
1340
+ end ) ->
1341
+ true
1342
+
1343
+ true ->
1344
+ false
1345
+ end
1346
+
1347
+ :destroy ->
1348
+ Enum . any? ( query . joins , & ( & 1 . qual != :inner ) ) ||
1349
+ Enum . any? ( atomics ++ calculations , fn { _ , expr } ->
1350
+ expr |> Ash.Filter . list_refs ( ) |> Enum . any? ( & ( & 1 . relationship_path != [ ] ) )
1351
+ end )
1352
+ end
1353
+
1354
+ needs_to_join? =
1355
+ requires_adding_inner_join? ||
1356
+ query . limit || query . offset
1357
+
1358
+ query =
1359
+ if needs_to_join? do
1360
+ root_query = Ecto.Query . exclude ( query , :select )
1361
+
1362
+ root_query =
1363
+ cond do
1364
+ query . limit || query . offset ->
1365
+ from ( row in Ecto.Query . subquery ( root_query ) , [ ] )
1366
+
1367
+ ! Enum . empty? ( query . joins ) ->
1368
+ from ( row in Ecto.Query . subquery ( Ecto.Query . exclude ( root_query , :order_by ) ) , [ ] )
1369
+
1370
+ true ->
1371
+ Ecto.Query . exclude ( root_query , :order_by )
1372
+ end
1373
+
1374
+ dynamic =
1375
+ Enum . reduce ( Ash.Resource.Info . primary_key ( resource ) , nil , fn pkey , dynamic ->
1376
+ if dynamic do
1377
+ Ecto.Query . dynamic (
1378
+ [ row , joining ] ,
1379
+ field ( row , ^ pkey ) == field ( joining , ^ pkey ) and ^ dynamic
1380
+ )
1381
+ else
1382
+ Ecto.Query . dynamic ( [ row , joining ] , field ( row , ^ pkey ) == field ( joining , ^ pkey ) )
1383
+ end
1384
+ end )
1385
+
1386
+ faked_query =
1387
+ from ( row in query . from . source ,
1388
+ inner_join: limiter in ^ root_query ,
1389
+ as: ^ 0 ,
1390
+ on: ^ dynamic
1391
+ )
1392
+ |> AshSql.Bindings . default_bindings (
1393
+ query . __ash_bindings__ . resource ,
1394
+ AshPostgres.SqlImplementation ,
1395
+ context
1396
+ )
1397
+
1398
+ faked_query
1399
+ else
1400
+ query
1401
+ |> Ecto.Query . exclude ( :select )
1402
+ |> Ecto.Query . exclude ( :order_by )
1403
+ end
1404
+
1314
1405
Enum . reduce_while ( atomics ++ calculations , { :ok , query } , fn { _ , expr } , { :ok , query } ->
1315
1406
used_aggregates =
1316
1407
Ash.Filter . used_aggregates ( expr , [ ] )
@@ -1332,53 +1423,6 @@ defmodule AshPostgres.DataLayer do
1332
1423
{ :halt , { :error , error } }
1333
1424
end
1334
1425
end )
1335
- |> case do
1336
- { :ok , query } ->
1337
- needs_to_join? =
1338
- Enum . any? ( query . joins , & ( & 1 . qual != :inner ) ) || query . limit || query . offset
1339
-
1340
- if needs_to_join? do
1341
- root_query = Ecto.Query . exclude ( query , :select )
1342
-
1343
- root_query =
1344
- if query . limit || query . offset do
1345
- Map . put ( root_query , :order_bys , query . order_bys )
1346
- else
1347
- Ecto.Query . exclude ( root_query , :order_by )
1348
- end
1349
-
1350
- dynamic =
1351
- Enum . reduce ( Ash.Resource.Info . primary_key ( resource ) , nil , fn pkey , dynamic ->
1352
- if dynamic do
1353
- Ecto.Query . dynamic (
1354
- [ row , joining ] ,
1355
- field ( row , ^ pkey ) == field ( joining , ^ pkey ) and ^ dynamic
1356
- )
1357
- else
1358
- Ecto.Query . dynamic ( [ row , joining ] , field ( row , ^ pkey ) == field ( joining , ^ pkey ) )
1359
- end
1360
- end )
1361
-
1362
- faked_query =
1363
- from ( row in query . from . source ,
1364
- inner_join: limiter in ^ subquery ( root_query ) ,
1365
- as: ^ 0 ,
1366
- on: ^ dynamic
1367
- )
1368
- |> Map . put ( :__ash_bindings__ , query . __ash_bindings__ )
1369
-
1370
- { :ok , faked_query }
1371
- else
1372
- { :ok ,
1373
- query
1374
- |> AshSql.Bindings . default_bindings ( resource , AshPostgres.SqlImplementation , context )
1375
- |> Ecto.Query . exclude ( :select )
1376
- |> Ecto.Query . exclude ( :order_by ) }
1377
- end
1378
-
1379
- { :error , error } ->
1380
- { :error , error }
1381
- end
1382
1426
end
1383
1427
1384
1428
@ impl true
@@ -1399,7 +1443,8 @@ defmodule AshPostgres.DataLayer do
1399
1443
resource ,
1400
1444
changeset . atomics ,
1401
1445
options [ :calculations ] || [ ] ,
1402
- changeset . context
1446
+ changeset . context ,
1447
+ :destroy
1403
1448
) do
1404
1449
{ :error , error } ->
1405
1450
{ :error , error }
0 commit comments