From 7e259ff2fa4c0c7a74db28c6ebacccf7f2f95507 Mon Sep 17 00:00:00 2001 From: Sotatek-SonVu3 Date: Mon, 15 Jan 2024 14:53:56 +0700 Subject: [PATCH] refactor: replace logic to get token metadata in get native script and tx details --- .../explorer/api/mapper/MaTxMintMapper.java | 28 ++++++++++++++----- .../api/projection/MintProjection.java | 24 ++++++++++++++++ .../ledgersync/MaTxMintRepository.java | 10 +++++++ .../ledgersync/MultiAssetRepository.java | 20 +++++++------ .../api/service/impl/ScriptServiceImpl.java | 16 ++++------- .../api/service/impl/TxServiceImpl.java | 16 ++--------- .../api/service/ScriptServiceTest.java | 3 +- 7 files changed, 76 insertions(+), 41 deletions(-) create mode 100644 src/main/java/org/cardanofoundation/explorer/api/projection/MintProjection.java diff --git a/src/main/java/org/cardanofoundation/explorer/api/mapper/MaTxMintMapper.java b/src/main/java/org/cardanofoundation/explorer/api/mapper/MaTxMintMapper.java index d48cbb6c6a..983ac274c5 100644 --- a/src/main/java/org/cardanofoundation/explorer/api/mapper/MaTxMintMapper.java +++ b/src/main/java/org/cardanofoundation/explorer/api/mapper/MaTxMintMapper.java @@ -1,8 +1,10 @@ package org.cardanofoundation.explorer.api.mapper; +import org.cardanofoundation.explorer.api.model.response.token.TokenMetadataResponse; import org.cardanofoundation.explorer.api.model.response.token.TokenMintTxResponse; import org.cardanofoundation.explorer.api.model.response.tx.TxMintingResponse; import org.cardanofoundation.explorer.api.projection.AddressInputOutputProjection; +import org.cardanofoundation.explorer.api.projection.MintProjection; import org.cardanofoundation.explorer.api.util.HexUtils; import org.cardanofoundation.explorer.consumercommon.entity.MaTxMint; import org.mapstruct.Mapper; @@ -11,13 +13,6 @@ @Mapper(componentModel = "spring",imports={HexUtils.class}) public interface MaTxMintMapper { - @Mapping(target = "assetName", - expression = "java(HexUtils.fromHex(maTxMint.getIdent().getName(), maTxMint.getIdent().getFingerprint()))") - @Mapping(target = "policy", source = "ident.policy") - @Mapping(target = "assetQuantity", source = "quantity") - @Mapping(target = "assetId", expression = "java(maTxMint.getIdent().getFingerprint())") - TxMintingResponse fromMaTxMint(MaTxMint maTxMint); - @Mapping(target = "assetName", expression = "java(HexUtils.fromHex(input.getAssetName(), input.getAssetId()))") @Mapping(target = "assetId", expression = "java(input.getAssetId())") @@ -28,4 +23,23 @@ TxMintingResponse fromAddressInputOutputProjection( @Mapping(target = "amount", source = "quantity") @Mapping(target = "time", source = "tx.block.time") TokenMintTxResponse fromMaTxMintToTokenMintTx(MaTxMint maTxMint); + + @Mapping(target = "assetName", + expression = "java(HexUtils.fromHex(mintProjection.getName(), mintProjection.getFingerprint()))") + @Mapping(target = "policy", source = "policy") + @Mapping(target = "assetQuantity", source = "assetQuantity") + @Mapping(target = "assetId", source = "fingerprint") + @Mapping(target = "metadata", + expression = "java(getMetadata(mintProjection))") + TxMintingResponse fromMintProjectionToTxMintingResponse(MintProjection mintProjection); + + default TokenMetadataResponse getMetadata(MintProjection mintProjection){ + TokenMetadataResponse tokenMetadataResponse = new TokenMetadataResponse(); + tokenMetadataResponse.setUrl(mintProjection.getUrl()); + tokenMetadataResponse.setTicker(mintProjection.getTicker()); + tokenMetadataResponse.setLogo(mintProjection.getLogo()); + tokenMetadataResponse.setDecimals(mintProjection.getDecimals()); + tokenMetadataResponse.setDescription(mintProjection.getDescription()); + return tokenMetadataResponse; + } } diff --git a/src/main/java/org/cardanofoundation/explorer/api/projection/MintProjection.java b/src/main/java/org/cardanofoundation/explorer/api/projection/MintProjection.java new file mode 100644 index 0000000000..82b5d0e25b --- /dev/null +++ b/src/main/java/org/cardanofoundation/explorer/api/projection/MintProjection.java @@ -0,0 +1,24 @@ +package org.cardanofoundation.explorer.api.projection; + +import java.math.BigInteger; + +public interface MintProjection { + String getName(); + + String getPolicy(); + + + BigInteger getAssetQuantity(); + + String getFingerprint(); + + String getUrl(); + + String getTicker(); + + Integer getDecimals(); + + String getLogo(); + + String getDescription(); +} diff --git a/src/main/java/org/cardanofoundation/explorer/api/repository/ledgersync/MaTxMintRepository.java b/src/main/java/org/cardanofoundation/explorer/api/repository/ledgersync/MaTxMintRepository.java index 103c7e5f4a..a68d8459d5 100644 --- a/src/main/java/org/cardanofoundation/explorer/api/repository/ledgersync/MaTxMintRepository.java +++ b/src/main/java/org/cardanofoundation/explorer/api/repository/ledgersync/MaTxMintRepository.java @@ -1,6 +1,7 @@ package org.cardanofoundation.explorer.api.repository.ledgersync; import java.math.BigInteger; +import org.cardanofoundation.explorer.api.projection.MintProjection; import org.cardanofoundation.explorer.consumercommon.entity.MaTxMint; import org.cardanofoundation.explorer.consumercommon.entity.MaTxMint_; import org.cardanofoundation.explorer.consumercommon.entity.Tx; @@ -14,6 +15,15 @@ public interface MaTxMintRepository extends JpaRepository { + @Query("SELECT ma.name as name, ma.policy as policy, mtm.quantity as assetQuantity," + + " am.fingerprint as fingerprint, am.url as url, am.ticker as ticker," + + " am.decimals as decimals, am.logo as logo, am.description as description" + + " FROM MaTxMint mtm " + + " JOIN MultiAsset ma ON ma.id = mtm.ident.id" + + " JOIN AssetMetadata am ON am.fingerprint = ma.fingerprint" + + " WHERE mtm.tx.id=:txId") + List findByTxId(@Param("txId") Long txId); + @EntityGraph(attributePaths = {MaTxMint_.IDENT}) List findByTx(@Param("tx") Tx tx); diff --git a/src/main/java/org/cardanofoundation/explorer/api/repository/ledgersync/MultiAssetRepository.java b/src/main/java/org/cardanofoundation/explorer/api/repository/ledgersync/MultiAssetRepository.java index bc04ab7244..9e3f84f17d 100644 --- a/src/main/java/org/cardanofoundation/explorer/api/repository/ledgersync/MultiAssetRepository.java +++ b/src/main/java/org/cardanofoundation/explorer/api/repository/ledgersync/MultiAssetRepository.java @@ -85,12 +85,16 @@ public interface MultiAssetRepository extends JpaRepository { List countAssetHoldersByPolicyIn(@Param("policyList") List policyList); List findByPolicy(@Param("policy") String policy, Pageable pageable); - - @Query(value = "SELECT topMultiAsset.* " - + " FROM script s " - + " CROSS JOIN LATERAL " - + " (SELECT ma.* FROM multi_asset ma WHERE ma.policy = s.hash ORDER BY ma.tx_count DESC LIMIT 5)" - + " AS topMultiAsset" - + " WHERE s.hash IN :scriptHashes", nativeQuery = true) - List findTopMultiAssetByScriptHashIn(@Param("scriptHashes") List scriptHashes); + @Query(value = "WITH firstResult AS (" + + " SELECT topMultiAsset.*" + + " FROM script s" + + " CROSS JOIN LATERAL" + + " (SELECT ma.name as name, ma.name_view as nameView, ma.policy as policy, ma.fingerprint as fingerprint FROM multi_asset ma WHERE ma.policy = s.hash ORDER BY ma.tx_count DESC LIMIT 5)" + + " AS topMultiAsset WHERE s.hash IN :scriptHashes)" + + " SELECT firstResult.policy as policy, firstResult.name as name, firstResult.nameView as nameView," + + " firstResult.fingerprint as fingerprint," + + " am.url as url, am.ticker as ticker, am.decimals as decimals, am.logo as logo, am.description as description" + + " FROM firstResult" + + " LEFT JOIN asset_metadata am ON am.fingerprint = firstResult.fingerprint",nativeQuery = true) + List findTopMultiAssetByScriptHashIn(@Param("scriptHashes") List scriptHashes); } diff --git a/src/main/java/org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl.java b/src/main/java/org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl.java index df0a06747d..f33e6b1896 100644 --- a/src/main/java/org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl.java +++ b/src/main/java/org/cardanofoundation/explorer/api/service/impl/ScriptServiceImpl.java @@ -22,8 +22,10 @@ import org.cardanofoundation.explorer.api.model.response.script.nativescript.NativeScriptResponse; import org.cardanofoundation.explorer.api.model.response.token.TokenAddressResponse; import org.cardanofoundation.explorer.api.model.response.token.TokenFilterResponse; +import org.cardanofoundation.explorer.api.model.response.token.TokenMetadataResponse; import org.cardanofoundation.explorer.api.model.response.tx.ContractResponse; import org.cardanofoundation.explorer.api.projection.AddressTokenProjection; +import org.cardanofoundation.explorer.api.projection.TokenProjection; import org.cardanofoundation.explorer.api.repository.explorer.VerifiedScriptRepository; import org.cardanofoundation.explorer.api.repository.explorer.NativeScriptInfoRepository; import org.cardanofoundation.explorer.api.repository.explorer.SmartContractInfoRepository; @@ -109,9 +111,9 @@ public BaseFilterResponse getNativeScripts(NativeScr ); Page nativeScriptPage = nativeScriptInfoRepository.findAll( NativeScriptInfoSpecification.filter(currrentBlock.getSlotNo(), filterRequest), pageable); - List multiAssetList = multiAssetRepository.findTopMultiAssetByScriptHashIn( + List tokenProjectionList = multiAssetRepository.findTopMultiAssetByScriptHashIn( nativeScriptPage.stream().map(NativeScriptInfo::getScriptHash).toList()); - List tokenResponses = createTokenResponse(multiAssetList); + List tokenResponses = createTokenResponse(tokenProjectionList); Map> tokenResponseMap = tokenResponses.stream().collect(Collectors.groupingBy(TokenFilterResponse::getPolicy)); Page nativeScriptPageResponse = @@ -135,13 +137,8 @@ public BaseFilterResponse getNativeScripts(NativeScr return new BaseFilterResponse<>(nativeScriptPageResponse); } - private List createTokenResponse(List tokens) { + private List createTokenResponse(List tokens) { List tokenResponses; - Set subjects = tokens.stream().map( - ma -> ma.getPolicy() + ma.getName()).collect(Collectors.toSet()); - List assetMetadataList = assetMetadataRepository.findBySubjectIn(subjects); - Map assetMetadataMap = assetMetadataList.stream().collect( - Collectors.toMap(AssetMetadata::getSubject, Function.identity())); tokenResponses = tokens.stream().map( token -> { TokenFilterResponse tokenFilterResponse = new TokenFilterResponse(); @@ -149,8 +146,7 @@ private List createTokenResponse(List tokens) { tokenFilterResponse.setName(token.getName()); tokenFilterResponse.setFingerprint(token.getFingerprint()); tokenFilterResponse.setDisplayName(token.getNameView()); - tokenFilterResponse.setMetadata(assetMetadataMapper.fromAssetMetadata( - assetMetadataMap.get(token.getPolicy() + token.getName()))); + tokenFilterResponse.setMetadata(new TokenMetadataResponse(token.getUrl(),token.getTicker(),token.getDecimals(),token.getLogo(),token.getDescription())); return tokenFilterResponse; }).toList(); return tokenResponses; diff --git a/src/main/java/org/cardanofoundation/explorer/api/service/impl/TxServiceImpl.java b/src/main/java/org/cardanofoundation/explorer/api/service/impl/TxServiceImpl.java index 1e0547d0cc..4dbe7d2634 100644 --- a/src/main/java/org/cardanofoundation/explorer/api/service/impl/TxServiceImpl.java +++ b/src/main/java/org/cardanofoundation/explorer/api/service/impl/TxServiceImpl.java @@ -631,22 +631,10 @@ private void getInstantaneousRewards(Tx tx, TxResponse txResponse) { * @param txResponse response data of transaction */ private void getMints(Tx tx, TxResponse txResponse) { - List maTxMints = maTxMintRepository.findByTx(tx); - Set subjects = maTxMints.stream().map( - ma -> ma.getIdent().getPolicy() + ma.getIdent().getName()).collect(Collectors.toSet()); - var assetMetadataList = assetMetadataRepository.findBySubjectIn(subjects); - var assetMetadataMap = assetMetadataList.stream().collect(Collectors.toMap( - AssetMetadata::getSubject, Function.identity() - )); + List maTxMints = maTxMintRepository.findByTxId(tx.getId()); if (!CollectionUtils.isEmpty(maTxMints)) { txResponse.setMints(maTxMints.stream().map( - ma -> { - TxMintingResponse txMintingResponse = maTxMintMapper.fromMaTxMint(ma); - String subject = ma.getIdent().getPolicy() + ma.getIdent().getName(); - txMintingResponse.setMetadata( - assetMetadataMapper.fromAssetMetadata(assetMetadataMap.get(subject))); - return txMintingResponse; - }).collect(Collectors.toList())); + maTxMintMapper::fromMintProjectionToTxMintingResponse).collect(Collectors.toList())); } } diff --git a/src/test/java/org/cardanofoundation/explorer/api/service/ScriptServiceTest.java b/src/test/java/org/cardanofoundation/explorer/api/service/ScriptServiceTest.java index 5956de38e2..df1eff4f34 100644 --- a/src/test/java/org/cardanofoundation/explorer/api/service/ScriptServiceTest.java +++ b/src/test/java/org/cardanofoundation/explorer/api/service/ScriptServiceTest.java @@ -105,8 +105,7 @@ void testGetNativeScripts() { when(nativeScriptInfoRepository .findAll(any(Specification.class), any(Pageable.class))) .thenReturn(new PageImpl<>(scriptList)); - when(assetMetadataRepository.findBySubjectIn(any())) - .thenReturn(List.of()); + when(multiAssetRepository.findTopMultiAssetByScriptHashIn(any())).thenReturn(List.of()); var response = scriptService.getNativeScripts(request, pageable); // Assert Assertions.assertEquals(1, response.getTotalItems());