From d1f1811ec88bd250ac0528969ee19a2b4db6754f Mon Sep 17 00:00:00 2001 From: Lea Lobanov Date: Mon, 4 Nov 2024 18:10:06 +0900 Subject: [PATCH 1/4] Setup get collection endpoint --- .../org/onflow/flow/sdk/AsyncFlowAccessApi.kt | 2 ++ .../org/onflow/flow/sdk/FlowAccessApi.kt | 2 ++ .../flow/sdk/impl/AsyncFlowAccessApiImpl.kt | 14 ++++++++++++++ .../onflow/flow/sdk/impl/FlowAccessApiImpl.kt | 13 +++++++++++++ .../main/kotlin/org/onflow/flow/sdk/models.kt | 18 ++++++++++++++++++ 5 files changed, 49 insertions(+) diff --git a/sdk/src/main/kotlin/org/onflow/flow/sdk/AsyncFlowAccessApi.kt b/sdk/src/main/kotlin/org/onflow/flow/sdk/AsyncFlowAccessApi.kt index 66d31bf..03af937 100644 --- a/sdk/src/main/kotlin/org/onflow/flow/sdk/AsyncFlowAccessApi.kt +++ b/sdk/src/main/kotlin/org/onflow/flow/sdk/AsyncFlowAccessApi.kt @@ -32,6 +32,8 @@ interface AsyncFlowAccessApi { fun getCollectionById(id: FlowId): CompletableFuture> + fun getFullCollectionById(id: FlowId): CompletableFuture>> + fun sendTransaction(transaction: FlowTransaction): CompletableFuture> fun getTransactionById(id: FlowId): CompletableFuture> diff --git a/sdk/src/main/kotlin/org/onflow/flow/sdk/FlowAccessApi.kt b/sdk/src/main/kotlin/org/onflow/flow/sdk/FlowAccessApi.kt index b160efd..ce8de86 100644 --- a/sdk/src/main/kotlin/org/onflow/flow/sdk/FlowAccessApi.kt +++ b/sdk/src/main/kotlin/org/onflow/flow/sdk/FlowAccessApi.kt @@ -44,6 +44,8 @@ interface FlowAccessApi { fun getCollectionById(id: FlowId): AccessApiCallResponse + fun getFullCollectionById(id: FlowId): AccessApiCallResponse> + fun sendTransaction(transaction: FlowTransaction): AccessApiCallResponse fun getTransactionById(id: FlowId): AccessApiCallResponse diff --git a/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImpl.kt b/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImpl.kt index 853b110..c7ff3eb 100644 --- a/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImpl.kt +++ b/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImpl.kt @@ -285,6 +285,20 @@ class AsyncFlowAccessApiImpl( errorMessage = "Failed to get collection by ID" ) + override fun getFullCollectionById(id: FlowId): CompletableFuture>> = + handleApiCall( + apiCall = { + api.getFullCollectionByID( + Access.GetFullCollectionByIDRequest + .newBuilder() + .setId(id.byteStringValue) + .build() + ) + }, + transform = { fullCollectionResponse -> fullCollectionResponse.transactionsList.map { FlowTransaction.of(it) } }, + errorMessage = "Failed to get full collection by ID" + ) + override fun sendTransaction(transaction: FlowTransaction): CompletableFuture> = handleApiCall( apiCall = { diff --git a/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt b/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt index 75ef414..6f8fd2b 100644 --- a/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt +++ b/sdk/src/main/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImpl.kt @@ -233,6 +233,19 @@ class FlowAccessApiImpl( FlowAccessApi.AccessApiCallResponse.Error("Failed to get collection by ID", e) } + override fun getFullCollectionById(id: FlowId): FlowAccessApi.AccessApiCallResponse> = + try { + val ret = api.getFullCollectionByID( + Access.GetFullCollectionByIDRequest + .newBuilder() + .setId(id.byteStringValue) + .build() + ) + FlowAccessApi.AccessApiCallResponse.Success(ret.transactionsList.map { FlowTransaction.of(it) }) + } catch (e: Exception) { + FlowAccessApi.AccessApiCallResponse.Error("Failed to get full collection by ID", e) + } + override fun sendTransaction(transaction: FlowTransaction): FlowAccessApi.AccessApiCallResponse = try { val ret = api.sendTransaction( diff --git a/sdk/src/main/kotlin/org/onflow/flow/sdk/models.kt b/sdk/src/main/kotlin/org/onflow/flow/sdk/models.kt index 981b406..eed91b7 100644 --- a/sdk/src/main/kotlin/org/onflow/flow/sdk/models.kt +++ b/sdk/src/main/kotlin/org/onflow/flow/sdk/models.kt @@ -1295,6 +1295,24 @@ data class FlowCollection( .addAllTransactionIds(transactionIds.map { it.byteStringValue }) } +data class FlowFullCollection( + val id: FlowId, + val transactionIds: List +) : Serializable { + companion object { + @JvmStatic + fun of(value: CollectionOuterClass.Collection) = FlowCollection( + id = FlowId.of(value.id.toByteArray()), + transactionIds = value.transactionIdsList.map { FlowId.of(it.toByteArray()) } + ) + } + + @JvmOverloads + fun builder(builder: CollectionOuterClass.Collection.Builder = CollectionOuterClass.Collection.newBuilder()): CollectionOuterClass.Collection.Builder = builder + .setId(id.byteStringValue) + .addAllTransactionIds(transactionIds.map { it.byteStringValue }) +} + interface BytesHolder { val bytes: ByteArray val base16Value: String get() = bytes.bytesToHex() From f3b5b55114c4cabec3043299d0f633c3fef59f56 Mon Sep 17 00:00:00 2001 From: Lea Lobanov Date: Mon, 4 Nov 2024 18:39:25 +0900 Subject: [PATCH 2/4] Working on examples --- java-example/README.md | 3 +++ .../GetCollectionAccessAPIConnector.java | 13 +++++++++++++ .../GetCollectionAccessAPIConnectorTest.java | 14 ++++++++++++++ kotlin-example/README.md | 3 +++ .../GetCollectionAccessAPIConnector.kt | 6 ++++++ .../GetCollectionAccessAPIConnectorTest.kt | 17 +++++++++++++---- 6 files changed, 52 insertions(+), 4 deletions(-) diff --git a/java-example/README.md b/java-example/README.md index 44d7785..f615dee 100644 --- a/java-example/README.md +++ b/java-example/README.md @@ -70,6 +70,9 @@ Below is a list of all Java code examples currently supported in this repo: [Get collections by ID.](src/main/java/org/onflow/examples/java/getCollection/GetCollectionAccessAPIConnector.java) +- Get collection by id +- Get full collection by id (returns all transactions in collection response) + #### Get Execution Data [Get execution data by block ID.](src/main/java/org/onflow/examples/java/getExecutionData/GetExecutionDataAccessAPIConnector.java) diff --git a/java-example/src/main/java/org/onflow/examples/java/getCollection/GetCollectionAccessAPIConnector.java b/java-example/src/main/java/org/onflow/examples/java/getCollection/GetCollectionAccessAPIConnector.java index 318d76b..5c29ebb 100644 --- a/java-example/src/main/java/org/onflow/examples/java/getCollection/GetCollectionAccessAPIConnector.java +++ b/java-example/src/main/java/org/onflow/examples/java/getCollection/GetCollectionAccessAPIConnector.java @@ -4,6 +4,9 @@ import org.onflow.flow.sdk.FlowAccessApi.AccessApiCallResponse; import org.onflow.flow.sdk.FlowCollection; import org.onflow.flow.sdk.FlowId; +import org.onflow.flow.sdk.FlowTransaction; + +import java.util.List; public class GetCollectionAccessAPIConnector { private final FlowAccessApi accessAPI; @@ -21,4 +24,14 @@ public FlowCollection getCollectionById(FlowId collectionId) { throw new RuntimeException(errorResponse.getMessage(), errorResponse.getThrowable()); } } + + public List getFullCollectionById(FlowId collectionId) { + AccessApiCallResponse> response = accessAPI.getFullCollectionById(collectionId); + if (response instanceof AccessApiCallResponse.Success) { + return ((AccessApiCallResponse.Success>) response).getData(); + } else { + AccessApiCallResponse.Error errorResponse = (AccessApiCallResponse.Error) response; + throw new RuntimeException(errorResponse.getMessage(), errorResponse.getThrowable()); + } + } } diff --git a/java-example/src/test/java/org/onflow/examples/java/getCollection/GetCollectionAccessAPIConnectorTest.java b/java-example/src/test/java/org/onflow/examples/java/getCollection/GetCollectionAccessAPIConnectorTest.java index e844ba8..170eb9a 100644 --- a/java-example/src/test/java/org/onflow/examples/java/getCollection/GetCollectionAccessAPIConnectorTest.java +++ b/java-example/src/test/java/org/onflow/examples/java/getCollection/GetCollectionAccessAPIConnectorTest.java @@ -11,6 +11,8 @@ import org.onflow.flow.sdk.crypto.Crypto; import org.onflow.flow.sdk.crypto.PublicKey; +import java.util.List; + import static org.junit.jupiter.api.Assertions.*; @FlowEmulatorProjectTest(flowJsonLocation = "../flow/flow.json") @@ -51,4 +53,16 @@ public void canFetchCollectionById() { assertNotNull(collection, "Collection should not be null"); assertEquals(collectionId, collection.getId(), "Collection ID should match the fetched collection ID"); } + + @Test + public void canFetchFullCollectionById() { + List fullCollectionResponse = connector.getFullCollectionById(collectionId); + + assertNotNull(fullCollectionResponse, "Collection transactions should not be null"); + assertFalse(fullCollectionResponse.isEmpty(), "Collection transactions should not be empty"); + + FlowTransaction firstTransaction = fullCollectionResponse.get(0); + assertNotNull(firstTransaction.getId(), "Transaction ID should not be null"); + assertNotNull(firstTransaction.getScript(), "Transaction script should not be null"); + } } diff --git a/kotlin-example/README.md b/kotlin-example/README.md index ed1a977..a7d5436 100644 --- a/kotlin-example/README.md +++ b/kotlin-example/README.md @@ -71,6 +71,9 @@ Below is a list of all Kotlin code examples currently supported in this repo: [Get collections by ID.](src/main/kotlin/org/onflow/examples/kotlin/getCollection/GetCollectionAccessAPIConnector.kt) +- Get collection by id +- Get full collection by id (returns all transactions in collection response) + #### Get Execution Data [Get execution data by block ID.](src/main/kotlin/org/onflow/examples/kotlin/getExecutionData/GetExecutionDataAccessAPIConnector.kt) diff --git a/kotlin-example/src/main/kotlin/org/onflow/examples/kotlin/getCollection/GetCollectionAccessAPIConnector.kt b/kotlin-example/src/main/kotlin/org/onflow/examples/kotlin/getCollection/GetCollectionAccessAPIConnector.kt index 030c82e..fc86d18 100644 --- a/kotlin-example/src/main/kotlin/org/onflow/examples/kotlin/getCollection/GetCollectionAccessAPIConnector.kt +++ b/kotlin-example/src/main/kotlin/org/onflow/examples/kotlin/getCollection/GetCollectionAccessAPIConnector.kt @@ -11,4 +11,10 @@ class GetCollectionAccessAPIConnector( is AccessApiCallResponse.Success -> response.data is AccessApiCallResponse.Error -> throw Exception(response.message, response.throwable) } + + fun getFullCollectionById(collectionId: FlowId): List = + when (val response = accessAPI.getFullCollectionById(collectionId)) { + is AccessApiCallResponse.Success -> response.data + is AccessApiCallResponse.Error -> throw Exception(response.message, response.throwable) + } } diff --git a/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getCollection/GetCollectionAccessAPIConnectorTest.kt b/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getCollection/GetCollectionAccessAPIConnectorTest.kt index 36a1e0b..53545f9 100644 --- a/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getCollection/GetCollectionAccessAPIConnectorTest.kt +++ b/kotlin-example/src/test/kotlin/org/onflow/examples/kotlin/getCollection/GetCollectionAccessAPIConnectorTest.kt @@ -8,10 +8,7 @@ import org.onflow.flow.common.test.FlowEmulatorProjectTest import org.onflow.flow.common.test.FlowServiceAccountCredentials import org.onflow.flow.common.test.FlowTestClient import org.onflow.flow.common.test.TestAccount -import org.onflow.flow.sdk.FlowAccessApi -import org.onflow.flow.sdk.FlowCollection -import org.onflow.flow.sdk.FlowId -import org.onflow.flow.sdk.SignatureAlgorithm +import org.onflow.flow.sdk.* import org.onflow.flow.sdk.crypto.Crypto @FlowEmulatorProjectTest(flowJsonLocation = "../flow/flow.json") @@ -53,4 +50,16 @@ class GetCollectionAccessAPIConnectorTest { assertNotNull(collection, "Collection should not be null") assertEquals(collectionId, collection.id, "Collection ID should match the fetched collection ID") } + + @Test + fun `Can fetch full collection by ID`() { + val collectionTransactions: List = connector.getFullCollectionById(collectionId) + + assertNotNull(collectionTransactions, "Collection transactions should not be null") + assertTrue(collectionTransactions.isNotEmpty(), "Collection transactions should not be empty") + + val firstTransaction = collectionTransactions.first() + assertNotNull(firstTransaction.id, "Transaction ID should not be null") + assertNotNull(firstTransaction.script, "Transaction script should not be null") + } } From e8d7a66798c8e898e5eca89c28d739fd62f091fb Mon Sep 17 00:00:00 2001 From: Lea Lobanov Date: Mon, 4 Nov 2024 18:42:05 +0900 Subject: [PATCH 3/4] Working on examples --- .../main/kotlin/org/onflow/flow/sdk/models.kt | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/sdk/src/main/kotlin/org/onflow/flow/sdk/models.kt b/sdk/src/main/kotlin/org/onflow/flow/sdk/models.kt index eed91b7..981b406 100644 --- a/sdk/src/main/kotlin/org/onflow/flow/sdk/models.kt +++ b/sdk/src/main/kotlin/org/onflow/flow/sdk/models.kt @@ -1295,24 +1295,6 @@ data class FlowCollection( .addAllTransactionIds(transactionIds.map { it.byteStringValue }) } -data class FlowFullCollection( - val id: FlowId, - val transactionIds: List -) : Serializable { - companion object { - @JvmStatic - fun of(value: CollectionOuterClass.Collection) = FlowCollection( - id = FlowId.of(value.id.toByteArray()), - transactionIds = value.transactionIdsList.map { FlowId.of(it.toByteArray()) } - ) - } - - @JvmOverloads - fun builder(builder: CollectionOuterClass.Collection.Builder = CollectionOuterClass.Collection.newBuilder()): CollectionOuterClass.Collection.Builder = builder - .setId(id.byteStringValue) - .addAllTransactionIds(transactionIds.map { it.byteStringValue }) -} - interface BytesHolder { val bytes: ByteArray val base16Value: String get() = bytes.bytesToHex() From 1faecd965a622263f774578940673646798415c3 Mon Sep 17 00:00:00 2001 From: Lea Lobanov Date: Tue, 5 Nov 2024 12:31:24 +0900 Subject: [PATCH 4/4] Unit and integration tests --- .../org/onflow/flow/sdk/FlowAccessApiTest.kt | 12 ++++++++++++ .../flow/sdk/impl/AsyncFlowAccessApiImplTest.kt | 15 +++++++++++++++ .../onflow/flow/sdk/impl/FlowAccessApiImplTest.kt | 11 +++++++++++ 3 files changed, 38 insertions(+) diff --git a/sdk/src/test/kotlin/org/onflow/flow/sdk/FlowAccessApiTest.kt b/sdk/src/test/kotlin/org/onflow/flow/sdk/FlowAccessApiTest.kt index ede75a6..422b1b2 100644 --- a/sdk/src/test/kotlin/org/onflow/flow/sdk/FlowAccessApiTest.kt +++ b/sdk/src/test/kotlin/org/onflow/flow/sdk/FlowAccessApiTest.kt @@ -230,6 +230,18 @@ class FlowAccessApiTest { assertEquals(FlowAccessApi.AccessApiCallResponse.Success(flowCollection), result) } + @Test + fun `Test getFullCollectionById`() { + val flowAccessApi = mock(FlowAccessApi::class.java) + val flowId = FlowId("01") + val flowTransaction = FlowTransaction.of(TransactionOuterClass.Transaction.getDefaultInstance()) + `when`(flowAccessApi.getFullCollectionById(flowId)).thenReturn(FlowAccessApi.AccessApiCallResponse.Success(listOf(flowTransaction))) + + val result = flowAccessApi.getFullCollectionById(flowId) + + assertEquals(FlowAccessApi.AccessApiCallResponse.Success(listOf(flowTransaction)), result) + } + @Test fun `Test sendTransaction`() { val flowAccessApi = mock(FlowAccessApi::class.java) diff --git a/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt b/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt index 0e8ce15..dd87bbb 100644 --- a/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt +++ b/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/AsyncFlowAccessApiImplTest.kt @@ -158,6 +158,11 @@ class AsyncFlowAccessApiImplTest { .setCollection(mockCollection.builder().build()) .build() + fun fullCollectionResponse(transactions: List) = Access.FullCollectionResponse + .newBuilder() + .addAllTransactions(transactions.map { it.builder().build() }) + .build() + fun executionResultResponse(mockExecutionResult: FlowExecutionResult) = Access.ExecutionResultByIDResponse .newBuilder() .setExecutionResult(mockExecutionResult.builder().build()) @@ -413,6 +418,16 @@ class AsyncFlowAccessApiImplTest { assertSuccess(result, mockCollection) } + @Test + fun `test getFullCollectionById`() { + val collectionId = FlowId("01") + val mockTransaction = FlowTransaction(FlowScript("script"), emptyList(), FlowId.of("01".toByteArray()), 123L, FlowTransactionProposalKey(FlowAddress("02"), 1, 123L), FlowAddress("02"), emptyList()) + `when`(api.getFullCollectionByID(any())).thenReturn(setupFutureMock(MockResponseFactory.fullCollectionResponse(listOf(mockTransaction)))) + + val result = asyncFlowAccessApi.getFullCollectionById(collectionId).get() + assertSuccess(result, listOf(mockTransaction)) + } + @Test fun `test sendTransaction`() { val mockTransaction = FlowTransaction(FlowScript("script"), emptyList(), FlowId.of("01".toByteArray()), 123L, FlowTransactionProposalKey(FlowAddress("02"), 1, 123L), FlowAddress("02"), emptyList()) diff --git a/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImplTest.kt b/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImplTest.kt index 908653f..577c300 100644 --- a/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImplTest.kt +++ b/sdk/src/test/kotlin/org/onflow/flow/sdk/impl/FlowAccessApiImplTest.kt @@ -339,6 +339,17 @@ class FlowAccessApiImplTest { assertResultSuccess(result) { assertEquals(mockCollection, it) } } + @Test + fun `Test getFullCollectionById`() { + val collectionId = FlowId("01") + val mockTransaction = createMockTransaction() + + `when`(mockApi.getFullCollectionByID(any())).thenReturn(AsyncFlowAccessApiImplTest.MockResponseFactory.fullCollectionResponse(listOf(mockTransaction))) + + val result = flowAccessApiImpl.getFullCollectionById(collectionId) + assertResultSuccess(result) { assertEquals(listOf(mockTransaction), it) } + } + @Test fun `Test sendTransaction`() { val mockTransaction = createMockTransaction()