Skip to content

Commit b4be28e

Browse files
committed
fix: use data from result for properly atomic transfer verification
1 parent 75fdb15 commit b4be28e

File tree

5 files changed

+163
-4
lines changed

5 files changed

+163
-4
lines changed

lib/transfer/changes/verify_transfer.ex

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@ defmodule AshDoubleEntry.Transfer.Changes.VerifyTransfer do
5151
end
5252
|> maybe_destroy_balances(context)
5353
|> Ash.Changeset.after_action(fn changeset, result ->
54-
from_account_id = Ash.Changeset.get_attribute(changeset, :from_account_id)
55-
to_account_id = Ash.Changeset.get_attribute(changeset, :to_account_id)
56-
new_amount = Ash.Changeset.get_attribute(changeset, :amount)
54+
from_account_id = result.from_account_id
55+
to_account_id = result.to_account_id
56+
new_amount = result.amount
5757

5858
old_amount =
5959
if changeset.action.type == :destroy do

test/ash_double_entry_test.exs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,11 @@ defmodule AshDoubleEntryTest do
271271
Ash.destroy!(transfer_2)
272272
end
273273

274+
# we test atomic destroy here
274275
assert_raise Ash.Error.Invalid, ~r/balance cannot be negative/, fn ->
275-
Ash.destroy!(transfer_3)
276+
Transfer
277+
|> Ash.Query.filter(id == ^transfer_3.id)
278+
|> Ash.bulk_destroy!(:destroy, %{}, return_errors?: true)
276279
end
277280

278281
Ash.destroy!(transfer_4)

test/support/balance.ex

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ defmodule AshDoubleEntry.Test.Balance do
4141
postgres do
4242
table "balances"
4343
repo(AshDoubleEntry.Test.Repo)
44+
45+
references do
46+
reference(:transfer, on_delete: :delete)
47+
end
4448
end
4549

4650
balance do
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
defmodule AshDoubleEntry.Test.Repo.Migrations.DeleteBalances do
2+
@moduledoc """
3+
Updates resources based on their most recent snapshots.
4+
5+
This file was autogenerated with `mix ash_postgres.generate_migrations`
6+
"""
7+
8+
use Ecto.Migration
9+
10+
def up do
11+
drop(constraint(:balances, "balances_transfer_id_fkey"))
12+
13+
alter table(:balances) do
14+
modify(
15+
:transfer_id,
16+
references(:transfers,
17+
column: :id,
18+
name: "balances_transfer_id_fkey",
19+
type: :binary,
20+
on_delete: :delete_all
21+
)
22+
)
23+
end
24+
end
25+
26+
def down do
27+
drop(constraint(:balances, "balances_transfer_id_fkey"))
28+
29+
alter table(:balances) do
30+
modify(
31+
:transfer_id,
32+
references(:transfers, column: :id, name: "balances_transfer_id_fkey", type: :binary)
33+
)
34+
end
35+
end
36+
end
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
{
2+
"attributes": [
3+
{
4+
"allow_nil?": false,
5+
"default": "fragment(\"gen_random_uuid()\")",
6+
"generated?": true,
7+
"primary_key?": true,
8+
"references": null,
9+
"size": null,
10+
"source": "id",
11+
"type": "uuid"
12+
},
13+
{
14+
"allow_nil?": false,
15+
"default": "nil",
16+
"generated?": false,
17+
"primary_key?": false,
18+
"references": null,
19+
"size": null,
20+
"source": "balance",
21+
"type": "money_with_currency"
22+
},
23+
{
24+
"allow_nil?": false,
25+
"default": "nil",
26+
"generated?": false,
27+
"primary_key?": false,
28+
"references": {
29+
"deferrable": false,
30+
"destination_attribute": "id",
31+
"destination_attribute_default": null,
32+
"destination_attribute_generated": null,
33+
"index?": false,
34+
"match_type": null,
35+
"match_with": null,
36+
"multitenancy": {
37+
"attribute": null,
38+
"global": null,
39+
"strategy": null
40+
},
41+
"name": "balances_transfer_id_fkey",
42+
"on_delete": "delete",
43+
"on_update": null,
44+
"primary_key?": true,
45+
"schema": null,
46+
"table": "transfers"
47+
},
48+
"size": null,
49+
"source": "transfer_id",
50+
"type": "binary"
51+
},
52+
{
53+
"allow_nil?": false,
54+
"default": "nil",
55+
"generated?": false,
56+
"primary_key?": false,
57+
"references": {
58+
"deferrable": false,
59+
"destination_attribute": "id",
60+
"destination_attribute_default": null,
61+
"destination_attribute_generated": null,
62+
"index?": false,
63+
"match_type": null,
64+
"match_with": null,
65+
"multitenancy": {
66+
"attribute": null,
67+
"global": null,
68+
"strategy": null
69+
},
70+
"name": "balances_account_id_fkey",
71+
"on_delete": null,
72+
"on_update": null,
73+
"primary_key?": true,
74+
"schema": null,
75+
"table": "accounts"
76+
},
77+
"size": null,
78+
"source": "account_id",
79+
"type": "uuid"
80+
}
81+
],
82+
"base_filter": null,
83+
"check_constraints": [],
84+
"custom_indexes": [],
85+
"custom_statements": [],
86+
"has_create_action": true,
87+
"hash": "71F6146A6CB681A42EFEB7E1DC739CA5BA76B42680273779E1C4AB2DECF656EA",
88+
"identities": [
89+
{
90+
"all_tenants?": false,
91+
"base_filter": null,
92+
"index_name": "balances_unique_references_index",
93+
"keys": [
94+
{
95+
"type": "atom",
96+
"value": "account_id"
97+
},
98+
{
99+
"type": "atom",
100+
"value": "transfer_id"
101+
}
102+
],
103+
"name": "unique_references",
104+
"nils_distinct?": true,
105+
"where": null
106+
}
107+
],
108+
"multitenancy": {
109+
"attribute": null,
110+
"global": null,
111+
"strategy": null
112+
},
113+
"repo": "Elixir.AshDoubleEntry.Test.Repo",
114+
"schema": null,
115+
"table": "balances"
116+
}

0 commit comments

Comments
 (0)