Skip to content

Commit 7f7528e

Browse files
authored
Merge pull request #109 from companieshouse/BI-6634-add-dissolved-search
Add dissolved search to node sdk
2 parents 8f4c1c3 + 832fa42 commit 7f7528e

File tree

7 files changed

+204
-4
lines changed

7 files changed

+204
-4
lines changed

src/client.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { PaymentService } from "./services/payment/";
88
import CompanyFilingHistoryService from "./services/company-filing-history/service";
99
import { RefreshTokenService } from "./services/refresh-token";
1010
import AlphabeticalSearchService from "./services/search/alphabetical-search/service";
11+
import DissolvedSearchService from "./services/search/dissolved-search/service";
1112

1213
/**
1314
* ApiClient is the class that all service objects hang off.
@@ -26,6 +27,7 @@ export default class ApiClient {
2627
public readonly mid : MidService;
2728
public readonly refreshToken: RefreshTokenService;
2829
public readonly alphabeticalSearch: AlphabeticalSearchService;
30+
public readonly dissolvedSearch: DissolvedSearchService;
2931

3032
constructor (readonly apiClient: IHttpClient, readonly accountClient: IHttpClient) {
3133
// services on the api domain using the apiClient
@@ -41,6 +43,7 @@ export default class ApiClient {
4143
this.order = new OrderService(apiClient);
4244
this.mid = new MidService(apiClient);
4345
this.alphabeticalSearch = new AlphabeticalSearchService(apiClient);
46+
this.dissolvedSearch = new DissolvedSearchService(apiClient);
4447
// service on the account/identity domain using the accountClient
4548
// e.g. user profile service can be added here when required
4649
this.refreshToken = new RefreshTokenService(accountClient);

src/mapping/mapping.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
import camelCaseKeys from "camelcase-keys";
22
import snakeCaseKeys from "snakecase-keys";
33

4+
type ObjArray = { [key: string]: any; }[]
5+
type Obj = { [key: string]: any; }
6+
type ObjOptions = Obj | ObjArray;
7+
48
export default class Mapping {
59
public static camelCaseKeys<T> (input: any): T {
610
return camelCaseKeys(input, { deep: true }) as T;
711
}
812

9-
public static snakeCaseKeys<T> (input: any): T {
10-
return snakeCaseKeys(input, { deep: true }) as T;
13+
public static snakeCaseKeys (input: ObjOptions) {
14+
return snakeCaseKeys(input, { deep: true });
1115
}
1216
}

src/services/payment/service.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ export default class PaymentService {
4141

4242
private async createPaymentHandler (createPaymentRequest: CreatePaymentRequest, path: string):
4343
Promise<ApiResult<ApiResponse<Payment>>> {
44-
const createPaymentRequestResource: CreatePaymentRequestResource =
45-
Mapping.snakeCaseKeys<CreatePaymentRequestResource>(createPaymentRequest);
44+
const createPaymentRequestResource =
45+
Mapping.snakeCaseKeys(createPaymentRequest);
4646

4747
const resp: HttpResponse = await this.client.httpPost(path, createPaymentRequestResource);
4848

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { default as DissolvedSearchService } from "./service";
2+
export * from "./types";
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { IHttpClient } from "../../../http";
2+
import { CompaniesResource } from "./types";
3+
import Resource from "../../resource";
4+
5+
export default class DissolvedSearchService {
6+
constructor (private readonly client: IHttpClient) { }
7+
public async getCompanies (companyName: string, requestId: string): Promise<Resource<CompaniesResource>> {
8+
const additionalHeaders = {
9+
"X-Request-ID": requestId,
10+
"Content-Type": "application/json"
11+
}
12+
const dissolvedSearchURL = "/dissolved-search/companies?q=" + companyName;
13+
14+
const resp = await this.client.httpGet(dissolvedSearchURL, additionalHeaders);
15+
16+
const resource: Resource<CompaniesResource> = {
17+
httpStatusCode: resp.status
18+
};
19+
20+
if (resp.error) {
21+
return resource;
22+
}
23+
24+
resource.resource = resp.body as CompaniesResource;
25+
26+
return resource;
27+
}
28+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
export interface CompaniesResource {
2+
etag: string;
3+
items: Items[];
4+
kind: string;
5+
top_hit: TopHit;
6+
}
7+
8+
export interface Items {
9+
address: Address;
10+
company_name: string;
11+
company_number: string;
12+
company_status: string;
13+
date_of_cessation: string;
14+
date_of_creation: string;
15+
kind: string;
16+
previous_company_names: PreviousCompanyNames[];
17+
}
18+
19+
export interface Address {
20+
locality: string;
21+
postal_code: string;
22+
}
23+
24+
export interface PreviousCompanyNames {
25+
ceased_on: string;
26+
effective_from: string;
27+
name: string;
28+
}
29+
30+
export interface TopHit {
31+
address: Address;
32+
company_name: string;
33+
company_number: string;
34+
company_status: string;
35+
date_of_cessation: string;
36+
date_of_creation: string;
37+
kind: string;
38+
previous_company_names: PreviousCompanyNames[];
39+
}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import chai from "chai";
2+
import sinon from "sinon";
3+
4+
import { DissolvedSearchService } from "../../../../src/services/search/dissolved-search";
5+
import { RequestClient } from "../../../../src/http";
6+
import { CompaniesResource } from "../../../../src/services/search/dissolved-search/types";
7+
import Resource from "../../../../src/services/resource";
8+
const expect = chai.expect;
9+
10+
const requestClient = new RequestClient({ baseUrl: "URL-NOT-USED", oauthToken: "TOKEN-NOT-USED" });
11+
12+
const mockResponseBody : CompaniesResource = ({
13+
etag: "etag",
14+
items: [
15+
{
16+
address: {
17+
locality: "cardiff",
18+
postal_code: "cf5 6rb"
19+
},
20+
company_name: "test company",
21+
company_number: "0000789",
22+
company_status: "active",
23+
date_of_cessation: "19910212",
24+
date_of_creation: "19910212",
25+
kind: "kind",
26+
previous_company_names: [
27+
{
28+
ceased_on: "19910212",
29+
effective_from: "19910212",
30+
name: "old name"
31+
}
32+
]
33+
}
34+
],
35+
kind: "kind",
36+
top_hit: {
37+
address: {
38+
locality: "cardiff",
39+
postal_code: "cf5 6rb"
40+
},
41+
company_name: "test company",
42+
company_number: "0000789",
43+
company_status: "active",
44+
date_of_cessation: "19910212",
45+
date_of_creation: "19910212",
46+
kind: "kind",
47+
previous_company_names: [
48+
{
49+
ceased_on: "19910212",
50+
effective_from: "19910212",
51+
name: "old name"
52+
}
53+
]
54+
}
55+
});
56+
57+
const mockRequestId = "fdskfhsdoifhsffsif";
58+
const testCompanyName = "TEST COMPANY NAME";
59+
60+
describe("create a dissolved search GET", () => {
61+
beforeEach(() => {
62+
sinon.reset();
63+
sinon.restore();
64+
});
65+
66+
afterEach(done => {
67+
sinon.reset();
68+
sinon.restore();
69+
done();
70+
});
71+
72+
it("returns an error response on failure", async () => {
73+
const mockGetRequest = {
74+
status: 401,
75+
error: "An error occurred"
76+
};
77+
78+
const mockRequest = sinon.stub(requestClient, "httpGet").resolves(mockGetRequest);
79+
const search: DissolvedSearchService = new DissolvedSearchService(requestClient);
80+
const data: Resource<CompaniesResource> = await search.getCompanies(testCompanyName, mockRequestId);
81+
82+
expect(data.httpStatusCode).to.equal(401);
83+
expect(data.resource).to.be.undefined;
84+
});
85+
86+
it("returns dissolved search results correctly", async () => {
87+
const mockGetRequest = {
88+
status: 200,
89+
body: mockResponseBody
90+
};
91+
92+
const mockRequest = sinon.stub(requestClient, "httpGet").resolves(mockGetRequest);
93+
const search: DissolvedSearchService = new DissolvedSearchService(requestClient);
94+
const data: Resource<CompaniesResource> = await search.getCompanies(testCompanyName, mockRequestId);
95+
const item = data.resource.items[0];
96+
const mockItem = mockResponseBody.items[0];
97+
98+
expect(data.httpStatusCode).to.equal(200);
99+
expect(data.resource.etag).to.equal(mockResponseBody.etag);
100+
expect(item.address.locality).to.equal(mockItem.address.locality);
101+
expect(item.address.postal_code).to.equal(mockItem.address.postal_code);
102+
expect(item.company_name).to.equal(mockItem.company_name);
103+
expect(item.company_number).to.equal(mockItem.company_number);
104+
expect(item.company_status).to.equal(mockItem.company_status);
105+
expect(item.date_of_cessation).to.equal(mockItem.date_of_cessation);
106+
expect(item.date_of_creation).to.equal(mockItem.date_of_creation);
107+
expect(item.kind).to.equal(mockItem.kind);
108+
expect(item.previous_company_names[0].ceased_on).to.equal(mockItem.previous_company_names[0].ceased_on);
109+
expect(item.previous_company_names[0].effective_from).to.equal(mockItem.previous_company_names[0].effective_from);
110+
expect(item.previous_company_names[0].name).to.equal(mockItem.previous_company_names[0].name);
111+
expect(data.resource.kind).to.equal(mockResponseBody.kind);
112+
expect(data.resource.top_hit.address.locality).to.equal(mockResponseBody.top_hit.address.locality);
113+
expect(data.resource.top_hit.address.postal_code).to.equal(mockResponseBody.top_hit.address.postal_code);
114+
expect(data.resource.top_hit.company_name).to.equal(mockResponseBody.top_hit.company_name);
115+
expect(data.resource.top_hit.company_number).to.equal(mockResponseBody.top_hit.company_number);
116+
expect(data.resource.top_hit.company_status).to.equal(mockResponseBody.top_hit.company_status);
117+
expect(data.resource.top_hit.date_of_cessation).to.equal(mockResponseBody.top_hit.date_of_cessation);
118+
expect(data.resource.top_hit.date_of_creation).to.equal(mockResponseBody.top_hit.date_of_creation);
119+
expect(data.resource.top_hit.kind).to.equal(mockResponseBody.top_hit.kind);
120+
expect(data.resource.top_hit.previous_company_names[0].ceased_on).to.equal(mockResponseBody.top_hit.previous_company_names[0].ceased_on);
121+
expect(data.resource.top_hit.previous_company_names[0].effective_from).to.equal(mockResponseBody.top_hit.previous_company_names[0].effective_from);
122+
expect(data.resource.top_hit.previous_company_names[0].name).to.equal(mockResponseBody.top_hit.previous_company_names[0].name);
123+
});
124+
});

0 commit comments

Comments
 (0)