Switch token_transfers to composite primary key

* Drop id.
* Make (transaaction_hash, log_index) the primary key.

This ports the change from `internal_transactions`.
pull/985/head
Luke Imhoff 6 years ago
parent 92264a59e2
commit 7f7cdf753d
  1. 2
      apps/explorer/lib/explorer/chain.ex
  2. 12
      apps/explorer/lib/explorer/chain/token_transfer.ex
  3. 22
      apps/explorer/priv/repo/migrations/20181024172010_token_transfers_composite_primary_key.exs
  4. 15
      apps/explorer/test/explorer/chain/token_transfer_test.exs
  5. 36
      apps/explorer/test/explorer/chain_test.exs

@ -1967,7 +1967,7 @@ defmodule Explorer.Chain do
left_join: tf in TokenTransfer, left_join: tf in TokenTransfer,
on: tf.transaction_hash == l.transaction_hash and tf.log_index == l.index, on: tf.transaction_hash == l.transaction_hash and tf.log_index == l.index,
where: l.first_topic == unquote(TokenTransfer.constant()), where: l.first_topic == unquote(TokenTransfer.constant()),
where: is_nil(tf.id), where: is_nil(tf.transaction_hash) and is_nil(tf.log_index),
select: t.block_number, select: t.block_number,
distinct: t.block_number distinct: t.block_number
) )

@ -62,9 +62,10 @@ defmodule Explorer.Chain.TokenTransfer do
@constant "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" @constant "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
@primary_key false
schema "token_transfers" do schema "token_transfers" do
field(:amount, :decimal) field(:amount, :decimal)
field(:log_index, :integer) field(:log_index, :integer, primary_key: true)
field(:token_id, :decimal) field(:token_id, :decimal)
belongs_to(:from_address, Address, foreign_key: :from_address_hash, references: :hash, type: Hash.Address) belongs_to(:from_address, Address, foreign_key: :from_address_hash, references: :hash, type: Hash.Address)
@ -78,7 +79,12 @@ defmodule Explorer.Chain.TokenTransfer do
type: Hash.Address type: Hash.Address
) )
belongs_to(:transaction, Transaction, foreign_key: :transaction_hash, references: :hash, type: Hash.Full) belongs_to(:transaction, Transaction,
foreign_key: :transaction_hash,
primary_key: true,
references: :hash,
type: Hash.Full
)
has_one(:token, through: [:token_contract_address, :token]) has_one(:token, through: [:token_contract_address, :token])
@ -195,7 +201,7 @@ defmodule Explorer.Chain.TokenTransfer do
tt in TokenTransfer, tt in TokenTransfer,
join: t in Token, join: t in Token,
on: tt.token_contract_address_hash == t.contract_address_hash, on: tt.token_contract_address_hash == t.contract_address_hash,
select: {tt.token_contract_address_hash, count(tt.id)}, select: {tt.token_contract_address_hash, fragment("COUNT(*)")},
group_by: tt.token_contract_address_hash group_by: tt.token_contract_address_hash
) )

@ -0,0 +1,22 @@
defmodule Explorer.Repo.Migrations.TokenTransfersCompositePrimaryKey do
use Ecto.Migration
def up do
# Remove old id
alter table(:token_transfers) do
remove(:id)
end
# Don't use `modify` as it requires restating the whole column description
execute("ALTER TABLE token_transfers ADD PRIMARY KEY (transaction_hash, log_index)")
end
def down do
execute("ALTER TABLE token_transfers DROP CONSTRAINT token_transfers_pkey")
# Add back old id
alter table(:token_transfers) do
add(:id, :bigserial, primary_key: true)
end
end
end

@ -50,12 +50,15 @@ defmodule Explorer.Chain.TokenTransferTest do
token: token token: token
) )
transfers_ids = transfers_primary_keys =
token_contract_address.hash token_contract_address.hash
|> TokenTransfer.fetch_token_transfers_from_token_hash([]) |> TokenTransfer.fetch_token_transfers_from_token_hash([])
|> Enum.map(& &1.id) |> Enum.map(&{&1.transaction_hash, &1.log_index})
assert transfers_ids == [another_transfer.id, token_transfer.id] assert transfers_primary_keys == [
{another_transfer.transaction_hash, another_transfer.log_index},
{token_transfer.transaction_hash, token_transfer.log_index}
]
end end
test "when there isn't token transfers won't show anything" do test "when there isn't token transfers won't show anything" do
@ -101,14 +104,14 @@ defmodule Explorer.Chain.TokenTransferTest do
paging_options = %PagingOptions{key: first_page.inserted_at, page_size: 1} paging_options = %PagingOptions{key: first_page.inserted_at, page_size: 1}
token_transfers_ids_paginated = token_transfers_primary_keys_paginated =
TokenTransfer.fetch_token_transfers_from_token_hash( TokenTransfer.fetch_token_transfers_from_token_hash(
token_contract_address.hash, token_contract_address.hash,
paging_options: paging_options paging_options: paging_options
) )
|> Enum.map(& &1.id) |> Enum.map(&{&1.transaction_hash, &1.log_index})
assert token_transfers_ids_paginated == [second_page.id] assert token_transfers_primary_keys_paginated == [{second_page.transaction_hash, second_page.log_index}]
end end
end end

@ -235,7 +235,10 @@ defmodule Explorer.ChainTest do
insert(:token_transfer, to_address: build(:address), transaction: transaction) insert(:token_transfer, to_address: build(:address), transaction: transaction)
transaction = Chain.address_to_transactions(address) |> List.first() transaction = Chain.address_to_transactions(address) |> List.first()
assert transaction.token_transfers |> Enum.map(& &1.id) == [token_transfer.id]
assert transaction.token_transfers |> Enum.map(&{&1.transaction_hash, &1.log_index}) == [
{token_transfer.transaction_hash, token_transfer.log_index}
]
end end
test "returns just the token transfers related to the given contract address" do test "returns just the token transfers related to the given contract address" do
@ -250,7 +253,10 @@ defmodule Explorer.ChainTest do
insert(:token_transfer, to_address: build(:address), transaction: transaction) insert(:token_transfer, to_address: build(:address), transaction: transaction)
transaction = Chain.address_to_transactions(contract_address) |> List.first() transaction = Chain.address_to_transactions(contract_address) |> List.first()
assert Enum.map(transaction.token_transfers, & &1.id) == [token_transfer.id]
assert Enum.map(transaction.token_transfers, &{&1.transaction_hash, &1.log_index}) == [
{token_transfer.transaction_hash, token_transfer.log_index}
]
end end
test "returns all token transfers when the given address is the token contract address" do test "returns all token transfers when the given address is the token contract address" do
@ -572,12 +578,17 @@ defmodule Explorer.ChainTest do
|> insert() |> insert()
|> with_block() |> with_block()
%TokenTransfer{id: token_transfer_id, token_contract_address_hash: token_contract_address_hash} = %TokenTransfer{
insert(:token_transfer, to_address: address, transaction: transaction) transaction_hash: token_transfer_transaction_hash,
log_index: token_transfer_log_index,
token_contract_address_hash: token_contract_address_hash
} = insert(:token_transfer, to_address: address, transaction: transaction)
assert token_contract_address_hash assert token_contract_address_hash
|> Chain.fetch_token_transfers_from_token_hash() |> Chain.fetch_token_transfers_from_token_hash()
|> Enum.map(& &1.id) == [token_transfer_id] |> Enum.map(&{&1.transaction_hash, &1.log_index}) == [
{token_transfer_transaction_hash, token_transfer_log_index}
]
end end
end end
@ -778,7 +789,7 @@ defmodule Explorer.ChainTest do
|> insert_list(:transaction) |> insert_list(:transaction)
|> with_block() |> with_block()
%TokenTransfer{id: id1} = %TokenTransfer{transaction_hash: transaction_hash1, log_index: log_index1} =
insert( insert(
:token_transfer, :token_transfer,
to_address: address, to_address: address,
@ -787,7 +798,7 @@ defmodule Explorer.ChainTest do
token: token token: token
) )
%TokenTransfer{id: id2} = %TokenTransfer{transaction_hash: transaction_hash2, log_index: log_index2} =
insert( insert(
:token_transfer, :token_transfer,
to_address: address, to_address: address,
@ -799,7 +810,10 @@ defmodule Explorer.ChainTest do
fetched_transactions = Explorer.Chain.hashes_to_transactions([transaction1.hash, transaction2.hash]) fetched_transactions = Explorer.Chain.hashes_to_transactions([transaction1.hash, transaction2.hash])
assert Enum.all?(fetched_transactions, fn transaction -> assert Enum.all?(fetched_transactions, fn transaction ->
hd(transaction.token_transfers).id in [id1, id2] %TokenTransfer{transaction_hash: transaction_hash, log_index: log_index} =
hd(transaction.token_transfers)
{transaction_hash, log_index} in [{transaction_hash1, log_index1}, {transaction_hash2, log_index2}]
end) end)
end end
end end
@ -2004,9 +2018,11 @@ defmodule Explorer.ChainTest do
|> insert() |> insert()
|> with_block() |> with_block()
%TokenTransfer{id: id} = insert(:token_transfer, transaction: transaction) %TokenTransfer{transaction_hash: transaction_hash, log_index: log_index} =
insert(:token_transfer, transaction: transaction)
assert [%TokenTransfer{id: ^id}] = Chain.transaction_to_token_transfers(transaction) assert [%TokenTransfer{transaction_hash: ^transaction_hash, log_index: ^log_index}] =
Chain.transaction_to_token_transfers(transaction)
end end
test "token transfers necessity_by_association loads associations" do test "token transfers necessity_by_association loads associations" do

Loading…
Cancel
Save