Skip to content

Commit

Permalink
Merge pull request #531 from alephium/event-index-filter
Browse files Browse the repository at this point in the history
Allow to filter contract events by event index
  • Loading branch information
h0ngcha0 authored Dec 26, 2024
2 parents 58f74c1 + b2d6bfd commit 0e5b0cd
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 22 deletions.
18 changes: 18 additions & 0 deletions app/src/main/resources/explorer-backend-openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -7112,6 +7112,15 @@
"format": "address"
}
},
{
"name": "event_index",
"in": "query",
"required": false,
"schema": {
"type": "integer",
"format": "int32"
}
},
{
"name": "page",
"in": "query",
Expand Down Expand Up @@ -7286,6 +7295,15 @@
"format": "address"
}
},
{
"name": "event_index",
"in": "query",
"required": false,
"schema": {
"type": "integer",
"format": "int32"
}
},
{
"name": "page",
"in": "query",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,21 +41,24 @@ trait EventsEndpoints extends BaseEndpoint with QueryParams {
.out(jsonBody[ArraySeq[Event]])
.description("Get contract events by transaction id")

val getEventsByContractAddress: BaseEndpoint[(Address, Pagination), ArraySeq[Event]] =
val getEventsByContractAddress
: BaseEndpoint[(Address, Option[Int], Pagination), ArraySeq[Event]] =
eventsEndpoint.get
.in("contract-address")
.in(path[Address]("contract_address"))
.in(query[Option[Int]]("event_index"))
.in(pagination)
.out(jsonBody[ArraySeq[Event]])
.description("Get contract events by contract address")

val getEventsByContractAndInputAddress
: BaseEndpoint[(Address, Address, Pagination), ArraySeq[Event]] =
: BaseEndpoint[(Address, Address, Option[Int], Pagination), ArraySeq[Event]] =
eventsEndpoint.get
.in("contract-address")
.in(path[Address]("contract_address"))
.in("input-address")
.in(path[Address]("input_address"))
.in(query[Option[Int]]("event_index"))
.in(pagination)
.out(jsonBody[ArraySeq[Event]])
.description("Get contract events by contract and input addresses")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,30 +73,59 @@ object EventQueries {

def getEventsByContractAddressQuery(
address: Address,
eventIndex: Option[Int],
pagination: Pagination
): DBActionSR[EventEntity] = {
sql"""
SELECT *
FROM events
WHERE contract_address = $address
ORDER BY block_timestamp DESC, event_order_in_block
"""
// We map to add or not the event index, we duplicate the rest of the
// query to have proper prepared statements
eventIndex
.map { i =>
sql"""
SELECT *
FROM events
WHERE contract_address = $address
AND event_index = $i
ORDER BY block_timestamp DESC, event_order_in_block
"""
}
.getOrElse {
sql"""
SELECT *
FROM events
WHERE contract_address = $address
ORDER BY block_timestamp DESC, event_order_in_block
"""
}
.paginate(pagination)
.asASE[EventEntity](eventGetResult)
}

def getEventsByContractAndInputAddressQuery(
contract: Address,
input: Address,
eventIndex: Option[Int],
pagination: Pagination
): DBActionSR[EventEntity] = {
sql"""
SELECT *
FROM events
WHERE contract_address = $contract
AND input_address = $input
ORDER BY block_timestamp DESC
"""
eventIndex
.map { i =>
sql"""
SELECT *
FROM events
WHERE contract_address = $contract
AND input_address = $input
AND event_index = $i
ORDER BY block_timestamp DESC
"""
}
.getOrElse {
sql"""
SELECT *
FROM events
WHERE contract_address = $contract
AND input_address = $input
ORDER BY block_timestamp DESC
"""
}
.paginate(pagination)
.asASE[EventEntity](eventGetResult)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,13 @@ class EventServer(implicit
route(getEventsByTxId.serverLogicSuccess[Future] { txId =>
run(getEventsByTxIdQuery(txId)).map(_.map(_.toApi))
}),
route(getEventsByContractAddress.serverLogicSuccess[Future] { case (address, pagination) =>
run(getEventsByContractAddressQuery(address, pagination)).map(_.map(_.toApi))
route(getEventsByContractAddress.serverLogicSuccess[Future] {
case (address, eventIndex, pagination) =>
run(getEventsByContractAddressQuery(address, eventIndex, pagination)).map(_.map(_.toApi))
}),
route(getEventsByContractAndInputAddress.serverLogicSuccess[Future] {
case (contract, input, pagination) =>
run(getEventsByContractAndInputAddressQuery(contract, input, pagination))
case (contract, input, eventIndex, pagination) =>
run(getEventsByContractAndInputAddressQuery(contract, input, eventIndex, pagination))
.map(_.map(_.toApi))
})
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class EventQueriesSpec
events.map { event =>
val result =
run(
EventQueries.getEventsByContractAddressQuery(event.contractAddress, pagination)
EventQueries.getEventsByContractAddressQuery(event.contractAddress, None, pagination)
).futureValue
result.size is 1
result.head.toApi is event.toApi
Expand All @@ -100,7 +100,7 @@ class EventQueriesSpec

val result =
run(
EventQueries.getEventsByContractAddressQuery(contractAddress, fullPagination)
EventQueries.getEventsByContractAddressQuery(contractAddress, None, fullPagination)
).futureValue

result.size is uniqueContractAddressEvents.size
Expand All @@ -110,7 +110,9 @@ class EventQueriesSpec
}

val paginatedResult =
run(EventQueries.getEventsByContractAddressQuery(contractAddress, pagination)).futureValue
run(
EventQueries.getEventsByContractAddressQuery(contractAddress, None, pagination)
).futureValue

if (uniqueContractAddressEvents.sizeIs > pagination.limit) {
paginatedResult.size is pagination.limit
Expand All @@ -120,6 +122,37 @@ class EventQueriesSpec
}
}

"filter event by event index" in {
forAll(Gen.nonEmptyListOf(eventEntityGen())) { events =>
val events2 = events.map(event =>
event.copy(eventOrder = event.eventOrder + 1, eventIndex = event.eventIndex + 1)
)

insert(events ++ events2)

events.map { event =>
val withoutFilter =
run(
EventQueries.getEventsByContractAddressQuery(event.contractAddress, None, pagination)
).futureValue

withoutFilter.size is 2

val result =
run(
EventQueries.getEventsByContractAddressQuery(
event.contractAddress,
Some(event.eventIndex),
pagination
)
).futureValue

result.size is 1
result.head.toApi is event.toApi
}
}
}

"get event by contract address and input address" in {
forAll(Gen.nonEmptyListOf(eventEntityGen())) { events =>
insert(events)
Expand All @@ -132,6 +165,7 @@ class EventQueriesSpec
EventQueries.getEventsByContractAndInputAddressQuery(
event.contractAddress,
inputAddress,
None,
pagination
)
).futureValue
Expand All @@ -143,6 +177,7 @@ class EventQueriesSpec
EventQueries.getEventsByContractAndInputAddressQuery(
event.contractAddress,
addressGen.sample.get,
None,
pagination
)
).futureValue is ArraySeq.empty
Expand All @@ -169,6 +204,7 @@ class EventQueriesSpec
EventQueries.getEventsByContractAndInputAddressQuery(
contractAddress,
inputAddress,
None,
fullPagination
)
).futureValue
Expand All @@ -184,6 +220,7 @@ class EventQueriesSpec
EventQueries.getEventsByContractAndInputAddressQuery(
contractAddress,
inputAddress,
None,
pagination
)
).futureValue
Expand All @@ -197,6 +234,54 @@ class EventQueriesSpec
}
}

"get event by contract address, input address and filter event index" in {
forAll(Gen.nonEmptyListOf(eventEntityGen())) { events =>
val events2 = events.map(event =>
event.copy(eventOrder = event.eventOrder + 1, eventIndex = event.eventIndex + 1)
)

insert(events ++ events2)

events.map { event =>
event.inputAddress match {
case Some(inputAddress) =>
val withoutFilter =
run(
EventQueries.getEventsByContractAndInputAddressQuery(
event.contractAddress,
inputAddress,
None,
pagination
)
).futureValue

withoutFilter.size is 2

val result =
run(
EventQueries.getEventsByContractAndInputAddressQuery(
event.contractAddress,
inputAddress,
Some(event.eventIndex),
pagination
)
).futureValue

result.size is 1

case None =>
run(
EventQueries.getEventsByContractAndInputAddressQuery(
event.contractAddress,
addressGen.sample.get,
Some(event.eventIndex),
pagination
)
).futureValue is ArraySeq.empty
}
}
}
}
def insert(events: ArraySeq[EventEntity]) = {
run(EventSchema.table.delete).futureValue
run(EventSchema.table ++= events).futureValue
Expand Down

0 comments on commit 0e5b0cd

Please sign in to comment.