@node-c/core 1.0.0-alpha8 → 1.0.0-beta0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/coverage/src/app.ts.html +349 -0
- package/coverage/src/common/configProvider/configProvider.module.ts.html +160 -0
- package/coverage/src/common/configProvider/configProvider.service.ts.html +658 -0
- package/coverage/src/common/configProvider/index.html +146 -0
- package/coverage/src/common/configProvider/index.ts.html +94 -0
- package/coverage/src/common/definitions/common.constants.ts.html +160 -0
- package/coverage/src/common/definitions/common.errors.ts.html +124 -0
- package/coverage/src/common/definitions/index.html +146 -0
- package/coverage/src/common/definitions/index.ts.html +94 -0
- package/coverage/src/common/utils/index.html +131 -0
- package/coverage/src/common/utils/index.ts.html +88 -0
- package/coverage/src/common/utils/utils.loadDynamicModules.ts.html +265 -0
- package/coverage/src/domain/entityService/domain.entity.service.ts.html +784 -0
- package/coverage/src/domain/entityService/index.html +131 -0
- package/coverage/src/domain/entityService/index.ts.html +91 -0
- package/coverage/src/index.html +116 -0
- package/coverage/src/persistance/entityService/index.html +131 -0
- package/coverage/src/persistance/entityService/index.ts.html +91 -0
- package/coverage/src/persistance/entityService/persistance.entity.service.ts.html +268 -0
- package/dist/app.d.ts +2 -2
- package/dist/app.js +27 -15
- package/dist/app.js.map +1 -1
- package/dist/common/configProvider/configProvider.definitions.d.ts +156 -20
- package/dist/common/configProvider/configProvider.definitions.js +21 -7
- package/dist/common/configProvider/configProvider.definitions.js.map +1 -1
- package/dist/common/configProvider/configProvider.module.js +13 -2
- package/dist/common/configProvider/configProvider.module.js.map +1 -1
- package/dist/common/configProvider/configProvider.service.js +21 -18
- package/dist/common/configProvider/configProvider.service.js.map +1 -1
- package/dist/common/definitions/common.constants.d.ts +2 -1
- package/dist/common/definitions/common.constants.js +1 -0
- package/dist/common/definitions/common.constants.js.map +1 -1
- package/dist/common/utils/base64UrlEncode/base64UrlEncode.method.d.ts +1 -0
- package/dist/common/utils/base64UrlEncode/base64UrlEncode.method.js +9 -0
- package/dist/common/utils/base64UrlEncode/base64UrlEncode.method.js.map +1 -0
- package/dist/common/utils/base64UrlEncode/index.d.ts +1 -0
- package/dist/{persistance/common/entityService → common/utils/base64UrlEncode}/index.js +1 -2
- package/dist/common/utils/base64UrlEncode/index.js.map +1 -0
- package/dist/common/utils/getNested/getNested.definitions.d.ts +4 -0
- package/dist/common/utils/getNested/getNested.definitions.js +3 -0
- package/dist/common/utils/getNested/getNested.definitions.js.map +1 -0
- package/dist/common/utils/getNested/getNested.method.d.ts +6 -0
- package/dist/common/utils/getNested/getNested.method.js +88 -0
- package/dist/common/utils/getNested/getNested.method.js.map +1 -0
- package/dist/common/utils/getNested/index.d.ts +2 -0
- package/dist/common/utils/getNested/index.js +19 -0
- package/dist/common/utils/getNested/index.js.map +1 -0
- package/dist/common/utils/httpRequest/httpRequest.definitions.d.ts +19 -0
- package/dist/common/utils/httpRequest/httpRequest.definitions.js +3 -0
- package/dist/common/utils/httpRequest/httpRequest.definitions.js.map +1 -0
- package/dist/common/utils/httpRequest/httpRequest.method.d.ts +2 -0
- package/dist/common/utils/httpRequest/httpRequest.method.js +56 -0
- package/dist/common/utils/httpRequest/httpRequest.method.js.map +1 -0
- package/dist/common/utils/httpRequest/index.d.ts +2 -0
- package/dist/common/utils/httpRequest/index.js +19 -0
- package/dist/common/utils/httpRequest/index.js.map +1 -0
- package/dist/common/utils/index.d.ts +5 -1
- package/dist/common/utils/index.js +5 -1
- package/dist/common/utils/index.js.map +1 -1
- package/dist/common/utils/loadDynamicModules/index.d.ts +1 -0
- package/dist/common/utils/loadDynamicModules/index.js +18 -0
- package/dist/common/utils/loadDynamicModules/index.js.map +1 -0
- package/dist/common/utils/{utils.loadDynamicModules.d.ts → loadDynamicModules/utils.loadDynamicModules.d.ts} +1 -1
- package/dist/common/utils/loadDynamicModules/utils.loadDynamicModules.js.map +1 -0
- package/dist/common/utils/setNested/index.d.ts +2 -0
- package/dist/common/utils/setNested/index.js +19 -0
- package/dist/common/utils/setNested/index.js.map +1 -0
- package/dist/common/utils/setNested/setNested.definitions.d.ts +4 -0
- package/dist/common/utils/setNested/setNested.definitions.js +3 -0
- package/dist/common/utils/setNested/setNested.definitions.js.map +1 -0
- package/dist/common/utils/setNested/setNested.method.d.ts +2 -0
- package/dist/common/utils/setNested/setNested.method.js +70 -0
- package/dist/common/utils/setNested/setNested.method.js.map +1 -0
- package/dist/data/entityService/data.entity.service.d.ts +17 -0
- package/dist/data/entityService/data.entity.service.definitions.d.ts +117 -0
- package/dist/data/entityService/data.entity.service.definitions.js +28 -0
- package/dist/data/entityService/data.entity.service.definitions.js.map +1 -0
- package/dist/{persistance/common/entityService/persistance.entity.service.js → data/entityService/data.entity.service.js} +42 -10
- package/dist/data/entityService/data.entity.service.js.map +1 -0
- package/dist/data/entityService/index.d.ts +2 -0
- package/dist/data/entityService/index.js +19 -0
- package/dist/data/entityService/index.js.map +1 -0
- package/dist/domain/entityService/domain.entity.service.d.ts +28 -13
- package/dist/domain/entityService/domain.entity.service.definitions.d.ts +26 -17
- package/dist/domain/entityService/domain.entity.service.definitions.js +6 -6
- package/dist/domain/entityService/domain.entity.service.definitions.js.map +1 -1
- package/dist/domain/entityService/domain.entity.service.js +97 -56
- package/dist/domain/entityService/domain.entity.service.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +11 -10
- package/src/app.spec.ts +138 -0
- package/src/app.ts +115 -0
- package/src/common/configProvider/configProvider.definitions.ts +445 -0
- package/src/common/configProvider/configProvider.module.spec.ts +90 -0
- package/src/common/configProvider/configProvider.module.ts +25 -0
- package/src/common/configProvider/configProvider.service.spec.ts +206 -0
- package/src/common/configProvider/configProvider.service.ts +204 -0
- package/src/common/configProvider/index.ts +3 -0
- package/src/common/definitions/common.constants.ts +27 -0
- package/src/common/definitions/common.definitions.ts +13 -0
- package/src/common/definitions/common.errors.ts +13 -0
- package/src/common/definitions/index.ts +3 -0
- package/src/common/utils/base64UrlEncode/base64UrlEncode.method.ts +4 -0
- package/src/common/utils/base64UrlEncode/index.ts +1 -0
- package/src/common/utils/getNested/getNested.definitions.ts +4 -0
- package/src/common/utils/getNested/getNested.method.ts +108 -0
- package/src/common/utils/getNested/getNested.spec.ts +151 -0
- package/src/common/utils/getNested/index.ts +2 -0
- package/src/common/utils/httpRequest/httpRequest.definitions.ts +22 -0
- package/src/common/utils/httpRequest/httpRequest.method.ts +46 -0
- package/src/common/utils/httpRequest/index.ts +2 -0
- package/src/common/utils/index.ts +5 -0
- package/src/common/utils/loadDynamicModules/index.ts +1 -0
- package/src/common/utils/loadDynamicModules/utils.loadDynamicModules.spec.ts +111 -0
- package/src/common/utils/loadDynamicModules/utils.loadDynamicModules.ts +69 -0
- package/src/common/utils/setNested/index.ts +2 -0
- package/src/common/utils/setNested/setNested.definitions.ts +4 -0
- package/src/common/utils/setNested/setNested.method.ts +83 -0
- package/src/common/utils/setNested/setNested.spec.ts +184 -0
- package/src/data/entityService/data.entity.service.definitions.ts +154 -0
- package/src/data/entityService/data.entity.service.spec.ts +112 -0
- package/src/data/entityService/data.entity.service.ts +144 -0
- package/src/data/entityService/index.ts +2 -0
- package/src/domain/entityService/domain.entity.service.definitions.ts +142 -0
- package/src/domain/entityService/domain.entity.service.spec.ts +126 -0
- package/src/domain/entityService/domain.entity.service.ts +421 -0
- package/src/domain/entityService/index.ts +2 -0
- package/src/index.ts +6 -0
- package/src/vitest.config.ts +9 -0
- package/dist/common/utils/utils.loadDynamicModules.js.map +0 -1
- package/dist/persistance/common/entityService/index.d.ts +0 -2
- package/dist/persistance/common/entityService/index.js.map +0 -1
- package/dist/persistance/common/entityService/persistance.entity.service.d.ts +0 -11
- package/dist/persistance/common/entityService/persistance.entity.service.definitions.d.ts +0 -70
- package/dist/persistance/common/entityService/persistance.entity.service.definitions.js +0 -23
- package/dist/persistance/common/entityService/persistance.entity.service.definitions.js.map +0 -1
- package/dist/persistance/common/entityService/persistance.entity.service.js.map +0 -1
- /package/dist/common/utils/{utils.loadDynamicModules.js → loadDynamicModules/utils.loadDynamicModules.js} +0 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { GenericObject } from '../../common/definitions';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
DataBulkCreatePrivateOptions,
|
|
5
|
+
DataCreatePrivateOptions,
|
|
6
|
+
DataDeleteOptions,
|
|
7
|
+
DataDeletePrivateOptions,
|
|
8
|
+
DataDeleteResult,
|
|
9
|
+
DataFindOneOptions,
|
|
10
|
+
DataFindOnePrivateOptions,
|
|
11
|
+
DataFindOptions,
|
|
12
|
+
DataFindPrivateOptions,
|
|
13
|
+
DataFindResults,
|
|
14
|
+
DataUpdateOptions,
|
|
15
|
+
DataUpdatePrivateOptions,
|
|
16
|
+
DataUpdateResult
|
|
17
|
+
} from '../../data/entityService';
|
|
18
|
+
|
|
19
|
+
export interface DomainBaseAdditionalServiceOptionsOverrides {
|
|
20
|
+
filterByFirstServiceResultFields?: GenericObject<string>;
|
|
21
|
+
returnData?: boolean;
|
|
22
|
+
runOnNoFirstServiceResultOnly?: boolean | string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type DomainBaseOptions<Options> = Options & DomainBaseOptionsForAdditionalServices<Options>;
|
|
26
|
+
|
|
27
|
+
export interface DomainBaseOptionsForAdditionalServices<Options> {
|
|
28
|
+
optionsOverridesByService?: GenericObject<Partial<Options> & DomainBaseAdditionalServiceOptionsOverrides>;
|
|
29
|
+
dataServices?: DomainDataServicesKey[];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type DomainBaseOptionsForAdditionalServicesFull<
|
|
33
|
+
Options extends object | undefined = undefined,
|
|
34
|
+
SaveAdditionalResultsOptions extends object | undefined = undefined
|
|
35
|
+
> = DomainBaseOptionsForAdditionalServices<Options> & DomainBaseOptionsWithSearchData<SaveAdditionalResultsOptions>;
|
|
36
|
+
|
|
37
|
+
export interface DomainBaseOptionsWithSearchData<SaveAdditionalResultsOptions extends object | undefined = undefined> {
|
|
38
|
+
saveAdditionalResultsInFirstService?: {
|
|
39
|
+
saveOptions?: SaveAdditionalResultsOptions;
|
|
40
|
+
serviceName: string;
|
|
41
|
+
useResultsForFirstService?: boolean;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface DomainBaseResult<Result> {
|
|
46
|
+
result: Result;
|
|
47
|
+
resultsByService?: GenericObject<Result>;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type DomainBulkCreatePrivateOptions = DataBulkCreatePrivateOptions;
|
|
51
|
+
|
|
52
|
+
export type DomainBulkCreateData<Entity> = Partial<Entity>[];
|
|
53
|
+
|
|
54
|
+
export type DomainBulkCreateOptions<Options = object> = DomainBaseOptions<Options>;
|
|
55
|
+
|
|
56
|
+
export type DomainBulkCreateResult<Entity> = DomainBaseResult<Entity[]>;
|
|
57
|
+
|
|
58
|
+
export type DomainCreateData<Entity> = Partial<Entity>;
|
|
59
|
+
|
|
60
|
+
export type DomainCreateOptions<Options = object> = DomainBaseOptions<Options>;
|
|
61
|
+
|
|
62
|
+
export type DomainCreatePrivateOptions = DataCreatePrivateOptions;
|
|
63
|
+
|
|
64
|
+
export type DomainCreateResult<Entity> = DomainBaseResult<Entity>;
|
|
65
|
+
|
|
66
|
+
export type DomainDeleteOptions<Options = object> = Options & DomainBaseOptions<DataDeleteOptions>;
|
|
67
|
+
|
|
68
|
+
export type DomainDeletePrivateOptions = DataDeletePrivateOptions;
|
|
69
|
+
|
|
70
|
+
export type DomainDeleteResult<Entity> = DomainBaseResult<DataDeleteResult<Entity>>;
|
|
71
|
+
|
|
72
|
+
export interface DomainEntityServiceDefaultData<Entity> {
|
|
73
|
+
BulkCreate: DomainBulkCreateData<Entity>;
|
|
74
|
+
Create: DomainCreateData<Entity>;
|
|
75
|
+
Update: DomainUpdateData<Entity>;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export type DomainFindOneOptions<Options = object> = Options &
|
|
79
|
+
DomainBaseOptions<DataFindOneOptions> &
|
|
80
|
+
DomainBaseOptionsWithSearchData<DomainCreateOptions>;
|
|
81
|
+
|
|
82
|
+
export type DomainFindOnePrivateOptions = DataFindOnePrivateOptions;
|
|
83
|
+
|
|
84
|
+
export type DomainFindOneResult<Entity> = DomainBaseResult<Entity | null>;
|
|
85
|
+
|
|
86
|
+
export type DomainFindOptions<Options = object> = Options &
|
|
87
|
+
DomainBaseOptions<DataFindOptions> &
|
|
88
|
+
DomainBaseOptionsWithSearchData<DomainBulkCreateOptions>;
|
|
89
|
+
|
|
90
|
+
export type DomainFindPrivateOptions = DataFindPrivateOptions;
|
|
91
|
+
|
|
92
|
+
export type DomainFindResult<Entity> = DomainBaseResult<DataFindResults<Entity>>;
|
|
93
|
+
|
|
94
|
+
export enum DomainMethod {
|
|
95
|
+
// eslint-disable-next-line no-unused-vars
|
|
96
|
+
BulkCreate = 'bulkCreate',
|
|
97
|
+
// eslint-disable-next-line no-unused-vars
|
|
98
|
+
Create = 'create',
|
|
99
|
+
// eslint-disable-next-line no-unused-vars
|
|
100
|
+
Delete = 'delete',
|
|
101
|
+
// eslint-disable-next-line no-unused-vars
|
|
102
|
+
Find = 'find',
|
|
103
|
+
// eslint-disable-next-line no-unused-vars
|
|
104
|
+
FindOne = 'findOne',
|
|
105
|
+
// eslint-disable-next-line no-unused-vars
|
|
106
|
+
Update = 'update'
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export const DOMAIN_ENTITY_SERVICE_DEFAULT_METHODS = [
|
|
110
|
+
DomainMethod.BulkCreate,
|
|
111
|
+
DomainMethod.Create,
|
|
112
|
+
DomainMethod.Delete,
|
|
113
|
+
DomainMethod.Find,
|
|
114
|
+
DomainMethod.FindOne,
|
|
115
|
+
DomainMethod.Update
|
|
116
|
+
];
|
|
117
|
+
|
|
118
|
+
export enum DomainDataEntityServiceType {
|
|
119
|
+
// eslint-disable-next-line no-unused-vars
|
|
120
|
+
All = 'all',
|
|
121
|
+
// eslint-disable-next-line no-unused-vars
|
|
122
|
+
Main = 'main'
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export type DomainDataServicesKey = DomainDataEntityServiceType | string;
|
|
126
|
+
|
|
127
|
+
export type DomainRunMethodInAdditionalServicesOptions<Options> = {
|
|
128
|
+
firstServiceResult?: unknown;
|
|
129
|
+
hasFirstServiceResult: boolean;
|
|
130
|
+
methodArgs?: unknown[];
|
|
131
|
+
methodName: string;
|
|
132
|
+
optionsArgIndex?: number;
|
|
133
|
+
optionsOverridesByService?: GenericObject<Partial<Options> & DomainBaseAdditionalServiceOptionsOverrides>;
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
export type DomainUpdateData<Entity> = Partial<Entity>;
|
|
137
|
+
|
|
138
|
+
export type DomainUpdateOptions<Options = object> = Options & DomainBaseOptions<DataUpdateOptions>;
|
|
139
|
+
|
|
140
|
+
export type DomainUpdatePrivateOptions = DataUpdatePrivateOptions;
|
|
141
|
+
|
|
142
|
+
export type DomainUpdateResult<Entity> = DomainBaseResult<DataUpdateResult<Entity>>;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { DomainEntityService } from './domain.entity.service';
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
DataDeleteOptions,
|
|
7
|
+
DataDeleteResult,
|
|
8
|
+
DataEntityService,
|
|
9
|
+
DataFindOneOptions,
|
|
10
|
+
DataFindOptions,
|
|
11
|
+
DataFindResults,
|
|
12
|
+
DataUpdateOptions,
|
|
13
|
+
DataUpdateResult
|
|
14
|
+
} from '../../data/entityService';
|
|
15
|
+
|
|
16
|
+
interface TestEntity {
|
|
17
|
+
id: number;
|
|
18
|
+
name: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
describe('DomainEntityService', () => {
|
|
22
|
+
let mockDataService: DataEntityService<TestEntity>;
|
|
23
|
+
let domainService: DomainEntityService<TestEntity, DataEntityService<TestEntity>>;
|
|
24
|
+
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
// Create a fully typed mock for the underlying persistence service.
|
|
27
|
+
mockDataService = {
|
|
28
|
+
bulkCreate: vi.fn().mockResolvedValue([{ id: 1, name: 'Test1' }]),
|
|
29
|
+
create: vi.fn().mockResolvedValue({ id: 2, name: 'Test2' }),
|
|
30
|
+
count: vi.fn().mockResolvedValue({ count: 0 }),
|
|
31
|
+
delete: vi.fn().mockResolvedValue({ affected: 1 } as DataDeleteResult),
|
|
32
|
+
find: vi.fn().mockResolvedValue({ items: [{ id: 3, name: 'Test3' }] } as DataFindResults<TestEntity>),
|
|
33
|
+
findOne: vi.fn().mockResolvedValue({ id: 4, name: 'Test4' }),
|
|
34
|
+
getEntityName: vi.fn().mockResolvedValue('mockEntity'),
|
|
35
|
+
update: vi.fn().mockResolvedValue({ updated: { id: 5, name: 'Test5' } } as DataUpdateResult<TestEntity>)
|
|
36
|
+
};
|
|
37
|
+
domainService = new DomainEntityService<TestEntity, DataEntityService<TestEntity>>(mockDataService);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
describe('bulkCreate', () => {
|
|
41
|
+
it('should call dataEntityService.bulkCreate with the provided data and return its result', async () => {
|
|
42
|
+
const data: TestEntity[] = [{ id: 10, name: 'BulkTest' }];
|
|
43
|
+
const result = await domainService.bulkCreate(data);
|
|
44
|
+
expect(mockDataService.bulkCreate).toHaveBeenCalledWith(data);
|
|
45
|
+
expect(result).toEqual({ result: [{ id: 1, name: 'Test1' }] });
|
|
46
|
+
});
|
|
47
|
+
it('should propagate errors from bulkCreate', async () => {
|
|
48
|
+
const error = new Error('bulk error');
|
|
49
|
+
(mockDataService.bulkCreate as ReturnType<typeof vi.fn>).mockRejectedValueOnce(error);
|
|
50
|
+
await expect(domainService.bulkCreate([{ id: 0, name: 'Error' }])).rejects.toThrow('bulk error');
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe('create', () => {
|
|
55
|
+
it('should call dataEntityService.create with the provided data and return its result', async () => {
|
|
56
|
+
const data: TestEntity = { id: 20, name: 'CreateTest' };
|
|
57
|
+
const result = await domainService.create(data);
|
|
58
|
+
expect(mockDataService.create).toHaveBeenCalledWith(data);
|
|
59
|
+
expect(result).toEqual({ result: { id: 2, name: 'Test2' } });
|
|
60
|
+
});
|
|
61
|
+
it('should propagate errors from create', async () => {
|
|
62
|
+
const error = new Error('create error');
|
|
63
|
+
(mockDataService.create as ReturnType<typeof vi.fn>).mockRejectedValueOnce(error);
|
|
64
|
+
await expect(domainService.create({ id: 0, name: 'Error' })).rejects.toThrow('create error');
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe('delete', () => {
|
|
69
|
+
it('should call dataEntityService.delete with correct options and return its result', async () => {
|
|
70
|
+
const options: DataDeleteOptions = { filters: { id: 1 } };
|
|
71
|
+
const result = await domainService.delete(options);
|
|
72
|
+
expect(mockDataService.delete).toHaveBeenCalledWith(options);
|
|
73
|
+
expect(result).toEqual({ result: { affected: 1 } });
|
|
74
|
+
});
|
|
75
|
+
it('should propagate errors from delete', async () => {
|
|
76
|
+
const error = new Error('delete error');
|
|
77
|
+
(mockDataService.delete as ReturnType<typeof vi.fn>).mockRejectedValueOnce(error);
|
|
78
|
+
await expect(domainService.delete({ filters: { id: 999 } })).rejects.toThrow('delete error');
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe('find', () => {
|
|
83
|
+
it('should call dataEntityService.find with correct options and return its result', async () => {
|
|
84
|
+
const options: DataFindOptions = { filters: { name: 'Test' } };
|
|
85
|
+
const result = await domainService.find(options);
|
|
86
|
+
expect(mockDataService.find).toHaveBeenCalledWith(options);
|
|
87
|
+
expect(result).toEqual({ result: { items: [{ id: 3, name: 'Test3' }] } });
|
|
88
|
+
});
|
|
89
|
+
it('should propagate errors from find', async () => {
|
|
90
|
+
const error = new Error('find error');
|
|
91
|
+
(mockDataService.find as ReturnType<typeof vi.fn>).mockRejectedValueOnce(error);
|
|
92
|
+
await expect(domainService.find({ filters: { name: 'Error' } })).rejects.toThrow('find error');
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe('findOne', () => {
|
|
97
|
+
it('should call dataEntityService.findOne with correct options and return its result', async () => {
|
|
98
|
+
const options: DataFindOneOptions = { filters: { id: 4 } };
|
|
99
|
+
const result = await domainService.findOne(options);
|
|
100
|
+
expect(mockDataService.findOne).toHaveBeenCalledWith(options);
|
|
101
|
+
expect(result).toEqual({ result: { id: 4, name: 'Test4' } });
|
|
102
|
+
});
|
|
103
|
+
it('should propagate errors from findOne', async () => {
|
|
104
|
+
const error = new Error('findOne error');
|
|
105
|
+
(mockDataService.findOne as ReturnType<typeof vi.fn>).mockRejectedValueOnce(error);
|
|
106
|
+
await expect(domainService.findOne({ filters: { id: 999 } })).rejects.toThrow('findOne error');
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
describe('update', () => {
|
|
111
|
+
it('should call dataEntityService.update with correct data and options and return its result', async () => {
|
|
112
|
+
const data: TestEntity = { id: 30, name: 'UpdateTest' };
|
|
113
|
+
const options: DataUpdateOptions = { filters: { id: 30 } };
|
|
114
|
+
const result = await domainService.update(data, options);
|
|
115
|
+
expect(mockDataService.update).toHaveBeenCalledWith(data, options);
|
|
116
|
+
expect(result).toEqual({ result: { updated: { id: 5, name: 'Test5' } } });
|
|
117
|
+
});
|
|
118
|
+
it('should propagate errors from update', async () => {
|
|
119
|
+
const error = new Error('update error');
|
|
120
|
+
(mockDataService.update as ReturnType<typeof vi.fn>).mockRejectedValueOnce(error);
|
|
121
|
+
await expect(domainService.update({ id: 0, name: 'Error' }, { filters: { id: 0 } })).rejects.toThrow(
|
|
122
|
+
'update error'
|
|
123
|
+
);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
});
|
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
import ld from 'lodash';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
DOMAIN_ENTITY_SERVICE_DEFAULT_METHODS,
|
|
5
|
+
DomainBaseAdditionalServiceOptionsOverrides,
|
|
6
|
+
DomainBulkCreateOptions,
|
|
7
|
+
DomainBulkCreatePrivateOptions,
|
|
8
|
+
DomainBulkCreateResult,
|
|
9
|
+
DomainCreateOptions,
|
|
10
|
+
DomainCreatePrivateOptions,
|
|
11
|
+
DomainCreateResult,
|
|
12
|
+
DomainDataEntityServiceType,
|
|
13
|
+
DomainDeleteOptions,
|
|
14
|
+
DomainDeletePrivateOptions,
|
|
15
|
+
DomainDeleteResult,
|
|
16
|
+
DomainEntityServiceDefaultData,
|
|
17
|
+
DomainFindOneOptions,
|
|
18
|
+
DomainFindOnePrivateOptions,
|
|
19
|
+
DomainFindOneResult,
|
|
20
|
+
DomainFindOptions,
|
|
21
|
+
DomainFindPrivateOptions,
|
|
22
|
+
DomainFindResult,
|
|
23
|
+
DomainMethod,
|
|
24
|
+
DomainRunMethodInAdditionalServicesOptions,
|
|
25
|
+
DomainUpdateOptions,
|
|
26
|
+
DomainUpdatePrivateOptions,
|
|
27
|
+
DomainUpdateResult
|
|
28
|
+
} from './domain.entity.service.definitions';
|
|
29
|
+
|
|
30
|
+
import { ApplicationError, GenericObject } from '../../common/definitions';
|
|
31
|
+
|
|
32
|
+
import { DataDefaultData, DataEntityService, DataFindResults } from '../../data/entityService';
|
|
33
|
+
|
|
34
|
+
// TODO: privateOptionsOverrides by service
|
|
35
|
+
export class DomainEntityService<
|
|
36
|
+
Entity,
|
|
37
|
+
EntityService extends DataEntityService<Entity, DataEntityServiceData>,
|
|
38
|
+
Data extends DomainEntityServiceDefaultData<Entity> = DomainEntityServiceDefaultData<Entity>,
|
|
39
|
+
AdditionalEntityServices extends
|
|
40
|
+
| Record<string, DataEntityService<Partial<Entity>, DataDefaultData<object>>>
|
|
41
|
+
| undefined = undefined,
|
|
42
|
+
DataEntityServiceData extends DataDefaultData<Entity> = DataDefaultData<Entity>
|
|
43
|
+
> {
|
|
44
|
+
constructor(
|
|
45
|
+
// eslint-disable-next-line no-unused-vars
|
|
46
|
+
protected dataEntityService: EntityService,
|
|
47
|
+
// eslint-disable-next-line no-unused-vars
|
|
48
|
+
protected defaultMethods: string[] = DOMAIN_ENTITY_SERVICE_DEFAULT_METHODS,
|
|
49
|
+
// eslint-disable-next-line no-unused-vars
|
|
50
|
+
protected additionalDataEntityServices?: AdditionalEntityServices,
|
|
51
|
+
// eslint-disable-next-line no-unused-vars
|
|
52
|
+
protected defaultAdditionalDataEntityServicesOptions?: {
|
|
53
|
+
[methodName: string]: {
|
|
54
|
+
[serviceName: string]: {
|
|
55
|
+
allowIncoming?: boolean;
|
|
56
|
+
serviceOptions?: DomainBaseAdditionalServiceOptionsOverrides & GenericObject<unknown>;
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
) {}
|
|
61
|
+
|
|
62
|
+
public bulkCreate(
|
|
63
|
+
// eslint-disable-next-line no-unused-vars
|
|
64
|
+
data: Data['BulkCreate'],
|
|
65
|
+
// eslint-disable-next-line no-unused-vars
|
|
66
|
+
options?: DomainBulkCreateOptions,
|
|
67
|
+
// eslint-disable-next-line no-unused-vars
|
|
68
|
+
privateOptions?: DomainBulkCreatePrivateOptions
|
|
69
|
+
): Promise<DomainBulkCreateResult<Entity>>;
|
|
70
|
+
async bulkCreate(
|
|
71
|
+
data: Data['BulkCreate'],
|
|
72
|
+
options?: DomainBulkCreateOptions,
|
|
73
|
+
privateOptions?: DomainBulkCreatePrivateOptions
|
|
74
|
+
): Promise<DomainBulkCreateResult<Entity>> {
|
|
75
|
+
if (!this.defaultMethods?.includes(DomainMethod.BulkCreate)) {
|
|
76
|
+
throw new ApplicationError(`Method bulkCreate not implemented for class ${typeof this}.`);
|
|
77
|
+
}
|
|
78
|
+
// const defaultAdditionalDataEntityServicesOptions =
|
|
79
|
+
// this.defaultAdditionalDataEntityServicesOptions?.bulkCreate;
|
|
80
|
+
const { optionsOverridesByService, dataServices = [DomainDataEntityServiceType.Main] } = options || {};
|
|
81
|
+
const [firstServiceName, ...otherServiceNames] = dataServices;
|
|
82
|
+
const result = await this.getDataService(firstServiceName).bulkCreate(data, privateOptions);
|
|
83
|
+
let actualOtherServiceNames: string[] = [];
|
|
84
|
+
let actualOptionsOverridesByService: typeof optionsOverridesByService = {};
|
|
85
|
+
// if (defaultAdditionalDataEntityServicesOptions) {
|
|
86
|
+
// for (const serviceName in defaultAdditionalDataEntityServicesOptions) {
|
|
87
|
+
// const { allowIncoming = true, serviceOptions } = defaultAdditionalDataEntityServicesOptions[serviceName];
|
|
88
|
+
// }
|
|
89
|
+
// } else {
|
|
90
|
+
actualOtherServiceNames = otherServiceNames || [];
|
|
91
|
+
actualOptionsOverridesByService = optionsOverridesByService;
|
|
92
|
+
// }
|
|
93
|
+
return {
|
|
94
|
+
result,
|
|
95
|
+
resultsByService: await this.runMethodInAdditionalServices(actualOtherServiceNames, {
|
|
96
|
+
firstServiceResult: result,
|
|
97
|
+
hasFirstServiceResult: result.length > 0,
|
|
98
|
+
methodArgs: [result, privateOptions],
|
|
99
|
+
methodName: 'bulkCreate',
|
|
100
|
+
optionsArgIndex: 1,
|
|
101
|
+
optionsOverridesByService: actualOptionsOverridesByService
|
|
102
|
+
})
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
public create(
|
|
107
|
+
// eslint-disable-next-line no-unused-vars
|
|
108
|
+
data: Data['Create'],
|
|
109
|
+
// eslint-disable-next-line no-unused-vars
|
|
110
|
+
options?: DomainCreateOptions,
|
|
111
|
+
// eslint-disable-next-line no-unused-vars
|
|
112
|
+
privateOptions?: DomainCreatePrivateOptions
|
|
113
|
+
): Promise<DomainCreateResult<Entity>>;
|
|
114
|
+
async create<Options extends object | undefined = undefined>(
|
|
115
|
+
data: Data['Create'],
|
|
116
|
+
options?: DomainCreateOptions<Options>,
|
|
117
|
+
privateOptions?: DomainCreatePrivateOptions
|
|
118
|
+
): Promise<DomainCreateResult<Entity>> {
|
|
119
|
+
if (!this.defaultMethods?.includes(DomainMethod.Create)) {
|
|
120
|
+
throw new ApplicationError(`Method create not implemented for class ${typeof this}.`);
|
|
121
|
+
}
|
|
122
|
+
const { optionsOverridesByService, dataServices = [DomainDataEntityServiceType.Main] } = options || {};
|
|
123
|
+
const [firstServiceName, ...otherServiceNames] = dataServices;
|
|
124
|
+
const result = await this.getDataService(firstServiceName).create(data, privateOptions);
|
|
125
|
+
return {
|
|
126
|
+
result,
|
|
127
|
+
resultsByService: await this.runMethodInAdditionalServices(otherServiceNames || [], {
|
|
128
|
+
firstServiceResult: result,
|
|
129
|
+
hasFirstServiceResult: typeof result !== 'undefined' && result !== null,
|
|
130
|
+
methodArgs: [result, privateOptions],
|
|
131
|
+
methodName: 'create',
|
|
132
|
+
optionsArgIndex: 1,
|
|
133
|
+
optionsOverridesByService
|
|
134
|
+
})
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
public delete(
|
|
139
|
+
// eslint-disable-next-line no-unused-vars
|
|
140
|
+
options: DomainDeleteOptions,
|
|
141
|
+
// eslint-disable-next-line no-unused-vars
|
|
142
|
+
privateOptions?: DomainDeletePrivateOptions
|
|
143
|
+
): Promise<DomainDeleteResult<Entity>>;
|
|
144
|
+
async delete(
|
|
145
|
+
options: DomainDeleteOptions,
|
|
146
|
+
privateOptions?: DomainDeletePrivateOptions
|
|
147
|
+
): Promise<DomainDeleteResult<Entity>> {
|
|
148
|
+
if (!this.defaultMethods?.includes(DomainMethod.Delete)) {
|
|
149
|
+
throw new ApplicationError(`Method delete not implemented for class ${typeof this}.`);
|
|
150
|
+
}
|
|
151
|
+
const {
|
|
152
|
+
optionsOverridesByService,
|
|
153
|
+
dataServices = [DomainDataEntityServiceType.Main],
|
|
154
|
+
...otherOptions
|
|
155
|
+
} = options || {};
|
|
156
|
+
const [firstServiceName, ...otherServiceNames] = dataServices;
|
|
157
|
+
const result = await this.getDataService(firstServiceName).delete(otherOptions, privateOptions);
|
|
158
|
+
return {
|
|
159
|
+
result,
|
|
160
|
+
resultsByService: await this.runMethodInAdditionalServices(otherServiceNames || [], {
|
|
161
|
+
firstServiceResult: { ...result, items: result.originalItems || [] },
|
|
162
|
+
hasFirstServiceResult: !!result.count,
|
|
163
|
+
methodArgs: [otherOptions, privateOptions],
|
|
164
|
+
methodName: 'delete',
|
|
165
|
+
optionsArgIndex: 0,
|
|
166
|
+
optionsOverridesByService
|
|
167
|
+
})
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
public find(
|
|
172
|
+
// eslint-disable-next-line no-unused-vars
|
|
173
|
+
options: DomainFindOptions,
|
|
174
|
+
// eslint-disable-next-line no-unused-vars
|
|
175
|
+
privateOptions?: DomainFindOnePrivateOptions
|
|
176
|
+
): Promise<DomainFindResult<Entity>>;
|
|
177
|
+
async find(
|
|
178
|
+
options: DomainFindOptions,
|
|
179
|
+
privateOptions?: DomainFindOnePrivateOptions
|
|
180
|
+
): Promise<DomainFindResult<Entity>> {
|
|
181
|
+
if (!this.defaultMethods?.includes(DomainMethod.Find)) {
|
|
182
|
+
throw new ApplicationError(`Method find not implemented for class ${typeof this}.`);
|
|
183
|
+
}
|
|
184
|
+
const {
|
|
185
|
+
optionsOverridesByService,
|
|
186
|
+
dataServices = [DomainDataEntityServiceType.Main],
|
|
187
|
+
saveAdditionalResultsInFirstService,
|
|
188
|
+
...otherOptions
|
|
189
|
+
} = options || {};
|
|
190
|
+
const [firstServiceName, ...otherServiceNames] = dataServices;
|
|
191
|
+
let result = await this.getDataService(firstServiceName).find(otherOptions, privateOptions);
|
|
192
|
+
const hasFirstServiceResult = result.items.length > 0;
|
|
193
|
+
const resultsByService = await this.runMethodInAdditionalServices<DataFindResults<Entity>>(
|
|
194
|
+
otherServiceNames || [],
|
|
195
|
+
{
|
|
196
|
+
firstServiceResult: result,
|
|
197
|
+
hasFirstServiceResult,
|
|
198
|
+
methodArgs: [otherOptions, privateOptions],
|
|
199
|
+
methodName: 'find',
|
|
200
|
+
optionsArgIndex: 0,
|
|
201
|
+
optionsOverridesByService
|
|
202
|
+
}
|
|
203
|
+
);
|
|
204
|
+
if (saveAdditionalResultsInFirstService && resultsByService) {
|
|
205
|
+
const { saveOptions, serviceName, useResultsForFirstService } = saveAdditionalResultsInFirstService;
|
|
206
|
+
const dataFromAdditionalService = resultsByService[serviceName];
|
|
207
|
+
if (dataFromAdditionalService?.items?.length) {
|
|
208
|
+
await this.dataEntityService.bulkCreate(dataFromAdditionalService.items, saveOptions);
|
|
209
|
+
if (useResultsForFirstService && !hasFirstServiceResult) {
|
|
210
|
+
result = dataFromAdditionalService;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
result,
|
|
216
|
+
resultsByService
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
public findOne(
|
|
221
|
+
// eslint-disable-next-line no-unused-vars
|
|
222
|
+
options: DomainFindOneOptions,
|
|
223
|
+
// eslint-disable-next-line no-unused-vars
|
|
224
|
+
privateOptions?: DomainFindPrivateOptions
|
|
225
|
+
): Promise<DomainFindOneResult<Entity>>;
|
|
226
|
+
async findOne(
|
|
227
|
+
options: DomainFindOneOptions,
|
|
228
|
+
privateOptions?: DomainFindPrivateOptions
|
|
229
|
+
): Promise<DomainFindOneResult<Entity>> {
|
|
230
|
+
if (!this.defaultMethods?.includes(DomainMethod.FindOne)) {
|
|
231
|
+
throw new ApplicationError(`Method findOne not implemented for class ${typeof this}.`);
|
|
232
|
+
}
|
|
233
|
+
const {
|
|
234
|
+
optionsOverridesByService,
|
|
235
|
+
dataServices = [DomainDataEntityServiceType.Main],
|
|
236
|
+
saveAdditionalResultsInFirstService,
|
|
237
|
+
...otherOptions
|
|
238
|
+
} = options || {};
|
|
239
|
+
const [firstServiceName, ...otherServiceNames] = dataServices;
|
|
240
|
+
let result: Entity | null = await this.getDataService(firstServiceName).findOne(otherOptions, privateOptions);
|
|
241
|
+
const hasFirstServiceResult = typeof result !== 'undefined' && result !== null;
|
|
242
|
+
const resultsByService = await this.runMethodInAdditionalServices<Entity | null>(otherServiceNames || [], {
|
|
243
|
+
firstServiceResult: result,
|
|
244
|
+
hasFirstServiceResult,
|
|
245
|
+
methodArgs: [otherOptions, privateOptions],
|
|
246
|
+
methodName: 'findOne',
|
|
247
|
+
optionsArgIndex: 0,
|
|
248
|
+
optionsOverridesByService
|
|
249
|
+
});
|
|
250
|
+
if (saveAdditionalResultsInFirstService && resultsByService) {
|
|
251
|
+
const { saveOptions, serviceName, useResultsForFirstService } = saveAdditionalResultsInFirstService;
|
|
252
|
+
const dataFromAdditionalService = resultsByService[serviceName];
|
|
253
|
+
if (dataFromAdditionalService) {
|
|
254
|
+
await this.dataEntityService.create(dataFromAdditionalService, saveOptions);
|
|
255
|
+
if (useResultsForFirstService && !hasFirstServiceResult) {
|
|
256
|
+
result = dataFromAdditionalService;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return {
|
|
261
|
+
result,
|
|
262
|
+
resultsByService
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
protected getDataService(serviceName: DomainDataEntityServiceType.Main | string): DataEntityService<Entity> {
|
|
267
|
+
if (serviceName === DomainDataEntityServiceType.Main) {
|
|
268
|
+
return this.dataEntityService;
|
|
269
|
+
}
|
|
270
|
+
const service = this.additionalDataEntityServices?.[serviceName];
|
|
271
|
+
if (!service) {
|
|
272
|
+
throw new ApplicationError(
|
|
273
|
+
`DataEntityService ${serviceName} does not exist for DomainEntityService ${this.dataEntityService.getEntityName(true) || '(no entity name)'}.`
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
return service as DataEntityService<Entity>;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
protected async runMethodInAdditionalServices<ServiceReturnData>(
|
|
280
|
+
serviceNames: string[],
|
|
281
|
+
options: DomainRunMethodInAdditionalServicesOptions<unknown>
|
|
282
|
+
): Promise<GenericObject<ServiceReturnData> | undefined> {
|
|
283
|
+
if (!serviceNames.length) {
|
|
284
|
+
return undefined;
|
|
285
|
+
}
|
|
286
|
+
const {
|
|
287
|
+
firstServiceResult,
|
|
288
|
+
hasFirstServiceResult,
|
|
289
|
+
methodArgs = [],
|
|
290
|
+
methodName,
|
|
291
|
+
optionsArgIndex,
|
|
292
|
+
optionsOverridesByService = {}
|
|
293
|
+
} = options;
|
|
294
|
+
const returnDataByService: GenericObject<ServiceReturnData> = {};
|
|
295
|
+
if (!this.additionalDataEntityServices) {
|
|
296
|
+
throw new ApplicationError(
|
|
297
|
+
`No additional DataEntityServices exist for DomainEntityService ${this.dataEntityService.getEntityName(true) || '(no entity name)'}.`
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
if (
|
|
301
|
+
Object.keys(optionsOverridesByService).length &&
|
|
302
|
+
(typeof optionsArgIndex === 'undefined' || optionsArgIndex < 0 || optionsArgIndex > methodArgs.length - 1)
|
|
303
|
+
) {
|
|
304
|
+
throw new ApplicationError(
|
|
305
|
+
`Invalid optionsArgIndex value ${optionsArgIndex} provided for DomainEntityService ${this.dataEntityService.getEntityName(true) || '(no entity name)'}.}.`
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
for (const i in serviceNames) {
|
|
309
|
+
const serviceName = serviceNames[i];
|
|
310
|
+
const service = this.getDataService(serviceName);
|
|
311
|
+
if (!service) {
|
|
312
|
+
throw new ApplicationError(
|
|
313
|
+
`DataEntityService ${serviceName} does not exist for DomainEntityService ${this.dataEntityService.getEntityName(true) || '(no entity name)'}.`
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
const serviceMethodOptionsOverrides = optionsOverridesByService[serviceName] || {};
|
|
317
|
+
const {
|
|
318
|
+
filterByFirstServiceResultFields,
|
|
319
|
+
runOnNoFirstServiceResultOnly = true,
|
|
320
|
+
...actualMethodOptionsOverrides
|
|
321
|
+
} = serviceMethodOptionsOverrides;
|
|
322
|
+
// be extra careful when working with data that has TTL as the main service,
|
|
323
|
+
// since there is no way to check for limited results here.
|
|
324
|
+
if (
|
|
325
|
+
(runOnNoFirstServiceResultOnly === true || runOnNoFirstServiceResultOnly === 'true') &&
|
|
326
|
+
hasFirstServiceResult
|
|
327
|
+
) {
|
|
328
|
+
continue;
|
|
329
|
+
}
|
|
330
|
+
const serviceMethodArgs = ld.cloneDeep(methodArgs);
|
|
331
|
+
if (typeof serviceMethodArgs[optionsArgIndex!] === 'undefined') {
|
|
332
|
+
if (optionsArgIndex! > serviceMethodArgs.length - 1) {
|
|
333
|
+
serviceMethodArgs.push(actualMethodOptionsOverrides);
|
|
334
|
+
} else {
|
|
335
|
+
serviceMethodArgs[optionsArgIndex!] = actualMethodOptionsOverrides;
|
|
336
|
+
}
|
|
337
|
+
} else {
|
|
338
|
+
serviceMethodArgs[optionsArgIndex!] = {
|
|
339
|
+
...(serviceMethodArgs[optionsArgIndex!] as object),
|
|
340
|
+
...actualMethodOptionsOverrides
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
if (filterByFirstServiceResultFields && Object.keys(filterByFirstServiceResultFields).length) {
|
|
344
|
+
if (!hasFirstServiceResult) {
|
|
345
|
+
continue;
|
|
346
|
+
}
|
|
347
|
+
const filters: GenericObject = {};
|
|
348
|
+
const resultItems: GenericObject[] = (firstServiceResult as { items?: GenericObject[] }).items || [
|
|
349
|
+
firstServiceResult as GenericObject
|
|
350
|
+
];
|
|
351
|
+
resultItems.forEach(resultItem => {
|
|
352
|
+
if (!resultItem) {
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
for (const sourceFieldName in filterByFirstServiceResultFields) {
|
|
356
|
+
const fieldValue = resultItem[sourceFieldName];
|
|
357
|
+
const targetFieldName = filterByFirstServiceResultFields[sourceFieldName];
|
|
358
|
+
if (typeof fieldValue === 'undefined') {
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
if (!filters[targetFieldName]) {
|
|
362
|
+
filters[targetFieldName] = [];
|
|
363
|
+
}
|
|
364
|
+
(filters[targetFieldName] as unknown[]).push(fieldValue);
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
if (Object.keys(filters).length) {
|
|
368
|
+
const serviceMethodOptions = serviceMethodArgs[optionsArgIndex!] as GenericObject & {
|
|
369
|
+
filters?: GenericObject;
|
|
370
|
+
};
|
|
371
|
+
serviceMethodArgs[optionsArgIndex!] = {
|
|
372
|
+
...serviceMethodOptions,
|
|
373
|
+
filters: {
|
|
374
|
+
...ld.omit(serviceMethodOptions.filters || {}, ['page', 'perPage']),
|
|
375
|
+
...filters
|
|
376
|
+
},
|
|
377
|
+
findAll: true
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
returnDataByService[serviceName] = (await (
|
|
382
|
+
service[methodName as keyof DataEntityService<Entity>] as unknown as (
|
|
383
|
+
..._args: unknown[]
|
|
384
|
+
) => Promise<ServiceReturnData>
|
|
385
|
+
).apply(service, serviceMethodArgs)) as ServiceReturnData;
|
|
386
|
+
}
|
|
387
|
+
return returnDataByService;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
public update(
|
|
391
|
+
// eslint-disable-next-line no-unused-vars
|
|
392
|
+
data: Data['Update'],
|
|
393
|
+
// eslint-disable-next-line no-unused-vars
|
|
394
|
+
options: DomainUpdateOptions,
|
|
395
|
+
// eslint-disable-next-line no-unused-vars
|
|
396
|
+
privateOptions?: DomainUpdatePrivateOptions
|
|
397
|
+
): Promise<DomainUpdateResult<Entity>>;
|
|
398
|
+
async update(
|
|
399
|
+
data: Data['Update'],
|
|
400
|
+
options: DomainUpdateOptions,
|
|
401
|
+
privateOptions?: DomainUpdatePrivateOptions
|
|
402
|
+
): Promise<DomainUpdateResult<Entity>> {
|
|
403
|
+
if (!this.defaultMethods?.includes(DomainMethod.Update)) {
|
|
404
|
+
throw new ApplicationError(`Method update not implemented for class ${typeof this}.`);
|
|
405
|
+
}
|
|
406
|
+
const { optionsOverridesByService, dataServices = [DomainDataEntityServiceType.Main], ...otherOptions } = options;
|
|
407
|
+
const [firstServiceName, ...otherServiceNames] = dataServices;
|
|
408
|
+
const result = await this.getDataService(firstServiceName).update(data, otherOptions, privateOptions);
|
|
409
|
+
return {
|
|
410
|
+
result,
|
|
411
|
+
resultsByService: await this.runMethodInAdditionalServices(otherServiceNames || [], {
|
|
412
|
+
firstServiceResult: result,
|
|
413
|
+
hasFirstServiceResult: !!result.count,
|
|
414
|
+
methodArgs: [data, otherOptions, privateOptions],
|
|
415
|
+
methodName: 'update',
|
|
416
|
+
optionsArgIndex: 1,
|
|
417
|
+
optionsOverridesByService
|
|
418
|
+
})
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
}
|