graphql: add user-selected ordering to transactions for address

pull/5774/head
Sebastien Guillemot 3 years ago committed by Viktor Baranov
parent 56d8d049fc
commit b216dbef76
  1. 1
      CHANGELOG.md
  2. 6
      apps/block_scout_web/lib/block_scout_web/resolvers/transaction.ex
  3. 5
      apps/block_scout_web/lib/block_scout_web/schema/scalars.ex
  4. 1
      apps/block_scout_web/lib/block_scout_web/schema/types.ex
  5. 62
      apps/block_scout_web/test/block_scout_web/schema/query/address_test.exs
  6. 8
      apps/explorer/lib/explorer/graphql.ex
  7. 10
      apps/explorer/test/explorer/graphql_test.exs

@ -5,6 +5,7 @@
- [#5732](https://github.com/blockscout/blockscout/pull/5732) - Manage testnet label (right to the navbar logo)
- [#5699](https://github.com/blockscout/blockscout/pull/5699) - Switch to basic (non-pro) API endpoint for Coingecko requests, if API key is not provided
- [#5542](https://github.com/blockscout/blockscout/pull/5542) - Add `jq` in docker image
- [#5345](https://github.com/blockscout/blockscout/pull/5345) - Graphql: add user-selected ordering to transactions for address query
### Fixes
- [#5768](https://github.com/blockscout/blockscout/pull/5768) - Outstanding rows limit for missing blocks query (catchup fetcher)

@ -13,9 +13,11 @@ defmodule BlockScoutWeb.Resolvers.Transaction do
end
def get_by(%Address{hash: address_hash}, args, _) do
connection_args = Map.take(args, [:after, :before, :first, :last])
address_hash
|> GraphQL.address_to_transactions_query()
|> Connection.from_query(&Repo.all/1, args, options(args))
|> GraphQL.address_to_transactions_query(args.order)
|> Connection.from_query(&Repo.all/1, connection_args, options(args))
end
defp options(%{before: _}), do: []

@ -113,4 +113,9 @@ defmodule BlockScoutWeb.Schema.Scalars do
value(:reward)
value(:selfdestruct)
end
enum :sort_order do
value(:asc)
value(:desc)
end
end

@ -33,6 +33,7 @@ defmodule BlockScoutWeb.Schema.Types do
connection field(:transactions, node_type: :transaction) do
arg(:count, :integer)
arg(:order, type: :sort_order, default_value: :desc)
resolve(&Transaction.get_by/3)
complexity(fn

@ -326,6 +326,68 @@ defmodule BlockScoutWeb.Schema.Query.AddressTest do
assert Enum.all?(transactions, &(&1["node"]["block_number"] == third_block.number))
end
test "transactions are ordered by ascending block and index", %{conn: conn} do
first_block = insert(:block)
second_block = insert(:block)
third_block = insert(:block)
address = insert(:address)
3
|> insert_list(:transaction, from_address: address)
|> with_block(second_block)
3
|> insert_list(:transaction, from_address: address)
|> with_block(third_block)
3
|> insert_list(:transaction, from_address: address)
|> with_block(first_block)
query = """
query ($hash: AddressHash!, $first: Int!) {
address(hash: $hash) {
transactions(first: $first, order: ASC) {
edges {
node {
hash
block_number
index
}
}
}
}
}
"""
variables = %{
"hash" => to_string(address.hash),
"first" => 3
}
conn = post(conn, "/graphql", query: query, variables: variables)
%{
"data" => %{
"address" => %{
"transactions" => %{
"edges" => transactions
}
}
}
} = json_response(conn, 200)
block_number_and_index_order =
Enum.map(transactions, fn transaction ->
{transaction["node"]["block_number"], transaction["node"]["index"]}
end)
assert block_number_and_index_order == Enum.sort(block_number_and_index_order, &(&1 < &2))
assert length(transactions) == 3
assert Enum.all?(transactions, &(&1["node"]["block_number"] == first_block.number))
end
test "complexity correlates to 'first' or 'last' arguments", %{conn: conn} do
address = build(:address)

@ -24,15 +24,15 @@ defmodule Explorer.GraphQL do
Returns a query to fetch transactions with a matching `to_address_hash`,
`from_address_hash`, or `created_contract_address_hash` field for a given address hash.
Orders transactions by descending block number and index.
Orders transactions by `block_number` and `index` according to to `order`
"""
@spec address_to_transactions_query(Hash.Address.t()) :: Ecto.Query.t()
def address_to_transactions_query(address_hash) do
@spec address_to_transactions_query(Hash.Address.t(), :desc | :asc) :: Ecto.Query.t()
def address_to_transactions_query(address_hash, order) do
Transaction
|> order_by([transaction], desc: transaction.block_number, desc: transaction.index)
|> where([transaction], transaction.to_address_hash == ^address_hash)
|> or_where([transaction], transaction.from_address_hash == ^address_hash)
|> or_where([transaction], transaction.created_contract_address_hash == ^address_hash)
|> order_by([transaction], [{^order, transaction.block_number}, {^order, transaction.index}])
end
@doc """

@ -12,7 +12,7 @@ defmodule Explorer.GraphQLTest do
:address
|> insert()
|> Map.get(:hash)
|> GraphQL.address_to_transactions_query()
|> GraphQL.address_to_transactions_query(:desc)
|> Repo.replica().all()
assert result == []
@ -25,7 +25,7 @@ defmodule Explorer.GraphQLTest do
[found_transaction] =
address_hash
|> GraphQL.address_to_transactions_query()
|> GraphQL.address_to_transactions_query(:desc)
|> Repo.replica().all()
assert found_transaction.hash == transaction.hash
@ -38,7 +38,7 @@ defmodule Explorer.GraphQLTest do
[found_transaction] =
address_hash
|> GraphQL.address_to_transactions_query()
|> GraphQL.address_to_transactions_query(:desc)
|> Repo.replica().all()
assert found_transaction.hash == transaction.hash
@ -51,7 +51,7 @@ defmodule Explorer.GraphQLTest do
[found_transaction] =
address_hash
|> GraphQL.address_to_transactions_query()
|> GraphQL.address_to_transactions_query(:desc)
|> Repo.replica().all()
assert found_transaction.hash == transaction.hash
@ -78,7 +78,7 @@ defmodule Explorer.GraphQLTest do
found_transactions =
address_hash
|> GraphQL.address_to_transactions_query()
|> GraphQL.address_to_transactions_query(:desc)
|> Repo.replica().all()
block_number_and_index_order =

Loading…
Cancel
Save