From 3ee166c6e7a0fbe0accd121d284e6c09e36fb948 Mon Sep 17 00:00:00 2001 From: Thomas Droxler Date: Wed, 6 Nov 2024 10:40:40 +0100 Subject: [PATCH] Fix sub-contracts endpoint returning duplicate --- .../persistence/queries/ContractQueries.scala | 10 +++++-- .../queries/ContractQueriesSpec.scala | 29 +++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/app/src/main/scala/org/alephium/explorer/persistence/queries/ContractQueries.scala b/app/src/main/scala/org/alephium/explorer/persistence/queries/ContractQueries.scala index 17f1a2544..bdcf22cf2 100644 --- a/app/src/main/scala/org/alephium/explorer/persistence/queries/ContractQueries.scala +++ b/app/src/main/scala/org/alephium/explorer/persistence/queries/ContractQueries.scala @@ -141,10 +141,14 @@ object ContractQueries { def getSubContractsQuery(parent: Address, pagination: Pagination): DBActionSR[Address] = { sql""" SELECT contract - FROM contracts - WHERE parent = $parent + FROM ( + SELECT DISTINCT ON (contract) contract, creation_timestamp, creation_event_order + FROM contracts + WHERE parent = $parent + ORDER BY contract, creation_timestamp DESC, creation_event_order + ) AS distinct_contracts ORDER BY creation_timestamp DESC, creation_event_order - """ + """ .paginate(pagination) .asASE[Address](addressGetResult) } diff --git a/app/src/test/scala/org/alephium/explorer/persistence/queries/ContractQueriesSpec.scala b/app/src/test/scala/org/alephium/explorer/persistence/queries/ContractQueriesSpec.scala index 20a632d5b..7a2c9eeac 100644 --- a/app/src/test/scala/org/alephium/explorer/persistence/queries/ContractQueriesSpec.scala +++ b/app/src/test/scala/org/alephium/explorer/persistence/queries/ContractQueriesSpec.scala @@ -117,5 +117,34 @@ class ContractQueriesSpec } } + + "getSubContractsQuery when duplicate contracts exists" in { + val parent = addressGen.sample.get + val pagination = Pagination.unsafe(1, 5) + + forAll( + createEventsGen(Some(parent)), + createEventsGen() + ) { case ((groupIndex, events), (otherGroup, otherEvents)) => + val eventsWithDuplicates = events ++ events.map(event => + event.copy(timestamp = event.timestamp.plusSecondsUnsafe(1)) + ) + + run(ContractSchema.table.delete).futureValue + run(ContractQueries.insertContractCreation(eventsWithDuplicates, groupIndex)).futureValue + run(ContractQueries.insertContractCreation(otherEvents, otherGroup)).futureValue + + run( + ContractQueries.getSubContractsQuery(parent, pagination) + ).futureValue is eventsWithDuplicates + .sortBy(_.timestamp) + .reverse + .flatMap(ContractEntity.creationFromEventEntity(_, groupIndex)) + .map(_.contract) + .distinct + .take(pagination.limit) + + } + } } }