Skip to content

Commit 7677492

Browse files
authored
feat(content): has many expand (#50)
* feat: add has many params to interfaces * feat: add single type view example with hasMany * feat: update tests * feat: add expand hasMany components logic * feat: cleanup * feat: update query for expand data * feat: get expand route properties * feat: replace entities helper * feat: add tests * feat: hasMany parse * feat(single-type-service): update tests * refactor: update types * refactor: update validation for requested expand data * feat(expand-route-input): add attributes and relations params * feat(expand-route-input): handle relations and attributes for entities * feat: update http request examples * feat: cleanup * feat(http-requests): update examples * feat: cleanup * feat(http-requests): update examples
1 parent 3feab21 commit 7677492

File tree

12 files changed

+579
-98
lines changed

12 files changed

+579
-98
lines changed

http-requests/content/requests.http

Lines changed: 243 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -209,8 +209,12 @@ Content-Type: application/json
209209
"contentDate": "2023-05-28T13:56:55.360Z",
210210
"contentDescription": "contentTitle",
211211
"contentCreators": [
212-
"b9b61ca6-761b-4051-84b2-647a2262b78b",
213-
"a5326de3-d04c-425c-8711-0f99fc031c67"
212+
{
213+
"id": "b9b61ca6-761b-4051-84b2-647a2262b78b"
214+
},
215+
{
216+
"id": "a5326de3-d04c-425c-8711-0f99fc031c67"
217+
}
214218
]
215219
}
216220
}
@@ -237,7 +241,110 @@ Content-Type: application/json
237241
}
238242
}
239243

240-
### View signle type
244+
### Create single type with the hasMany component for page
245+
POST http://127.0.0.1:8001/ms/content
246+
Accept: application/json
247+
Content-Type: application/json
248+
249+
{
250+
"id": "1",
251+
"method": "single-type.create",
252+
"params": {
253+
"fields": {
254+
"components": [
255+
{
256+
"id": "dff2719e-3c57-4248-9408-59af6287a568"
257+
}
258+
],
259+
"title": "Page single type",
260+
"alias": "pageSingleType",
261+
"value": {
262+
"blogPostPage": {
263+
"id": "dff2719e-3c57-4248-9408-59af6287a568",
264+
"data": {
265+
"header": {
266+
"id": "9a7aedb4-4b00-44b3-89a3-a535692d28d6",
267+
"data": {
268+
"pageHeader": {
269+
"id": "9a7aedb4-4b00-44b3-89a3-a535692d28d6",
270+
"data": {
271+
"headerTitle": "Cars",
272+
"postNumber": 1
273+
}
274+
}
275+
}
276+
},
277+
"content": {
278+
"id": "e6186469-a9a5-444c-812c-c801c95245b8",
279+
"data": {
280+
"pageContent": {
281+
"id": "e6186469-a9a5-444c-812c-c801c95245b8",
282+
"data": [
283+
{
284+
"contentTitle": "Green Lamborghini",
285+
"contentDate": "2023-05-28T13:56:55.360Z",
286+
"contentDescription": "contentTitle",
287+
"contentCreators": [
288+
{
289+
"id": "b9b61ca6-761b-4051-84b2-647a2262b78b"
290+
},
291+
{
292+
"id": "a5326de3-d04c-425c-8711-0f99fc031c67"
293+
}
294+
]
295+
},
296+
{
297+
"contentTitle": "White Lamborghini",
298+
"contentDate": "2023-05-28T13:56:55.360Z",
299+
"contentDescription": "contentTitle",
300+
"contentCreators": [
301+
{
302+
"id": "m9b61ca6-761b-4051-84b2-647a2262b78b"
303+
},
304+
{
305+
"id": "z5326de3-d04c-425c-8711-0f99fc031c67"
306+
}
307+
]
308+
},
309+
{
310+
"contentTitle": "Blue Lamborghini",
311+
"contentDate": "2023-05-28T13:56:55.360Z",
312+
"contentDescription": "contentTitle",
313+
"contentCreators": [
314+
{
315+
"id": "p9b61ca6-761b-4051-84b2-647a2262b78b"
316+
},
317+
{
318+
"id": "o5326de3-d04c-425c-8711-0f99fc031c67"
319+
}
320+
]
321+
}
322+
]
323+
}
324+
}
325+
},
326+
"footer": {
327+
"id": "78567003-f8cb-4d92-8aab-d7c9dc88bf2e",
328+
"data": {
329+
"id": "78567003-f8cb-4d92-8aab-d7c9dc88bf2e",
330+
"pageFooter": {
331+
"contactUsWithTheEmail": "[email protected]",
332+
"isThisPostRecommendedByUS": true
333+
}
334+
}
335+
},
336+
"options": {
337+
"timeZoneId": "America/Los_Angeles",
338+
"timeZoneName": "Pacific Daylight Time"
339+
}
340+
}
341+
}
342+
}
343+
}
344+
}
345+
}
346+
347+
### View signle type with users (profile) relations
241348
POST http://127.0.0.1:8001/ms/content
242349
Accept: application/json
243350
Content-Type: application/json
@@ -253,7 +360,36 @@ Content-Type: application/json
253360
},
254361
"payload": {
255362
"expand": [
256-
"blogPostPage.content.pageContent.contentCreators"
363+
{
364+
"route": "blogPostPage.content.pageContent.contentCreators",
365+
"relations": ["profile"]
366+
}
367+
]
368+
}
369+
}
370+
}
371+
372+
### View signle type with users atributes
373+
### NOTE: Provide always primary keys to attributes
374+
POST http://127.0.0.1:8001/ms/content
375+
Accept: application/json
376+
Content-Type: application/json
377+
378+
{
379+
"id": "1",
380+
"method": "single-type.view",
381+
"params": {
382+
"query": {
383+
"where": {
384+
"id": "3cff317c-8ece-45b0-b0bb-0021760f06c2"
385+
}
386+
},
387+
"payload": {
388+
"expand": [
389+
{
390+
"route": "blogPostPage.content.pageContent.contentCreators",
391+
"attributes": ["id", "firstName"]
392+
}
257393
]
258394
}
259395
}
@@ -541,3 +677,106 @@ Authorization: Bearer usertokenoooooooooooooooooooooon
541677
}
542678
}
543679
}
680+
681+
### Additional
682+
### Create single type for page with hasMany
683+
POST http://127.0.0.1:8001/ms/content
684+
Accept: application/json
685+
Content-Type: application/json
686+
687+
{
688+
"id": "1",
689+
"method": "single-type.create",
690+
"params": {
691+
"fields": {
692+
"components": [
693+
{
694+
"id": "e5d4c33f-cd63-437a-a76b-bd798121ce15"
695+
}
696+
],
697+
"title": "Page single type",
698+
"alias": "pageSingleTypeNew",
699+
"value": {
700+
"blogPostPage": {
701+
"id": "e5d4c33f-cd63-437a-a76b-bd798121ce15",
702+
"data": {
703+
"header": {
704+
"id": "43edbae4-ec2f-4a32-a477-b1cfc8bb3673",
705+
"data": {
706+
"pageHeader": {
707+
"id": "43edbae4-ec2f-4a32-a477-b1cfc8bb3673",
708+
"data": {
709+
"headerTitle": "Cars",
710+
"postNumber": 1
711+
}
712+
}
713+
}
714+
},
715+
"content": {
716+
"id": "cc896aa8-1734-4556-94c1-fcbf849d520c",
717+
"data": {
718+
"pageContent": {
719+
"id": "cc896aa8-1734-4556-94c1-fcbf849d520c",
720+
"data": [
721+
{
722+
"contentTitle": "Green Lamborghini",
723+
"contentDate": "2023-05-28T13:56:55.360Z",
724+
"contentDescription": "contentTitle1",
725+
"contentCreators": [
726+
"a5326de3-d04c-425c-8711-0f99fc031c67"
727+
]
728+
},
729+
{
730+
"contentTitle": "Blue Lamborghini",
731+
"contentDate": "2023-05-28T13:56:55.360Z",
732+
"contentDescription": "contentTitle2",
733+
"contentCreators": [
734+
"b9b61ca6-761b-4051-84b2-647a2262b78b"
735+
]
736+
}
737+
]
738+
}
739+
}
740+
},
741+
"footer": {
742+
"id": "1fddf950-159f-419c-b006-eb07a51f7857",
743+
"data": {
744+
"id": "1fddf950-159f-419c-b006-eb07a51f7857",
745+
"pageFooter": {
746+
"contactUsWithTheEmail": "[email protected]",
747+
"isThisPostRecommendedByUS": true
748+
}
749+
}
750+
},
751+
"options": {
752+
"timeZoneId": "America/Los_Angeles",
753+
"timeZoneName": "Pacific Daylight Time"
754+
}
755+
}
756+
}
757+
}
758+
}
759+
}
760+
}
761+
762+
### View signle type
763+
POST http://127.0.0.1:8001/ms/content
764+
Accept: application/json
765+
Content-Type: application/json
766+
767+
{
768+
"id": "1",
769+
"method": "single-type.view",
770+
"params": {
771+
"query": {
772+
"where": {
773+
"id": "8b4d7fa9-4f61-4f6f-9737-01546cd07b4e"
774+
}
775+
},
776+
"payload": {
777+
"expand": [
778+
"blogPostPage.content.pageContent.contentCreators"
779+
]
780+
}
781+
}
782+
}

microservices/content/__mocks__/single-type-view-process.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const adminsRelationMock = ['blog.admins'];
1+
const adminsRelationMock = [{ route: 'blog.admins' }];
22

33
const adminsSingleTypeMock = {
44
alias: 'blog',
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { expect } from 'chai';
2+
import sinon from 'sinon';
3+
import replaceEntities from '@helpers/replace-entities';
4+
5+
describe('helpers/replace-entities', () => {
6+
const originalEntities = [
7+
{ cardId: 1, userId: 2 },
8+
{ cardId: 2, userId: 3 },
9+
];
10+
11+
it('should update original data with matching values from updated data', () => {
12+
const updatedEntities = [
13+
{ cardId: 1, userId: 2, name: 'Alex' },
14+
{ cardId: 2, userId: 3, name: 'Oleg' },
15+
];
16+
17+
const result = replaceEntities(originalEntities, updatedEntities);
18+
19+
expect(result).to.deep.equal(updatedEntities);
20+
});
21+
22+
it('should return empty array if matches not found and should clear is true', () => {
23+
const updatedData = [
24+
{ cardId: 1, userId: 5, name: 'Alex' },
25+
{ cardId: 2, userId: 5, name: 'Oleg' },
26+
];
27+
28+
const result = replaceEntities(originalEntities, updatedData);
29+
30+
expect(result).to.deep.equal([]);
31+
});
32+
33+
it('should return empty original entities if matches not found and should clear is true', () => {
34+
const updatedData = [
35+
{ cardId: 1, userId: 5, name: 'Alex' },
36+
{ cardId: 2, userId: 5, name: 'Oleg' },
37+
];
38+
39+
const result = replaceEntities(originalEntities, updatedData, false);
40+
41+
expect(result).to.deep.equal(originalEntities);
42+
});
43+
44+
it('should update original data with matching values', () => {
45+
const spy = sinon.spy(Object, 'assign');
46+
const usersData = [{ id: 'id-1' }, { id: 'id-2' }];
47+
const usersResultData = [
48+
{ id: 'id-1', name: 'Alex' },
49+
{ id: 'id-2', name: 'Oleg' },
50+
];
51+
52+
const result = replaceEntities(usersData, usersResultData);
53+
54+
expect(result).to.deep.equal(usersData);
55+
expect(spy.callCount).to.equal(2);
56+
spy.restore();
57+
});
58+
});

microservices/content/__tests__/services/single-type-view-process-test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ describe('services/single-type-view-process', () => {
2828
});
2929

3030
it('should throw error: incorrect relation routes', async () => {
31-
const relations = ['relation/admins'];
31+
const relations = [{ route: 'relation/admins' }];
3232
const service = SingleTypeViewProcess.init({
3333
// @ts-ignore
3434
entity: {},
@@ -84,7 +84,7 @@ describe('services/single-type-view-process', () => {
8484

8585
expect(await waitResult(service.expand(adminsRelationMock))).to.throw(
8686
BaseException,
87-
'Failed to get one or more expanded routes according to the passed relationship routes',
87+
'Failed to get one or more expanded routes according to the provided relationship routes.',
8888
);
8989
});
9090

@@ -96,7 +96,7 @@ describe('services/single-type-view-process', () => {
9696
singleTypeRepository,
9797
});
9898

99-
const [route] = adminsRelationMock;
99+
const [{ route }] = adminsRelationMock;
100100

101101
const handleRelationsStub = sinon.stub(componentRepository, 'handleRelations');
102102

@@ -111,10 +111,10 @@ describe('services/single-type-view-process', () => {
111111
* that's the reason of usage ts-ignore
112112
*/
113113
// @ts-ignore
114-
const getExpandDataStub = sinon.stub(service, 'getExpandData');
114+
const handleExpandStub = sinon.stub(service, 'handleExpand');
115115

116116
// @ts-ignore
117-
getExpandDataStub.resolves({ data: adminsMock, routeRef: route } as IExpandData);
117+
handleExpandStub.resolves({ data: adminsMock, routeRef: route } as IExpandData);
118118

119119
const adminsSingleType = { ...adminsSingleTypeMock };
120120

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
interface IProperties {
2+
properties: string[];
3+
lastIndex: number;
4+
}
5+
6+
/**
7+
* Returns expand route properties and last index
8+
*/
9+
const getExpandRouteProperties = (route: string): IProperties => {
10+
const properties = route.split('.');
11+
12+
return { properties, lastIndex: properties.length - 1 };
13+
};
14+
15+
export default getExpandRouteProperties;

0 commit comments

Comments
 (0)