Skip to content

Commit ff83361

Browse files
authored
Alias resolution for accountHttp (#540)
* Fixed #499 - Added AccountService * Fixed e2e tests * Fixed lints * Fixed years * another year fix * Chaned to use address array and reduce rest calls * handle empty array * Fixed typos * more typo fix * Fixed function name
1 parent c1aab78 commit ff83361

File tree

10 files changed

+533
-1
lines changed

10 files changed

+533
-1
lines changed

e2e/service/AccountService.spec.ts

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Copyright 2020 NEM
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { expect } from 'chai';
18+
import { Account } from '../../src/model/account/Account';
19+
import { NetworkType } from '../../src/model/network/NetworkType';
20+
import { Deadline } from '../../src/model/transaction/Deadline';
21+
import { UInt64 } from '../../src/model/UInt64';
22+
import { IntegrationTestHelper } from '../infrastructure/IntegrationTestHelper';
23+
import { AccountService } from '../../src/service/AccountService';
24+
import { NamespaceRegistrationTransaction } from '../../src/model/transaction/NamespaceRegistrationTransaction';
25+
import { NamespaceId } from '../../src/model/namespace/NamespaceId';
26+
27+
describe('AccountService', () => {
28+
const helper = new IntegrationTestHelper();
29+
let generationHash: string;
30+
let account: Account;
31+
let networkType: NetworkType;
32+
let accountService: AccountService;
33+
let namespaceId: NamespaceId;
34+
const name = 'root-test-namespace-' + Math.floor(Math.random() * 10000);
35+
36+
before(() => {
37+
return helper.start().then(() => {
38+
account = helper.account;
39+
generationHash = helper.generationHash;
40+
networkType = helper.networkType;
41+
accountService = new AccountService(helper.repositoryFactory);
42+
});
43+
});
44+
before(() => {
45+
return helper.listener.open();
46+
});
47+
48+
after(() => {
49+
helper.listener.close();
50+
});
51+
52+
/**
53+
* =========================
54+
* Setup test data
55+
* =========================
56+
*/
57+
describe('Create a namespace', () => {
58+
it('Announce NamespaceRegistrationTransaction', () => {
59+
const registerNamespaceTransaction = NamespaceRegistrationTransaction.createRootNamespace(
60+
Deadline.create(),
61+
name,
62+
UInt64.fromUint(300000),
63+
networkType,
64+
helper.maxFee,
65+
);
66+
namespaceId = new NamespaceId(name);
67+
const signedTransaction = registerNamespaceTransaction.signWith(account, generationHash);
68+
return helper.announce(signedTransaction);
69+
});
70+
});
71+
72+
/**
73+
* =========================
74+
* Test
75+
* =========================
76+
*/
77+
describe('call accountInfoWithResolvedMosaic', () => {
78+
it('accountInfoWithResolvedMosaic', async () => {
79+
const info = await accountService.accountInfoWithResolvedMosaic([account.address]).toPromise();
80+
expect(info).to.not.be.undefined;
81+
expect(info[0].resolvedMosaics).to.not.be.undefined;
82+
expect(info[0].resolvedMosaics?.length).to.be.greaterThan(0);
83+
});
84+
});
85+
86+
describe('call accountNamespacesWithName', () => {
87+
it('accountNamespacesWithName', async () => {
88+
const info = await accountService.accountNamespacesWithName([account.address]).toPromise();
89+
expect(info).to.not.be.undefined;
90+
expect(info.find((i) => i.id.equals(namespaceId))).to.not.be.undefined;
91+
expect(info.find((i) => i.id.equals(namespaceId))?.namespaceName).to.be.equal(name);
92+
});
93+
});
94+
});
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright 2020 NEM
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { AccountInfo } from './AccountInfo';
18+
import { ResolvedMosaic } from '../mosaic/ResolvedMosaic';
19+
20+
/**
21+
* Account info with resolved mosaic
22+
*/
23+
export type AccountInfoResolvedMosaic = AccountInfo & { resolvedMosaics?: ResolvedMosaic[] };

src/model/model.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export * from './account/MultisigAccountGraphInfo';
2727
export * from './account/MultisigAccountInfo';
2828
export * from './account/PublicAccount';
2929
export * from './account/AccountNames';
30+
export * from './account/AccountInfoResolvedMosaic';
3031

3132
// Blockchain
3233
export * from './blockchain/BlockchainScore';
@@ -51,6 +52,7 @@ export * from './mosaic/NetworkCurrencyLocal';
5152
export * from './mosaic/NetworkCurrencyPublic';
5253
export * from './mosaic/NetworkHarvestLocal';
5354
export * from './mosaic/MosaicNames';
55+
export * from './mosaic/ResolvedMosaic';
5456

5557
// Mosaic
5658
export * from './metadata/Metadata';
@@ -69,6 +71,7 @@ export * from './namespace/NamespaceName';
6971
export * from './namespace/NamespaceRegistrationType';
7072
export * from './namespace/AliasAction';
7173
export * from './namespace/EmptyAlias';
74+
export * from './namespace/NamespaceInfoWithName';
7275

7376
// Network
7477

src/model/mosaic/ResolvedMosaic.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright 2020 NEM
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { NamespaceName } from '../namespace/NamespaceName';
18+
import { Mosaic } from './Mosaic';
19+
20+
/**
21+
* Resolved mosaic model with namespace name
22+
*/
23+
export type ResolvedMosaic = Mosaic & { namespaceName?: NamespaceName };
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright 2020 NEM
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { NamespaceInfo } from './NamespaceInfo';
18+
19+
/**
20+
* Resolved mosaic model with namespace name
21+
*/
22+
export type NamespaceInfoWithName = NamespaceInfo & { namespaceName?: string };

src/service/AccountService.ts

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/*
2+
* Copyright 2020 NEM
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { Observable, of } from 'rxjs';
18+
import { map, withLatestFrom } from 'rxjs/operators';
19+
import { RepositoryFactory } from '../infrastructure/RepositoryFactory';
20+
import { AccountRepository } from '../infrastructure/AccountRepository';
21+
import { NamespaceRepository } from '../infrastructure/NamespaceRepository';
22+
import { Address } from '../model/account/Address';
23+
import { mergeMap } from 'rxjs/operators';
24+
import { DtoMapping } from '../core/utils/DtoMapping';
25+
import { IAccountService } from './interfaces/IAccountService';
26+
import { NamespaceInfoWithName } from '../model/namespace/NamespaceInfoWithName';
27+
import { ResolvedMosaic } from '../model/mosaic/ResolvedMosaic';
28+
import { Mosaic } from '../model/mosaic/Mosaic';
29+
import { MosaicId } from '../model/mosaic/MosaicId';
30+
import { NamespaceId } from '../model/namespace/NamespaceId';
31+
import { AccountInfoResolvedMosaic } from '../model/account/AccountInfoResolvedMosaic';
32+
import { AccountInfo } from '../model/account/AccountInfo';
33+
import { NamespaceName } from '../model/namespace/NamespaceName';
34+
/**
35+
* Account Service
36+
*/
37+
export class AccountService implements IAccountService {
38+
private readonly accountRepository: AccountRepository;
39+
40+
private readonly namespaceRepository: NamespaceRepository;
41+
42+
/**
43+
* Constructor
44+
* @param repositoryFactory
45+
*/
46+
constructor(public readonly repositoryFactory: RepositoryFactory) {
47+
this.accountRepository = repositoryFactory.createAccountRepository();
48+
this.namespaceRepository = repositoryFactory.createNamespaceRepository();
49+
}
50+
51+
/**
52+
* Get account info with resolved mosaic
53+
* @param addresses Array of addresses
54+
*/
55+
public accountInfoWithResolvedMosaic(addresses: Address[]): Observable<AccountInfoResolvedMosaic[]> {
56+
const accountInfoObservable = this.accountRepository.getAccountsInfo(addresses);
57+
const distinctNames = accountInfoObservable.pipe(
58+
mergeMap((info) => {
59+
const namespaceIds = this.getDistinctNamespaceIdFromAccountInfos(info);
60+
if (namespaceIds.length) {
61+
return this.namespaceRepository.getNamespacesName(namespaceIds);
62+
}
63+
return of([]);
64+
}),
65+
);
66+
67+
return accountInfoObservable.pipe(
68+
withLatestFrom(distinctNames),
69+
map(([infos, names]) => {
70+
return infos.map((info) => {
71+
const resolved = this.resolveMosaics(info.mosaics, names);
72+
return DtoMapping.assign(info, { resolvedMosaics: resolved });
73+
});
74+
}),
75+
);
76+
}
77+
78+
/**
79+
* Get namespace info for account with namespace name
80+
* @param addresses Array of addresses
81+
* @returns {Observable<NamespaceInfoWithName[]>}
82+
*/
83+
public accountNamespacesWithName(addresses: Address[]): Observable<NamespaceInfoWithName[]> {
84+
return this.namespaceRepository.getNamespacesFromAccounts(addresses).pipe(
85+
mergeMap((infos) => {
86+
const namespaceIds = infos.map((i) => i.id);
87+
return this.namespaceRepository.getNamespacesName(namespaceIds).pipe(
88+
map((resolved) => {
89+
return infos.map((info) => {
90+
const name = resolved.find((r) => r.namespaceId.equals(info.id));
91+
return DtoMapping.assign(info, { namespaceName: name?.name });
92+
});
93+
}),
94+
);
95+
}),
96+
);
97+
}
98+
99+
/**
100+
* Resolve mosaics provided namespace names
101+
* @param mosaics unresolved mosaics
102+
* @return {ResolvedMosaic[]}
103+
*/
104+
private resolveMosaics(mosaics: Mosaic[], names: NamespaceName[]): ResolvedMosaic[] {
105+
return mosaics.map((mosaic) => {
106+
if (mosaic.id instanceof MosaicId) {
107+
return mosaic as ResolvedMosaic;
108+
} else {
109+
const name = names.find((f) => f.namespaceId.equals(mosaic.id));
110+
if (name) {
111+
return DtoMapping.assign(mosaic, { namespaceName: name });
112+
} else {
113+
return mosaic as ResolvedMosaic;
114+
}
115+
}
116+
});
117+
}
118+
119+
/**
120+
* Get distinct list of namespaces ids from list of account infos
121+
* @param accountInfos List of account infos
122+
* @returns {NamespaceId[]}
123+
*/
124+
private getDistinctNamespaceIdFromAccountInfos(accountInfos: AccountInfo[]): NamespaceId[] {
125+
const namespaceIds: NamespaceId[] = [];
126+
accountInfos.forEach((info) => {
127+
info.mosaics.forEach((mosaic) => {
128+
if (mosaic.id instanceof NamespaceId) {
129+
if (!namespaceIds.find((n) => n.equals(mosaic.id))) {
130+
namespaceIds.push(mosaic.id);
131+
}
132+
}
133+
});
134+
});
135+
return namespaceIds;
136+
}
137+
}

src/service/BlockService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import { UInt64 } from '../model/UInt64';
2626
import { IBlockService } from './interfaces/IBlockService';
2727

2828
/**
29-
* Transaction Service
29+
* Block Service
3030
*/
3131
export class BlockService implements IBlockService {
3232
private readonly blockRepository: BlockRepository;
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright 2020 NEM
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { Observable } from 'rxjs';
18+
import { Address } from '../../model/account/Address';
19+
import { AccountInfoResolvedMosaic } from '../../model/account/AccountInfoResolvedMosaic';
20+
import { NamespaceInfoWithName } from '../../model/namespace/NamespaceInfoWithName';
21+
22+
/**
23+
* Block Service Interface
24+
*/
25+
export interface IAccountService {
26+
/**
27+
* Get account info with resolved mosaic
28+
* @param addresses Array of addresses
29+
*/
30+
accountInfoWithResolvedMosaic(addresses: Address[]): Observable<AccountInfoResolvedMosaic[]>;
31+
32+
/**
33+
* Get namespace info for account with namespace name
34+
* @param addresses Array of addresses
35+
* @returns {Observable<NamespaceInfoWithName[]>}
36+
*/
37+
accountNamespacesWithName(addresses: Address[]): Observable<NamespaceInfoWithName[]>;
38+
}

src/service/service.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@
1414
* limitations under the License.
1515
*/
1616

17+
export * from './AccountService';
1718
export * from './NamespaceService';
1819
export * from './MosaicService';
1920
export * from './AggregateTransactionService';
2021
export * from './MetadataTransactionService';
2122
export * from './MosaicRestrictionTransactionService';
2223
export * from './TransactionService';
2324
export * from './BlockService';
25+
export * from './interfaces/IAccountService';
2426
export * from './interfaces/IBlockService';
2527
export * from './interfaces/ITransactionService';

0 commit comments

Comments
 (0)