Skip to content

Commit a7bce12

Browse files
authored
Account & Namespace pagination (#630)
* Fixed #627 - Added account & namespace pagination * Updated e2e tests * removed importance in account order by * Fixed e2e tests * Fixed comments
1 parent fcfb08f commit a7bce12

25 files changed

+528
-133
lines changed

e2e/infrastructure/AccountHttp.spec.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ import { NamespaceRegistrationTransaction } from '../../src/model/transaction/Na
3333
import { TransferTransaction } from '../../src/model/transaction/TransferTransaction';
3434
import { UInt64 } from '../../src/model/UInt64';
3535
import { IntegrationTestHelper } from './IntegrationTestHelper';
36+
import { AccountPaginationStreamer } from '../../src/infrastructure/paginationStreamer/AccountPaginationStreamer';
37+
import { toArray, take } from 'rxjs/operators';
38+
import { deepEqual } from 'assert';
39+
import { Order } from '../../src/infrastructure/infrastructure';
40+
import { AccountOrderBy } from '../../src/infrastructure/searchCriteria/AccountOrderBy';
3641

3742
describe('AccountHttp', () => {
3843
const helper = new IntegrationTestHelper();
@@ -178,6 +183,26 @@ describe('AccountHttp', () => {
178183
});
179184
});
180185

186+
describe('searchAccount', () => {
187+
it('should return account info', async () => {
188+
const info = await accountRepository.search({}).toPromise();
189+
expect(info.data.length).to.be.greaterThan(0);
190+
});
191+
});
192+
193+
describe('searchAccount with streamer', () => {
194+
it('should return account info', async () => {
195+
const streamer = new AccountPaginationStreamer(accountRepository);
196+
const infoStreamer = await streamer
197+
.search({ pageSize: 20, order: Order.Asc, orderBy: AccountOrderBy.Id })
198+
.pipe(take(20), toArray())
199+
.toPromise();
200+
const info = await accountRepository.search({ pageSize: 20, order: Order.Asc, orderBy: AccountOrderBy.Id }).toPromise();
201+
expect(infoStreamer.length).to.be.greaterThan(0);
202+
deepEqual(infoStreamer[0], info.data[0]);
203+
});
204+
});
205+
181206
describe('transactions', () => {
182207
it('should not return accounts when account does not exist', () => {
183208
return accountRepository

e2e/infrastructure/NamespaceHttp.spec.ts

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ import { Deadline } from '../../src/model/transaction/Deadline';
2525
import { NamespaceRegistrationTransaction } from '../../src/model/transaction/NamespaceRegistrationTransaction';
2626
import { UInt64 } from '../../src/model/UInt64';
2727
import { IntegrationTestHelper } from './IntegrationTestHelper';
28+
import { NamespacePaginationStreamer } from '../../src/infrastructure/paginationStreamer/NamespacePaginationStreamer';
29+
import { take, toArray } from 'rxjs/operators';
30+
import { Order } from '../../src/infrastructure/infrastructure';
2831

2932
describe('NamespaceHttp', () => {
3033
let defaultNamespaceId: NamespaceId;
@@ -90,23 +93,9 @@ describe('NamespaceHttp', () => {
9093
});
9194
});
9295

93-
describe('getNamespacesFromAccount', () => {
94-
it('should return namespace data given publicKeyNemesis', async () => {
95-
const namespaces = await namespaceRepository.getNamespacesFromAccount(account.address).toPromise();
96-
deepEqual(namespaces[0].ownerAddress, account.address);
97-
});
98-
});
99-
100-
describe('getNamespacesFromAccounts', () => {
101-
it('should return namespaces data given publicKeyNemesis', async () => {
102-
const namespaces = await namespaceRepository.getNamespacesFromAccounts([account.address]).toPromise();
103-
deepEqual(namespaces[0].ownerAddress, account.address);
104-
});
105-
});
106-
10796
describe('getNamespacesName', () => {
10897
it('should return namespace name given array of namespaceIds', async () => {
109-
const namespaceNames = await namespaceRepository.getNamespacesName([defaultNamespaceId]).toPromise();
98+
const namespaceNames = await namespaceRepository.getNamespacesNames([defaultNamespaceId]).toPromise();
11099
expect(namespaceNames[0].name).to.be.equal('currency');
111100
});
112101
});
@@ -124,4 +113,24 @@ describe('NamespaceHttp', () => {
124113
expect(address.plain()).to.be.equal(account.address.plain());
125114
});
126115
});
116+
117+
describe('searchNamespace', () => {
118+
it('should return namespace info', async () => {
119+
const info = await namespaceRepository.search({ ownerAddress: account.address }).toPromise();
120+
expect(info.data.length).to.be.greaterThan(0);
121+
});
122+
});
123+
124+
describe('searchNamespace with streamer', () => {
125+
it('should return namespace info', async () => {
126+
const streamer = new NamespacePaginationStreamer(namespaceRepository);
127+
const infoStreamer = await streamer
128+
.search({ ownerAddress: account.address, pageSize: 20, order: Order.Desc })
129+
.pipe(take(20), toArray())
130+
.toPromise();
131+
const info = await namespaceRepository.search({ pageSize: 20, order: Order.Desc }).toPromise();
132+
expect(infoStreamer.length).to.be.greaterThan(0);
133+
deepEqual(infoStreamer[0], info.data[0]);
134+
});
135+
});
127136
});

e2e/service/AccountService.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ describe('AccountService', () => {
8585

8686
describe('call accountNamespacesWithName', () => {
8787
it('accountNamespacesWithName', async () => {
88-
const info = await accountService.accountNamespacesWithName([account.address]).toPromise();
88+
const info = await accountService.accountNamespacesWithName(account.address).toPromise();
8989
expect(info).to.not.be.undefined;
9090
expect(info.find((i) => i.id.equals(namespaceId))).to.not.be.undefined;
9191
expect(info.find((i) => i.id.equals(namespaceId))?.namespaceName).to.be.equal(name);

package-lock.json

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@
9999
"ripemd160": "^2.0.2",
100100
"rxjs": "^6.5.3",
101101
"rxjs-compat": "^6.5.3",
102-
"symbol-openapi-typescript-fetch-client": "0.9.4",
102+
"symbol-openapi-typescript-fetch-client": "0.9.5-SNAPSHOT.202007141039",
103103
"tweetnacl": "^1.0.3",
104104
"utf8": "^3.0.0",
105105
"ws": "^7.2.3"

src/infrastructure/AccountHttp.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ import { Http } from './Http';
2727
import { SupplementalPublicKeys } from '../model/account/SupplementalPublicKeys';
2828
import { AccountLinkPublicKey } from '../model/account/AccountLinkPublicKey';
2929
import { AccountLinkVotingKey } from '../model/account/AccountLinkVotingKey';
30+
import { AccountSearchCriteria } from './searchCriteria/AccountSearchCriteria';
31+
import { DtoMapping } from '../core/utils/DtoMapping';
32+
import { Page } from './Page';
3033

3134
/**
3235
* Account http repository.
@@ -71,6 +74,25 @@ export class AccountHttp extends Http implements AccountRepository {
7174
return this.call(this.accountRoutesApi.getAccountsInfo(accountIds), (body) => body.map(this.toAccountInfo));
7275
}
7376

77+
/**
78+
* Gets an array of accounts.
79+
* @param criteria - Account search criteria
80+
* @returns Observable<AccountInfo[]>
81+
*/
82+
public search(criteria: AccountSearchCriteria): Observable<Page<AccountInfo>> {
83+
return this.call(
84+
this.accountRoutesApi.searchAccounts(
85+
criteria.pageSize,
86+
criteria.pageNumber,
87+
criteria.offset,
88+
DtoMapping.mapEnum(criteria.order),
89+
DtoMapping.mapEnum(criteria.orderBy),
90+
criteria.mosaicId?.toHex(),
91+
),
92+
(body) => super.toPage(body.pagination, body.data, this.toAccountInfo),
93+
);
94+
}
95+
7496
/**
7597
* This method maps a AccountInfoDTO from rest to the SDK's AccountInfo model object.
7698
*

src/infrastructure/AccountRepository.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@
1717
import { Observable } from 'rxjs';
1818
import { AccountInfo } from '../model/account/AccountInfo';
1919
import { Address } from '../model/account/Address';
20+
import { Searcher } from './paginationStreamer/Searcher';
21+
import { AccountSearchCriteria } from './searchCriteria/AccountSearchCriteria';
2022

2123
/**
2224
* Account interface repository.
2325
*
2426
* @since 1.0
2527
*/
26-
export interface AccountRepository {
28+
export interface AccountRepository extends Searcher<AccountInfo, AccountSearchCriteria> {
2729
/**
2830
* Gets an AccountInfo for an account.
2931
* @param address Address

src/infrastructure/BlockHttp.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export class BlockHttp extends Http implements BlockRepository {
6060
}
6161

6262
/**
63-
* Gets an array of bocks.
63+
* Gets an array of blocks.
6464
* @param criteria - Block search criteria
6565
* @returns Observable<BlockInfo[]>
6666
*/

src/infrastructure/NamespaceHttp.ts

Lines changed: 35 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ import { NetworkType } from '../model/network/NetworkType';
3333
import { UInt64 } from '../model/UInt64';
3434
import { Http } from './Http';
3535
import { NamespaceRepository } from './NamespaceRepository';
36-
import { QueryParams } from './QueryParams';
36+
import { NamespaceSearchCriteria } from './searchCriteria/NamespaceSearchCriteria';
37+
import { Page } from './Page';
38+
import { DtoMapping } from '../core/utils/DtoMapping';
3739

3840
/**
3941
* Namespace http repository.
@@ -119,44 +121,12 @@ export class NamespaceHttp extends Http implements NamespaceRepository {
119121
return this.call(this.namespaceRoutesApi.getNamespace(namespaceId.toHex()), (body) => this.toNamespaceInfo(body));
120122
}
121123

122-
/**
123-
* Gets array of NamespaceInfo for an account
124-
* @param address - Address
125-
* @param queryParams - (Optional) Query params
126-
* @returns Observable<NamespaceInfo[]>
127-
*/
128-
public getNamespacesFromAccount(address: Address, queryParams?: QueryParams): Observable<NamespaceInfo[]> {
129-
return this.call(
130-
this.namespaceRoutesApi.getNamespacesFromAccount(
131-
address.plain(),
132-
this.queryParams(queryParams).pageSize,
133-
this.queryParams(queryParams).id,
134-
),
135-
(body) => body.namespaces.map((namespaceInfoDTO) => this.toNamespaceInfo(namespaceInfoDTO)),
136-
);
137-
}
138-
139-
/**
140-
* Gets array of NamespaceInfo for different account
141-
* @param addresses - Array of Address
142-
* @param queryParams - (Optional) Query params
143-
* @returns Observable<NamespaceInfo[]>
144-
*/
145-
public getNamespacesFromAccounts(addresses: Address[]): Observable<NamespaceInfo[]> {
146-
const publicKeysBody = {
147-
addresses: addresses.map((address) => address.plain()),
148-
};
149-
return this.call(this.namespaceRoutesApi.getNamespacesFromAccounts(publicKeysBody), (body) =>
150-
body.namespaces.map((namespaceInfoDTO) => this.toNamespaceInfo(namespaceInfoDTO)),
151-
);
152-
}
153-
154124
/**
155125
* Gets array of NamespaceName for different namespaceIds
156126
* @param namespaceIds - Array of namespace ids
157127
* @returns Observable<NamespaceName[]>
158128
*/
159-
public getNamespacesName(namespaceIds: NamespaceId[]): Observable<NamespaceName[]> {
129+
public getNamespacesNames(namespaceIds: NamespaceId[]): Observable<NamespaceName[]> {
160130
const namespaceIdsBody = {
161131
namespaceIds: namespaceIds.map((id) => id.toHex()),
162132
};
@@ -171,6 +141,27 @@ export class NamespaceHttp extends Http implements NamespaceRepository {
171141
);
172142
}
173143

144+
/**
145+
* Gets an array of namespaces.
146+
* @param criteria - Namespace search criteria
147+
* @returns Observable<NamespaceInfo[]>
148+
*/
149+
public search(criteria: NamespaceSearchCriteria): Observable<Page<NamespaceInfo>> {
150+
return this.call(
151+
this.namespaceRoutesApi.searchNamespaces(
152+
criteria.ownerAddress?.plain(),
153+
criteria.registrationType?.valueOf(),
154+
criteria.level0?.toHex(),
155+
criteria.aliasType?.valueOf(),
156+
criteria.pageSize,
157+
criteria.pageNumber,
158+
criteria.offset,
159+
DtoMapping.mapEnum(criteria.order),
160+
),
161+
(body) => super.toPage(body.pagination, body.data, this.toNamespaceInfo),
162+
);
163+
}
164+
174165
/**
175166
* Gets the MosaicId from a MosaicAlias
176167
* @param namespaceId - the namespaceId of the namespace
@@ -239,16 +230,22 @@ export class NamespaceHttp extends Http implements NamespaceRepository {
239230
dto.meta.id,
240231
dto.namespace.registrationType as number,
241232
dto.namespace.depth,
242-
this.extractLevels(dto.namespace),
233+
NamespaceHttp.extractLevels(dto.namespace),
243234
NamespaceId.createFromEncoded(dto.namespace.parentId),
244235
Address.createFromEncoded(dto.namespace.ownerAddress),
245236
UInt64.fromNumericString(dto.namespace.startHeight),
246237
UInt64.fromNumericString(dto.namespace.endHeight),
247-
this.extractAlias(dto.namespace),
238+
NamespaceHttp.extractAlias(dto.namespace),
248239
);
249240
}
250241

251-
private extractLevels(namespace: NamespaceDTO): NamespaceId[] {
242+
/**
243+
* Extract the namespace levels
244+
*
245+
* @internal
246+
* @param namespace
247+
*/
248+
private static extractLevels(namespace: NamespaceDTO): NamespaceId[] {
252249
const result: NamespaceId[] = [];
253250
if (namespace.level0) {
254251
result.push(NamespaceId.createFromEncoded(namespace.level0));
@@ -266,10 +263,9 @@ export class NamespaceHttp extends Http implements NamespaceRepository {
266263
* Extract the alias from a namespace
267264
*
268265
* @internal
269-
* @access private
270266
* @param namespace
271267
*/
272-
private extractAlias(namespace: NamespaceDTO): Alias {
268+
private static extractAlias(namespace: NamespaceDTO): Alias {
273269
if (namespace.alias && namespace.alias.type.valueOf() === AliasType.Mosaic) {
274270
return new MosaicAlias(new MosaicId(namespace.alias.mosaicId!));
275271
} else if (namespace.alias && namespace.alias.type.valueOf() === AliasType.Address) {

src/infrastructure/NamespaceRepository.ts

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,15 @@ import { MosaicNames } from '../model/mosaic/MosaicNames';
2222
import { NamespaceId } from '../model/namespace/NamespaceId';
2323
import { NamespaceInfo } from '../model/namespace/NamespaceInfo';
2424
import { NamespaceName } from '../model/namespace/NamespaceName';
25-
import { QueryParams } from './QueryParams';
25+
import { Searcher } from './paginationStreamer/Searcher';
26+
import { NamespaceSearchCriteria } from './searchCriteria/NamespaceSearchCriteria';
2627

2728
/**
2829
* Namespace interface repository.
2930
*
3031
* @since 1.0
3132
*/
32-
export interface NamespaceRepository {
33+
export interface NamespaceRepository extends Searcher<NamespaceInfo, NamespaceSearchCriteria> {
3334
/**
3435
* Get readable names for a set of accountIds.
3536
* Returns friendly names for accounts.
@@ -53,28 +54,12 @@ export interface NamespaceRepository {
5354
*/
5455
getNamespace(namespaceId: NamespaceId): Observable<NamespaceInfo>;
5556

56-
/**
57-
* Gets array of NamespaceInfo for an account
58-
* @param address - Address
59-
* @param queryParams - (Optional) Query params
60-
* @returns Observable<NamespaceInfo[]>
61-
*/
62-
getNamespacesFromAccount(address: Address, queryParams?: QueryParams): Observable<NamespaceInfo[]>;
63-
64-
/**
65-
* Gets array of NamespaceInfo for different account
66-
* @param addresses - Array of Address
67-
* @param queryParams - (Optional) Query params
68-
* @returns Observable<NamespaceInfo[]>
69-
*/
70-
getNamespacesFromAccounts(addresses: Address[], queryParams?: QueryParams): Observable<NamespaceInfo[]>;
71-
7257
/**
7358
* Gets array of NamespaceName for different namespaceIds
7459
* @param namespaceIds - Array of namespace ids
7560
* @returns Observable<NamespaceName[]>
7661
*/
77-
getNamespacesName(namespaceIds: NamespaceId[]): Observable<NamespaceName[]>;
62+
getNamespacesNames(namespaceIds: NamespaceId[]): Observable<NamespaceName[]>;
7863

7964
/**
8065
* Gets the MosaicId from a MosaicAlias

0 commit comments

Comments
 (0)