diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex index e830709500..5974406e6c 100644 --- a/apps/explorer/lib/explorer/chain.ex +++ b/apps/explorer/lib/explorer/chain.ex @@ -40,6 +40,7 @@ defmodule Explorer.Chain do SmartContract, StakingPool, Token, + Token.Instance, TokenTransfer, Transaction, Wei @@ -2973,6 +2974,16 @@ defmodule Explorer.Chain do end end + @spec upsert_token_instance(map()) :: {:ok, Instance.t()} | {:error, Ecto.Changeset.t()} + def upsert_token_instance(params) do + changeset = Instance.changeset(%Instance{}, params) + + Repo.insert(changeset, + on_conflict: :replace_all, + conflict_target: [:token_id, :token_contract_address_hash] + ) + end + @doc """ Update a new `t:Token.t/0` record. diff --git a/apps/explorer/lib/explorer/chain/token/instance.ex b/apps/explorer/lib/explorer/chain/token/instance.ex index 90a6d671dc..0e704650a0 100644 --- a/apps/explorer/lib/explorer/chain/token/instance.ex +++ b/apps/explorer/lib/explorer/chain/token/instance.ex @@ -20,6 +20,7 @@ defmodule Explorer.Chain.Token.Instance do metadata: Map.t() } + @primary_key false schema "token_instances" do field(:token_id, :decimal, primary_key: true) field(:metadata, :map) @@ -32,12 +33,14 @@ defmodule Explorer.Chain.Token.Instance do type: Hash.Address, primary_key: true ) + + timestamps() end - # def changeset(%Instance{} = instance, params \\ %{}) do - # instance - # |> cast([:token_id, :metadata, :token_contract_address_hash]) - # |> validate_required([:token_id, :token_contract_address_hash]) - # |> foreign_key_constraint(:token_contract_address_hash) - # end + def changeset(%Instance{} = instance, params \\ %{}) do + instance + |> cast(params, [:token_id, :metadata, :token_contract_address_hash]) + |> validate_required([:token_id, :token_contract_address_hash]) + |> foreign_key_constraint(:token_contract_address_hash) + end end diff --git a/apps/explorer/priv/repo/migrations/20190905083522_create_token_instances.exs b/apps/explorer/priv/repo/migrations/20190905083522_create_token_instances.exs index ef20e47e46..271b921dbb 100644 --- a/apps/explorer/priv/repo/migrations/20190905083522_create_token_instances.exs +++ b/apps/explorer/priv/repo/migrations/20190905083522_create_token_instances.exs @@ -13,6 +13,8 @@ defmodule Explorer.Repo.Migrations.CreateTokenInstances do ) add(:metadata, :jsonb) + + timestamps(null: false, type: :utc_datetime_usec) end end end diff --git a/apps/explorer/test/explorer/chain_test.exs b/apps/explorer/test/explorer/chain_test.exs index af00d78c12..9a665e7e7b 100644 --- a/apps/explorer/test/explorer/chain_test.exs +++ b/apps/explorer/test/explorer/chain_test.exs @@ -101,6 +101,63 @@ defmodule Explorer.ChainTest do end end + describe "upsert_token_instance/1" do + test "insert a new token instance with valid params" do + token = insert(:token) + + params = %{ + token_id: 1, + token_contract_address_hash: token.contract_address_hash, + metadata: %{uri: "http://example.com"} + } + + {:ok, result} = Chain.upsert_token_instance(params) + + assert result.token_id == Decimal.new(1) + assert result.metadata == params.metadata + assert result.token_contract_address_hash == token.contract_address_hash + end + + test "replaces existing token instance record" do + token = insert(:token) + + params = %{ + token_id: 1, + token_contract_address_hash: token.contract_address_hash, + metadata: %{uri: "http://example.com"} + } + + {:ok, _} = Chain.upsert_token_instance(params) + + params1 = %{ + token_id: 1, + token_contract_address_hash: token.contract_address_hash, + metadata: %{uri: "http://example1.com"} + } + + {:ok, result} = Chain.upsert_token_instance(params1) + + assert result.token_id == Decimal.new(1) + assert result.metadata == params1.metadata + assert result.token_contract_address_hash == token.contract_address_hash + end + + test "fails to import with invalid params" do + params = %{ + token_id: 1, + metadata: %{uri: "http://example.com"} + } + + {:error, + %{ + errors: [ + token_contract_address_hash: {"can't be blank", [validation: :required]} + ], + valid?: false + }} = Chain.upsert_token_instance(params) + end + end + describe "address_to_logs/2" do test "fetches logs" do %Address{hash: address_hash} = address = insert(:address)