Skip to content

Commit 73f67b7

Browse files
committed
Merge branch 'development' into API-626-applications-page
2 parents 51b8c80 + 3909b76 commit 73f67b7

10 files changed

Lines changed: 331 additions & 117 deletions

File tree

src/common/indexer/elastic/elastic.indexer.service.ts

Lines changed: 134 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { HttpStatus, Injectable } from "@nestjs/common";
22
import { BinaryUtils } from "@multiversx/sdk-nestjs-common";
3-
import { ElasticQuery, QueryOperator, QueryType, QueryConditionOptions, ElasticSortOrder, ElasticSortProperty, TermsQuery, RangeGreaterThanOrEqual, MatchQuery } from "@multiversx/sdk-nestjs-elastic";
3+
import { ElasticQuery, QueryOperator, QueryType, QueryConditionOptions, ElasticSortOrder, ElasticSortProperty, RangeGreaterThanOrEqual, MatchQuery } from "@multiversx/sdk-nestjs-elastic";
44
import { IndexerInterface } from "../indexer.interface";
55
import { ApiConfigService } from "src/common/api-config/api.config.service";
66
import { CollectionFilter } from "src/endpoints/collections/entities/collection.filter";
@@ -281,9 +281,7 @@ export class ElasticIndexerService implements IndexerInterface {
281281

282282
const elasticOperations = await this.elasticService.getList('operations', 'txHash', elasticQuery);
283283

284-
for (const operation of elasticOperations) {
285-
this.processTransaction(operation);
286-
}
284+
this.bulkProcessTransactions(elasticOperations);
287285

288286
return elasticOperations;
289287
}
@@ -340,15 +338,15 @@ export class ElasticIndexerService implements IndexerInterface {
340338
.withMustMatchCondition('type', 'unsigned')
341339
.withPagination({ from: 0, size: transactionHashes.length + 1 })
342340
.withSort([{ name: 'timestamp', order: ElasticSortOrder.ascending }])
343-
.withTerms(new TermsQuery('originalTxHash', transactionHashes));
341+
.withMustMultiShouldCondition(transactionHashes, hash => QueryType.Match('originalTxHash', hash));
344342

345343
return await this.elasticService.getList('operations', 'scHash', elasticQuery);
346344
}
347345

348346
async getAccountsForAddresses(addresses: string[]): Promise<any[]> {
349347
const elasticQuery: ElasticQuery = ElasticQuery.create()
350348
.withPagination({ from: 0, size: addresses.length + 1 })
351-
.withTerms(new TermsQuery('address', addresses));
349+
.withMustMultiShouldCondition(addresses, address => QueryType.Match('address', address));
352350

353351
return await this.elasticService.getList('accounts', 'address', elasticQuery);
354352
}
@@ -385,9 +383,7 @@ export class ElasticIndexerService implements IndexerInterface {
385383

386384
const results = await this.elasticService.getList('operations', 'hash', elasticQuery);
387385

388-
for (const result of results) {
389-
this.processTransaction(result);
390-
}
386+
this.bulkProcessTransactions(results);
391387

392388
return results;
393389
}
@@ -550,9 +546,7 @@ export class ElasticIndexerService implements IndexerInterface {
550546

551547
const transactions = await this.elasticService.getList('operations', 'txHash', elasticQuery);
552548

553-
for (const transaction of transactions) {
554-
this.processTransaction(transaction);
555-
}
549+
this.bulkProcessTransactions(transactions);
556550

557551
return transactions;
558552
}
@@ -563,6 +557,19 @@ export class ElasticIndexerService implements IndexerInterface {
563557
}
564558
}
565559

560+
private bulkProcessTransactions(transactions: any[]) {
561+
if (!transactions || transactions.length === 0) {
562+
return;
563+
}
564+
565+
for (let i = 0; i < transactions.length; i++) {
566+
const transaction = transactions[i];
567+
if (transaction && !transaction.function) {
568+
transaction.function = transaction.operation;
569+
}
570+
}
571+
}
572+
566573
private buildTokenFilter(query: ElasticQuery, filter: TokenFilter): ElasticQuery {
567574
if (filter.includeMetaESDT === true) {
568575
query = query.withMustMultiShouldCondition([TokenType.FungibleESDT, TokenType.MetaESDT], type => QueryType.Match('type', type));
@@ -618,9 +625,7 @@ export class ElasticIndexerService implements IndexerInterface {
618625

619626
const results = await this.elasticService.getList('operations', 'hash', elasticQuerySc);
620627

621-
for (const result of results) {
622-
this.processTransaction(result);
623-
}
628+
this.bulkProcessTransactions(results);
624629

625630
return results;
626631
}
@@ -634,9 +639,11 @@ export class ElasticIndexerService implements IndexerInterface {
634639
return [];
635640
}
636641

642+
const maxSize = Math.min(hashes.length * 10, 1000);
643+
637644
const elasticQuery = ElasticQuery.create()
638645
.withMustMatchCondition('type', 'unsigned')
639-
.withPagination({ from: 0, size: 10000 })
646+
.withPagination({ from: 0, size: maxSize })
640647
.withSort([{ name: 'timestamp', order: ElasticSortOrder.ascending }])
641648
.withMustMultiShouldCondition(hashes, hash => QueryType.Match('originalTxHash', hash));
642649

@@ -648,19 +655,19 @@ export class ElasticIndexerService implements IndexerInterface {
648655
return [];
649656
}
650657

651-
const queries = identifiers.map((identifier) => QueryType.Match('identifier', identifier, QueryOperator.AND));
652-
653658
let elasticQuery = ElasticQuery.create();
654659

655660
if (pagination) {
656661
elasticQuery = elasticQuery.withPagination(pagination);
657662
}
658663

659664
elasticQuery = elasticQuery
660-
.withSort([{ name: "balanceNum", order: ElasticSortOrder.descending }])
665+
.withSort([
666+
{ name: "balanceNum", order: ElasticSortOrder.descending },
667+
{ name: 'timestamp', order: ElasticSortOrder.descending },
668+
])
661669
.withCondition(QueryConditionOptions.mustNot, [QueryType.Match('address', 'pending')])
662-
.withCondition(QueryConditionOptions.should, queries)
663-
.withSort([{ name: 'timestamp', order: ElasticSortOrder.descending }]);
670+
.withMustMultiShouldCondition(identifiers, identifier => QueryType.Match('identifier', identifier, QueryOperator.AND));
664671

665672
return await this.elasticService.getList('accountsesdt', 'identifier', elasticQuery);
666673
}
@@ -670,19 +677,19 @@ export class ElasticIndexerService implements IndexerInterface {
670677
return [];
671678
}
672679

673-
const queries = identifiers.map((identifier) => QueryType.Match('collection', identifier, QueryOperator.AND));
674-
675680
let elasticQuery = ElasticQuery.create();
676681

677682
if (pagination) {
678683
elasticQuery = elasticQuery.withPagination(pagination);
679684
}
680685

681686
elasticQuery = elasticQuery
682-
.withSort([{ name: "balanceNum", order: ElasticSortOrder.descending }])
687+
.withSort([
688+
{ name: "balanceNum", order: ElasticSortOrder.descending },
689+
{ name: 'timestamp', order: ElasticSortOrder.descending },
690+
])
683691
.withCondition(QueryConditionOptions.mustNot, [QueryType.Match('address', 'pending')])
684-
.withCondition(QueryConditionOptions.should, queries)
685-
.withSort([{ name: 'timestamp', order: ElasticSortOrder.descending }]);
692+
.withMustMultiShouldCondition(identifiers, identifier => QueryType.Match('collection', identifier, QueryOperator.AND));
686693

687694
return await this.elasticService.getList('accountsesdt', 'identifier', elasticQuery);
688695
}
@@ -713,11 +720,22 @@ export class ElasticIndexerService implements IndexerInterface {
713720
]);
714721
}
715722

716-
let elasticNfts = await this.elasticService.getList('tokens', 'identifier', elasticQuery);
717-
if (elasticNfts.length === 0 && identifier !== undefined) {
718-
elasticNfts = await this.elasticService.getList('accountsesdt', 'identifier', ElasticQuery.create().withMustMatchCondition('identifier', identifier, QueryOperator.AND));
723+
if (identifier !== undefined) {
724+
const [tokensResult, accountsResult] = await Promise.all([
725+
this.elasticService.getList('tokens', 'identifier', elasticQuery).catch(() => []),
726+
this.elasticService.getList('accountsesdt', 'identifier',
727+
ElasticQuery.create()
728+
.withMustMatchCondition('identifier', identifier, QueryOperator.AND)
729+
.withPagination(pagination)
730+
).catch(() => []),
731+
]);
732+
733+
const elasticNfts = tokensResult.length > 0 ? tokensResult : accountsResult;
734+
return elasticNfts;
735+
} else {
736+
const elasticNfts = await this.elasticService.getList('tokens', 'identifier', elasticQuery);
737+
return elasticNfts;
719738
}
720-
return elasticNfts;
721739
}
722740

723741
async getTransactionBySenderAndNonce(sender: string, nonce: number): Promise<any[]> {
@@ -752,7 +770,7 @@ export class ElasticIndexerService implements IndexerInterface {
752770
'data.uris',
753771
])
754772
.withMustExistCondition('identifier')
755-
.withMustMultiShouldCondition([EsdtType.NonFungibleESDT, EsdtType.SemiFungibleESDT], type => QueryType.Match('type', type))
773+
.withMustMultiShouldCondition([EsdtType.NonFungibleESDT, EsdtType.SemiFungibleESDT, EsdtType.MetaESDT], type => QueryType.Match('type', type))
756774
.withPagination({ from: 0, size: 10000 });
757775

758776
return await this.elasticService.getScrollableList('tokens', 'identifier', query, action);
@@ -821,52 +839,100 @@ export class ElasticIndexerService implements IndexerInterface {
821839
}
822840
}
823841

824-
const elasticQuery = ElasticQuery.create()
825-
.withMustExistCondition('identifier')
826-
.withMustMatchCondition('address', address)
827-
.withPagination({ from: 0, size: 0 })
828-
.withMustMatchCondition('token', filter.collection, QueryOperator.AND)
829-
.withMustMultiShouldCondition(filter.identifiers, identifier => QueryType.Match('token', identifier, QueryOperator.AND))
830-
.withSearchWildcardCondition(filter.search, ['token', 'name'])
831-
.withMustMultiShouldCondition(filterTypes, type => QueryType.Match('type', type))
832-
.withMustMultiShouldCondition(filter.subType, subType => QueryType.Match('type', subType))
833-
.withExtra({
834-
aggs: {
835-
collections: {
836-
composite: {
837-
size: 10000,
838-
sources: [
839-
{
840-
collection: {
841-
terms: {
842-
field: 'token',
843-
},
844-
},
845-
},
846-
],
842+
const data: { collection: string, count: number, balance: number }[] = [];
843+
let afterKey: any = null;
844+
let remainingToSkip = pagination.from;
845+
let remainingToCollect = pagination.size;
846+
847+
while (data.length < pagination.size) {
848+
const batchSize = Math.min(1000, remainingToSkip + remainingToCollect);
849+
850+
const compositeAgg: any = {
851+
size: batchSize,
852+
sources: [
853+
{
854+
collection: {
855+
terms: {
856+
field: 'token',
857+
order: 'asc',
858+
},
847859
},
848-
aggs: {
849-
balance: {
850-
sum: {
851-
field: 'balanceNum',
860+
},
861+
],
862+
};
863+
864+
if (afterKey) {
865+
compositeAgg.after = afterKey;
866+
}
867+
868+
const elasticQuery = ElasticQuery.create()
869+
.withMustExistCondition('identifier')
870+
.withMustMatchCondition('address', address)
871+
.withPagination({ from: 0, size: 0 })
872+
.withMustMatchCondition('token', filter.collection, QueryOperator.AND)
873+
.withMustMultiShouldCondition(filter.identifiers, identifier => QueryType.Match('token', identifier, QueryOperator.AND))
874+
.withSearchWildcardCondition(filter.search, ['token', 'name'])
875+
.withMustMultiShouldCondition(filterTypes, type => QueryType.Match('type', type))
876+
.withMustMultiShouldCondition(filter.subType, subType => QueryType.Match('type', subType))
877+
.withExtra({
878+
aggs: {
879+
collections: {
880+
composite: compositeAgg,
881+
aggs: {
882+
balance: {
883+
sum: {
884+
field: 'balanceNum',
885+
},
852886
},
853887
},
854888
},
855889
},
856-
},
857-
});
890+
});
858891

859-
const result = await this.elasticService.post(`${this.apiConfigService.getElasticUrl()}/accountsesdt/_search`, elasticQuery.toJson());
892+
const result = await this.elasticService.post(`${this.apiConfigService.getElasticUrl()}/accountsesdt/_search`, elasticQuery.toJson());
893+
const buckets = result?.data?.aggregations?.collections?.buckets || [];
860894

861-
const buckets = result?.data?.aggregations?.collections?.buckets;
895+
if (buckets.length === 0) {
896+
break;
897+
}
862898

863-
let data: { collection: string, count: number, balance: number }[] = buckets.map((bucket: any) => ({
864-
collection: bucket.key.collection,
865-
count: bucket.doc_count,
866-
balance: bucket.balance.value,
867-
}));
899+
const batchData: { collection: string, count: number, balance: number }[] = buckets.map((bucket: any) => ({
900+
collection: bucket.key.collection,
901+
count: bucket.doc_count,
902+
balance: bucket.balance.value,
903+
}));
904+
905+
if (remainingToSkip > 0) {
906+
const skipFromBatch = Math.min(remainingToSkip, batchData.length);
907+
remainingToSkip -= skipFromBatch;
908+
909+
if (remainingToSkip === 0) {
910+
const collectFromBatch = Math.min(remainingToCollect, batchData.length - skipFromBatch);
911+
data.push(...batchData.slice(skipFromBatch, skipFromBatch + collectFromBatch));
912+
remainingToCollect -= collectFromBatch;
913+
}
914+
} else {
915+
const collectFromBatch = Math.min(remainingToCollect, batchData.length);
916+
data.push(...batchData.slice(0, collectFromBatch));
917+
remainingToCollect -= collectFromBatch;
918+
}
919+
920+
if (remainingToCollect === 0) {
921+
break;
922+
}
923+
924+
const aggregations = result?.data?.aggregations?.collections;
925+
if (aggregations?.after_key) {
926+
afterKey = aggregations.after_key;
927+
} else {
928+
break;
929+
}
930+
931+
if (buckets.length < batchSize) {
932+
break;
933+
}
934+
}
868935

869-
data = data.slice(pagination.from, pagination.from + pagination.size);
870936
return data;
871937
}
872938

src/common/rabbitmq/rabbitmq.nft.handler.service.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,6 @@ export class RabbitMqNftHandlerService {
104104

105105
const collectionIdentifier = identifier.split('-').slice(0, 2).join('-');
106106
const collectionType = await this.getCollectionType(collectionIdentifier);
107-
if (collectionType === NftType.MetaESDT) {
108-
return false;
109-
}
110107

111108
this.logger.log(`Detected 'ESDTNFTCreate' event for NFT with identifier '${identifier}' and collection type '${collectionType}'`);
112109

0 commit comments

Comments
 (0)