@ruiapp/rapid-core 0.5.11 → 0.5.13
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/CHANGELOG.md +7 -7
- package/dist/facilities/cache/CacheFacilityTypes.d.ts +4 -2
- package/dist/facilities/cache/MemoryCache.d.ts +3 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +131 -72
- package/dist/utilities/entityUtility.d.ts +1 -0
- package/dist/utilities/passwordUtility.d.ts +14 -0
- package/package.json +2 -2
- package/rollup.config.js +16 -16
- package/src/bootstrapApplicationConfig.ts +638 -638
- package/src/core/actionHandler.ts +22 -22
- package/src/core/eventManager.ts +20 -20
- package/src/core/facility.ts +7 -7
- package/src/core/http/formDataParser.ts +89 -89
- package/src/core/http-types.ts +4 -4
- package/src/core/pluginManager.ts +175 -175
- package/src/core/providers/runtimeProvider.ts +5 -5
- package/src/core/request.ts +95 -95
- package/src/core/response.ts +79 -79
- package/src/core/routeContext.ts +100 -100
- package/src/core/routesBuilder.ts +88 -88
- package/src/core/server.ts +145 -145
- package/src/dataAccess/columnTypeMapper.ts +22 -22
- package/src/dataAccess/dataAccessTypes.ts +163 -163
- package/src/dataAccess/dataAccessor.ts +135 -135
- package/src/dataAccess/entityManager.ts +1910 -1910
- package/src/dataAccess/entityMapper.ts +100 -100
- package/src/dataAccess/propertyMapper.ts +28 -28
- package/src/deno-std/assert/assert.ts +9 -9
- package/src/deno-std/assert/assertion_error.ts +7 -7
- package/src/deno-std/datetime/to_imf.ts +32 -32
- package/src/deno-std/encoding/base64.ts +141 -141
- package/src/deno-std/http/cookie.ts +372 -372
- package/src/facilities/cache/CacheFacilityTypes.ts +29 -27
- package/src/facilities/cache/CacheFactory.ts +31 -31
- package/src/facilities/cache/MemoryCache.ts +58 -42
- package/src/facilities/cache/MemoryCacheProvider.ts +15 -15
- package/src/facilities/log/LogFacility.ts +35 -35
- package/src/helpers/entityHelpers.ts +76 -76
- package/src/helpers/filterHelper.ts +148 -148
- package/src/helpers/inputHelper.ts +11 -11
- package/src/helpers/metaHelper.ts +104 -104
- package/src/helpers/runCollectionEntityActionHandler.ts +57 -57
- package/src/index.ts +67 -63
- package/src/plugins/auth/AuthPlugin.ts +93 -93
- package/src/plugins/auth/actionHandlers/changePassword.ts +60 -61
- package/src/plugins/auth/actionHandlers/createSession.ts +68 -68
- package/src/plugins/auth/actionHandlers/deleteSession.ts +18 -18
- package/src/plugins/auth/actionHandlers/getMyProfile.ts +35 -35
- package/src/plugins/auth/actionHandlers/index.ts +8 -8
- package/src/plugins/auth/actionHandlers/resetPassword.ts +44 -45
- package/src/plugins/auth/models/AccessToken.ts +56 -56
- package/src/plugins/auth/models/index.ts +3 -3
- package/src/plugins/auth/routes/changePassword.ts +15 -15
- package/src/plugins/auth/routes/getMyProfile.ts +15 -15
- package/src/plugins/auth/routes/index.ts +7 -7
- package/src/plugins/auth/routes/resetPassword.ts +15 -15
- package/src/plugins/auth/routes/signin.ts +15 -15
- package/src/plugins/auth/routes/signout.ts +15 -15
- package/src/plugins/auth/services/AuthService.ts +39 -39
- package/src/plugins/cronJob/CronJobPlugin.ts +112 -112
- package/src/plugins/cronJob/CronJobPluginTypes.ts +49 -49
- package/src/plugins/cronJob/actionHandlers/index.ts +4 -4
- package/src/plugins/cronJob/actionHandlers/runCronJob.ts +29 -29
- package/src/plugins/cronJob/routes/index.ts +3 -3
- package/src/plugins/cronJob/routes/runCronJob.ts +15 -15
- package/src/plugins/dataManage/DataManagePlugin.ts +163 -163
- package/src/plugins/dataManage/actionHandlers/addEntityRelations.ts +15 -15
- package/src/plugins/dataManage/actionHandlers/countCollectionEntities.ts +17 -17
- package/src/plugins/dataManage/actionHandlers/createCollectionEntitiesBatch.ts +81 -81
- package/src/plugins/dataManage/actionHandlers/createCollectionEntity.ts +20 -20
- package/src/plugins/dataManage/actionHandlers/deleteCollectionEntities.ts +45 -45
- package/src/plugins/dataManage/actionHandlers/deleteCollectionEntityById.ts +20 -20
- package/src/plugins/dataManage/actionHandlers/findCollectionEntities.ts +27 -27
- package/src/plugins/dataManage/actionHandlers/findCollectionEntityById.ts +30 -30
- package/src/plugins/dataManage/actionHandlers/queryDatabase.ts +22 -22
- package/src/plugins/dataManage/actionHandlers/removeEntityRelations.ts +15 -15
- package/src/plugins/dataManage/actionHandlers/updateCollectionEntityById.ts +38 -38
- package/src/plugins/entityAccessControl/EntityAccessControlPlugin.ts +146 -146
- package/src/plugins/fileManage/FileManagePlugin.ts +52 -52
- package/src/plugins/fileManage/actionHandlers/downloadDocument.ts +65 -65
- package/src/plugins/fileManage/actionHandlers/downloadFile.ts +44 -44
- package/src/plugins/fileManage/actionHandlers/uploadFile.ts +33 -33
- package/src/plugins/fileManage/routes/downloadDocument.ts +15 -15
- package/src/plugins/fileManage/routes/downloadFile.ts +15 -15
- package/src/plugins/fileManage/routes/index.ts +5 -5
- package/src/plugins/fileManage/routes/uploadFile.ts +15 -15
- package/src/plugins/license/LicensePlugin.ts +79 -79
- package/src/plugins/license/LicensePluginTypes.ts +95 -95
- package/src/plugins/license/LicenseService.ts +118 -118
- package/src/plugins/license/actionHandlers/getLicense.ts +18 -18
- package/src/plugins/license/actionHandlers/index.ts +4 -4
- package/src/plugins/license/helpers/certHelper.ts +21 -21
- package/src/plugins/license/helpers/cryptoHelper.ts +47 -47
- package/src/plugins/license/models/index.ts +1 -1
- package/src/plugins/license/routes/getLicense.ts +15 -15
- package/src/plugins/license/routes/index.ts +3 -3
- package/src/plugins/mail/MailPlugin.ts +74 -74
- package/src/plugins/mail/MailPluginTypes.ts +27 -27
- package/src/plugins/mail/MailService.ts +38 -38
- package/src/plugins/mail/actionHandlers/index.ts +3 -3
- package/src/plugins/mail/models/index.ts +1 -1
- package/src/plugins/mail/routes/index.ts +1 -1
- package/src/plugins/metaManage/MetaManagePlugin.ts +530 -530
- package/src/plugins/metaManage/actionHandlers/getMetaModelDetail.ts +10 -10
- package/src/plugins/metaManage/actionHandlers/listMetaModels.ts +9 -9
- package/src/plugins/metaManage/actionHandlers/listMetaRoutes.ts +9 -9
- package/src/plugins/notification/NotificationPlugin.ts +68 -68
- package/src/plugins/notification/NotificationPluginTypes.ts +13 -13
- package/src/plugins/notification/NotificationService.ts +25 -25
- package/src/plugins/notification/actionHandlers/index.ts +3 -3
- package/src/plugins/notification/models/Notification.ts +60 -60
- package/src/plugins/notification/models/index.ts +3 -3
- package/src/plugins/notification/routes/index.ts +1 -1
- package/src/plugins/routeManage/RouteManagePlugin.ts +62 -62
- package/src/plugins/routeManage/actionHandlers/httpProxy.ts +13 -13
- package/src/plugins/sequence/SequencePlugin.ts +146 -146
- package/src/plugins/sequence/SequencePluginTypes.ts +69 -69
- package/src/plugins/sequence/SequenceService.ts +92 -92
- package/src/plugins/sequence/actionHandlers/generateSn.ts +32 -32
- package/src/plugins/sequence/actionHandlers/index.ts +4 -4
- package/src/plugins/sequence/models/SequenceAutoIncrementRecord.ts +49 -49
- package/src/plugins/sequence/models/SequenceRule.ts +42 -42
- package/src/plugins/sequence/models/index.ts +4 -4
- package/src/plugins/sequence/routes/generateSn.ts +15 -15
- package/src/plugins/sequence/routes/index.ts +3 -3
- package/src/plugins/sequence/segment-utility.ts +11 -11
- package/src/plugins/sequence/segments/autoIncrement.ts +90 -90
- package/src/plugins/sequence/segments/dayOfMonth.ts +19 -19
- package/src/plugins/sequence/segments/index.ts +9 -9
- package/src/plugins/sequence/segments/literal.ts +16 -16
- package/src/plugins/sequence/segments/month.ts +19 -19
- package/src/plugins/sequence/segments/parameter.ts +20 -20
- package/src/plugins/sequence/segments/year.ts +19 -19
- package/src/plugins/serverOperation/ServerOperationPlugin.ts +91 -91
- package/src/plugins/serverOperation/ServerOperationPluginTypes.ts +15 -15
- package/src/plugins/serverOperation/actionHandlers/index.ts +4 -4
- package/src/plugins/serverOperation/actionHandlers/runServerOperation.ts +15 -15
- package/src/plugins/setting/SettingPlugin.ts +68 -68
- package/src/plugins/setting/SettingPluginTypes.ts +37 -37
- package/src/plugins/setting/SettingService.ts +213 -213
- package/src/plugins/setting/actionHandlers/getSystemSettingValues.ts +30 -30
- package/src/plugins/setting/actionHandlers/getUserSettingValues.ts +38 -38
- package/src/plugins/setting/actionHandlers/index.ts +6 -6
- package/src/plugins/setting/actionHandlers/setSystemSettingValues.ts +30 -30
- package/src/plugins/setting/models/SystemSettingGroupSetting.ts +57 -57
- package/src/plugins/setting/models/SystemSettingItem.ts +48 -48
- package/src/plugins/setting/models/SystemSettingItemSetting.ts +73 -73
- package/src/plugins/setting/models/UserSettingGroupSetting.ts +57 -57
- package/src/plugins/setting/models/UserSettingItem.ts +55 -55
- package/src/plugins/setting/models/UserSettingItemSetting.ts +73 -73
- package/src/plugins/setting/models/index.ts +8 -8
- package/src/plugins/setting/routes/getSystemSettingValues.ts +15 -15
- package/src/plugins/setting/routes/getUserSettingValues.ts +15 -15
- package/src/plugins/setting/routes/index.ts +5 -5
- package/src/plugins/setting/routes/setSystemSettingValues.ts +15 -15
- package/src/plugins/stateMachine/StateMachinePlugin.ts +196 -196
- package/src/plugins/stateMachine/StateMachinePluginTypes.ts +48 -48
- package/src/plugins/stateMachine/actionHandlers/index.ts +4 -4
- package/src/plugins/stateMachine/actionHandlers/sendStateMachineEvent.ts +54 -54
- package/src/plugins/stateMachine/models/StateMachine.ts +42 -42
- package/src/plugins/stateMachine/models/index.ts +3 -3
- package/src/plugins/stateMachine/routes/index.ts +3 -3
- package/src/plugins/stateMachine/routes/sendStateMachineEvent.ts +15 -15
- package/src/plugins/stateMachine/stateMachineHelper.ts +36 -36
- package/src/plugins/webhooks/WebhooksPlugin.ts +148 -148
- package/src/plugins/webhooks/pluginConfig.ts +75 -75
- package/src/polyfill.ts +5 -5
- package/src/proxy/mod.ts +38 -38
- package/src/proxy/types.ts +21 -21
- package/src/queryBuilder/index.ts +1 -1
- package/src/queryBuilder/queryBuilder.ts +668 -668
- package/src/server.ts +480 -480
- package/src/types.ts +722 -722
- package/src/utilities/accessControlUtility.ts +33 -33
- package/src/utilities/entityUtility.ts +18 -0
- package/src/utilities/errorUtility.ts +15 -15
- package/src/utilities/fsUtility.ts +61 -61
- package/src/utilities/httpUtility.ts +19 -19
- package/src/utilities/jwtUtility.ts +26 -26
- package/src/utilities/passwordUtility.ts +26 -0
- package/src/utilities/pathUtility.ts +14 -14
- package/src/utilities/timeUtility.ts +9 -9
- package/src/utilities/typeUtility.ts +15 -15
- package/tsconfig.json +19 -19
package/src/server.ts
CHANGED
|
@@ -1,480 +1,480 @@
|
|
|
1
|
-
import DataAccessor from "./dataAccess/dataAccessor";
|
|
2
|
-
import {
|
|
3
|
-
GetDataAccessorOptions,
|
|
4
|
-
GetModelOptions,
|
|
5
|
-
IDatabaseAccessor,
|
|
6
|
-
IDatabaseConfig,
|
|
7
|
-
IQueryBuilder,
|
|
8
|
-
IRpdDataAccessor,
|
|
9
|
-
RpdApplicationConfig,
|
|
10
|
-
RpdDataModel,
|
|
11
|
-
RpdServerEventTypes,
|
|
12
|
-
RapidServerConfig,
|
|
13
|
-
RpdDataModelProperty,
|
|
14
|
-
CreateEntityOptions,
|
|
15
|
-
UpdateEntityByIdOptions,
|
|
16
|
-
EntityWatchHandlerContext,
|
|
17
|
-
EntityWatcherType,
|
|
18
|
-
RpdEntityCreateEventPayload,
|
|
19
|
-
EmitServerEventOptions,
|
|
20
|
-
IDatabaseClient,
|
|
21
|
-
} from "./types";
|
|
22
|
-
|
|
23
|
-
import QueryBuilder from "./queryBuilder/queryBuilder";
|
|
24
|
-
import PluginManager from "./core/pluginManager";
|
|
25
|
-
import EventManager from "./core/eventManager";
|
|
26
|
-
import { ActionHandler, ActionHandlerContext, IPluginActionHandler } from "./core/actionHandler";
|
|
27
|
-
import { IRpdServer, RapidPlugin } from "./core/server";
|
|
28
|
-
import { buildRoutes } from "./core/routesBuilder";
|
|
29
|
-
import { Next, RouteContext } from "./core/routeContext";
|
|
30
|
-
import { RapidRequest } from "./core/request";
|
|
31
|
-
import bootstrapApplicationConfig from "./bootstrapApplicationConfig";
|
|
32
|
-
import EntityManager from "./dataAccess/entityManager";
|
|
33
|
-
import { bind, cloneDeep, find, forEach, merge, omit } from "lodash";
|
|
34
|
-
import { Logger } from "./facilities/log/LogFacility";
|
|
35
|
-
import { FacilityFactory } from "./core/facility";
|
|
36
|
-
|
|
37
|
-
export interface InitServerOptions {
|
|
38
|
-
logger: Logger;
|
|
39
|
-
databaseAccessor: IDatabaseAccessor;
|
|
40
|
-
databaseConfig: IDatabaseConfig;
|
|
41
|
-
serverConfig: RapidServerConfig;
|
|
42
|
-
applicationConfig?: RpdApplicationConfig;
|
|
43
|
-
facilityFactories?: FacilityFactory[];
|
|
44
|
-
plugins?: RapidPlugin[];
|
|
45
|
-
entityWatchers?: EntityWatcherType[];
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export class RapidServer implements IRpdServer {
|
|
49
|
-
#logger: Logger;
|
|
50
|
-
#facilityFactories: Map<string, FacilityFactory>;
|
|
51
|
-
#pluginManager: PluginManager;
|
|
52
|
-
#plugins: RapidPlugin[];
|
|
53
|
-
#eventManager: EventManager<RpdServerEventTypes>;
|
|
54
|
-
#middlewares: any[];
|
|
55
|
-
#bootstrapApplicationConfig: RpdApplicationConfig;
|
|
56
|
-
#applicationConfig: RpdApplicationConfig;
|
|
57
|
-
#actionHandlersMapByCode: Map<string, ActionHandler>;
|
|
58
|
-
#databaseAccessor: IDatabaseAccessor;
|
|
59
|
-
#cachedDataAccessors: Map<string, DataAccessor>;
|
|
60
|
-
|
|
61
|
-
#entityBeforeCreateEventEmitters: EventManager<Record<string, [EntityWatchHandlerContext<any>]>>;
|
|
62
|
-
#entityCreateEventEmitters: EventManager<Record<string, [EntityWatchHandlerContext<any>]>>;
|
|
63
|
-
#entityBeforeUpdateEventEmitters: EventManager<Record<string, [EntityWatchHandlerContext<any>]>>;
|
|
64
|
-
#entityUpdateEventEmitters: EventManager<Record<string, [EntityWatchHandlerContext<any>]>>;
|
|
65
|
-
#entityBeforeDeleteEventEmitters: EventManager<Record<string, [EntityWatchHandlerContext<any>]>>;
|
|
66
|
-
#entityDeleteEventEmitters: EventManager<Record<string, [EntityWatchHandlerContext<any>]>>;
|
|
67
|
-
#entityAddRelationsEventEmitters: EventManager<Record<string, [EntityWatchHandlerContext<any>]>>;
|
|
68
|
-
#entityRemoveRelationsEventEmitters: EventManager<Record<string, [EntityWatchHandlerContext<any>]>>;
|
|
69
|
-
#entityBeforeResponseEventEmitters: EventManager<Record<string, [EntityWatchHandlerContext<any>]>>;
|
|
70
|
-
#entityWatchers: EntityWatcherType[];
|
|
71
|
-
#appEntityWatchers: EntityWatcherType[];
|
|
72
|
-
|
|
73
|
-
#cachedEntityManager: Map<string, EntityManager>;
|
|
74
|
-
#services: Map<string, any>;
|
|
75
|
-
queryBuilder: IQueryBuilder;
|
|
76
|
-
config: RapidServerConfig;
|
|
77
|
-
databaseConfig: IDatabaseConfig;
|
|
78
|
-
#buildedRoutes: (ctx: any, next: any) => any;
|
|
79
|
-
|
|
80
|
-
constructor(options: InitServerOptions) {
|
|
81
|
-
this.#logger = options.logger;
|
|
82
|
-
|
|
83
|
-
this.#facilityFactories = new Map();
|
|
84
|
-
if (options.facilityFactories) {
|
|
85
|
-
forEach(options.facilityFactories, (factory) => {
|
|
86
|
-
this.registerFacilityFactory(factory);
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
this.#pluginManager = new PluginManager(this);
|
|
91
|
-
this.#eventManager = new EventManager();
|
|
92
|
-
this.#middlewares = [];
|
|
93
|
-
this.#bootstrapApplicationConfig = options.applicationConfig || bootstrapApplicationConfig;
|
|
94
|
-
|
|
95
|
-
this.#applicationConfig = {} as RpdApplicationConfig;
|
|
96
|
-
this.#actionHandlersMapByCode = new Map();
|
|
97
|
-
this.#databaseAccessor = options.databaseAccessor;
|
|
98
|
-
this.#cachedDataAccessors = new Map();
|
|
99
|
-
this.#cachedEntityManager = new Map();
|
|
100
|
-
|
|
101
|
-
this.#entityBeforeCreateEventEmitters = new EventManager();
|
|
102
|
-
this.#entityCreateEventEmitters = new EventManager();
|
|
103
|
-
this.#entityBeforeUpdateEventEmitters = new EventManager();
|
|
104
|
-
this.#entityUpdateEventEmitters = new EventManager();
|
|
105
|
-
this.#entityBeforeDeleteEventEmitters = new EventManager();
|
|
106
|
-
this.#entityDeleteEventEmitters = new EventManager();
|
|
107
|
-
this.#entityAddRelationsEventEmitters = new EventManager();
|
|
108
|
-
this.#entityRemoveRelationsEventEmitters = new EventManager();
|
|
109
|
-
this.#entityBeforeResponseEventEmitters = new EventManager();
|
|
110
|
-
|
|
111
|
-
this.registerEventHandler("entity.beforeCreate", this.#handleEntityEvent.bind(this, "entity.beforeCreate"));
|
|
112
|
-
this.registerEventHandler("entity.create", this.#handleEntityEvent.bind(this, "entity.create"));
|
|
113
|
-
this.registerEventHandler("entity.beforeUpdate", this.#handleEntityEvent.bind(this, "entity.beforeUpdate"));
|
|
114
|
-
this.registerEventHandler("entity.update", this.#handleEntityEvent.bind(this, "entity.update"));
|
|
115
|
-
this.registerEventHandler("entity.beforeDelete", this.#handleEntityEvent.bind(this, "entity.beforeDelete"));
|
|
116
|
-
this.registerEventHandler("entity.delete", this.#handleEntityEvent.bind(this, "entity.delete"));
|
|
117
|
-
this.registerEventHandler("entity.addRelations", this.#handleEntityEvent.bind(this, "entity.addRelations"));
|
|
118
|
-
this.registerEventHandler("entity.removeRelations", this.#handleEntityEvent.bind(this, "entity.removeRelations"));
|
|
119
|
-
this.registerEventHandler("entity.beforeResponse", this.#handleEntityEvent.bind(this, "entity.beforeResponse"));
|
|
120
|
-
|
|
121
|
-
this.#entityWatchers = [];
|
|
122
|
-
this.#appEntityWatchers = options.entityWatchers || [];
|
|
123
|
-
|
|
124
|
-
this.#services = new Map();
|
|
125
|
-
|
|
126
|
-
this.queryBuilder = new QueryBuilder({
|
|
127
|
-
dbDefaultSchema: options.databaseConfig.dbDefaultSchema,
|
|
128
|
-
});
|
|
129
|
-
this.databaseConfig = options.databaseConfig;
|
|
130
|
-
this.config = options.serverConfig;
|
|
131
|
-
|
|
132
|
-
this.#plugins = options.plugins || [];
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
getLogger(): Logger {
|
|
136
|
-
return this.#logger;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
getApplicationConfig() {
|
|
140
|
-
return this.#applicationConfig;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
getDatabaseAccessor(): IDatabaseAccessor {
|
|
144
|
-
return this.#databaseAccessor;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
appendApplicationConfig(config: Partial<RpdApplicationConfig>) {
|
|
148
|
-
const { models, dataDictionaries, routes } = config;
|
|
149
|
-
if (models) {
|
|
150
|
-
for (const model of models) {
|
|
151
|
-
const originalModel = find(this.#applicationConfig.models, (item) => item.singularCode == model.singularCode);
|
|
152
|
-
if (originalModel) {
|
|
153
|
-
merge(
|
|
154
|
-
originalModel,
|
|
155
|
-
omit(model, ["id", "maintainedBy", "namespace", "singularCode", "pluralCode", "schema", "tableName", "properties", "extensions"]),
|
|
156
|
-
);
|
|
157
|
-
originalModel.name = model.name;
|
|
158
|
-
const originalProperties = originalModel.properties;
|
|
159
|
-
for (const property of model.properties) {
|
|
160
|
-
const originalProperty = find(originalProperties, (item) => item.code == property.code);
|
|
161
|
-
if (originalProperty) {
|
|
162
|
-
originalProperty.name = property.name;
|
|
163
|
-
} else {
|
|
164
|
-
originalProperties.push(property);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
} else {
|
|
168
|
-
this.#applicationConfig.models.push(model);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
if (dataDictionaries) {
|
|
174
|
-
for (const dataDictionary of dataDictionaries) {
|
|
175
|
-
const originalDataDictionary = find(this.#applicationConfig.dataDictionaries, (item) => item.code == dataDictionary.code);
|
|
176
|
-
if (originalDataDictionary) {
|
|
177
|
-
originalDataDictionary.name = dataDictionary.name;
|
|
178
|
-
originalDataDictionary.description = dataDictionary.description;
|
|
179
|
-
originalDataDictionary.entries = dataDictionary.entries;
|
|
180
|
-
} else {
|
|
181
|
-
this.#applicationConfig.dataDictionaries.push(dataDictionary);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
if (routes) {
|
|
186
|
-
for (const route of routes) {
|
|
187
|
-
const originalRoute = find(this.#applicationConfig.routes, (item) => item.code == route.code);
|
|
188
|
-
if (originalRoute) {
|
|
189
|
-
originalRoute.name = route.name;
|
|
190
|
-
originalRoute.actions = route.actions;
|
|
191
|
-
} else {
|
|
192
|
-
this.#applicationConfig.routes.push(route);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
appendModelProperties(modelSingularCode: string, properties: RpdDataModelProperty[]) {
|
|
199
|
-
const originalModel = find(this.#applicationConfig.models, (item) => item.singularCode == modelSingularCode);
|
|
200
|
-
if (!originalModel) {
|
|
201
|
-
throw new Error(`Cannot append model properties. Model '${modelSingularCode}' was not found.`);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
const originalProperties = originalModel.properties;
|
|
205
|
-
for (const property of properties) {
|
|
206
|
-
const originalProperty = find(originalProperties, (item) => item.code == property.code);
|
|
207
|
-
if (originalProperty) {
|
|
208
|
-
originalProperty.name = property.name;
|
|
209
|
-
} else {
|
|
210
|
-
originalProperties.push(property);
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
registerActionHandler(plugin: RapidPlugin, options: IPluginActionHandler) {
|
|
216
|
-
const handler = bind(options.handler, null, plugin);
|
|
217
|
-
this.#actionHandlersMapByCode.set(options.code, handler);
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
getActionHandlerByCode(code: string) {
|
|
221
|
-
return this.#actionHandlersMapByCode.get(code);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
registerMiddleware(middleware: any) {
|
|
225
|
-
this.#middlewares.push(middleware);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
getDataAccessor<T = any>(options: GetDataAccessorOptions): IRpdDataAccessor<T> {
|
|
229
|
-
const { namespace, singularCode } = options;
|
|
230
|
-
|
|
231
|
-
let dataAccessor = this.#cachedDataAccessors.get(singularCode);
|
|
232
|
-
if (dataAccessor) {
|
|
233
|
-
return dataAccessor;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
const model = this.getModel(options);
|
|
237
|
-
if (!model) {
|
|
238
|
-
throw new Error(`Data model ${namespace}.${singularCode} not found.`);
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
dataAccessor = new DataAccessor<T>(this, this.#databaseAccessor, {
|
|
242
|
-
model,
|
|
243
|
-
queryBuilder: this.queryBuilder as QueryBuilder,
|
|
244
|
-
});
|
|
245
|
-
this.#cachedDataAccessors.set(singularCode, dataAccessor);
|
|
246
|
-
return dataAccessor;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
getModel(options: GetModelOptions): RpdDataModel | undefined {
|
|
250
|
-
if (options.namespace) {
|
|
251
|
-
return this.#applicationConfig?.models.find((e) => e.namespace === options.namespace && e.singularCode === options.singularCode);
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
return this.#applicationConfig?.models.find((e) => e.singularCode === options.singularCode);
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
getEntityManager<TEntity = any>(singularCode: string): EntityManager<TEntity> {
|
|
258
|
-
let entityManager = this.#cachedEntityManager.get(singularCode);
|
|
259
|
-
if (entityManager) {
|
|
260
|
-
return entityManager;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
const dataAccessor = this.getDataAccessor({ singularCode });
|
|
264
|
-
entityManager = new EntityManager(this, dataAccessor);
|
|
265
|
-
this.#cachedEntityManager.set(singularCode, entityManager);
|
|
266
|
-
return entityManager;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
registerEventHandler<K extends keyof RpdServerEventTypes>(eventName: K, listener: (...args: RpdServerEventTypes[K]) => void) {
|
|
270
|
-
this.#eventManager.on(eventName, listener);
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
registerEntityWatcher(entityWatcher: EntityWatcherType) {
|
|
274
|
-
this.#entityWatchers.push(entityWatcher);
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
async emitEvent<TEventName extends keyof RpdServerEventTypes>(event: EmitServerEventOptions<TEventName>) {
|
|
278
|
-
const { eventName, payload, sender, routeContext: routerContext } = event;
|
|
279
|
-
this.#logger.debug(`Emitting '${eventName}' event.`, { eventName });
|
|
280
|
-
this.#logger.verbose(`Event payload: `, { payload });
|
|
281
|
-
await this.#eventManager.emit<TEventName>(eventName, sender, payload as any, routerContext);
|
|
282
|
-
|
|
283
|
-
// TODO: should move this logic into metaManager
|
|
284
|
-
// if (
|
|
285
|
-
// (eventName === "entity.create" || eventName === "entity.update" ||
|
|
286
|
-
// eventName === "entity.delete") &&
|
|
287
|
-
// payload.namespace === "meta"
|
|
288
|
-
// ) {
|
|
289
|
-
// await this.configureApplication();
|
|
290
|
-
// }
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
registerService(name: string, service: any) {
|
|
294
|
-
this.#services.set(name, service);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
getService<TService>(name: string): TService {
|
|
298
|
-
return this.#services.get(name);
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
async start() {
|
|
302
|
-
this.#logger.info("Starting rapid server...");
|
|
303
|
-
const pluginManager = this.#pluginManager;
|
|
304
|
-
await pluginManager.loadPlugins(this.#plugins);
|
|
305
|
-
|
|
306
|
-
await pluginManager.initPlugins();
|
|
307
|
-
|
|
308
|
-
await pluginManager.registerMiddlewares();
|
|
309
|
-
await pluginManager.registerActionHandlers();
|
|
310
|
-
await pluginManager.registerEventHandlers();
|
|
311
|
-
await pluginManager.registerMessageHandlers();
|
|
312
|
-
await pluginManager.registerTaskProcessors();
|
|
313
|
-
|
|
314
|
-
this.#entityWatchers = this.#entityWatchers.concat(this.#appEntityWatchers);
|
|
315
|
-
for (const entityWatcher of this.#entityWatchers) {
|
|
316
|
-
if (entityWatcher.eventName === "entity.beforeCreate") {
|
|
317
|
-
this.#entityBeforeCreateEventEmitters.on(entityWatcher.modelSingularCode, entityWatcher.handler);
|
|
318
|
-
} else if (entityWatcher.eventName === "entity.create") {
|
|
319
|
-
this.#entityCreateEventEmitters.on(entityWatcher.modelSingularCode, entityWatcher.handler);
|
|
320
|
-
} else if (entityWatcher.eventName === "entity.beforeUpdate") {
|
|
321
|
-
this.#entityBeforeUpdateEventEmitters.on(entityWatcher.modelSingularCode, entityWatcher.handler);
|
|
322
|
-
} else if (entityWatcher.eventName === "entity.update") {
|
|
323
|
-
this.#entityUpdateEventEmitters.on(entityWatcher.modelSingularCode, entityWatcher.handler);
|
|
324
|
-
} else if (entityWatcher.eventName === "entity.beforeDelete") {
|
|
325
|
-
this.#entityBeforeDeleteEventEmitters.on(entityWatcher.modelSingularCode, entityWatcher.handler);
|
|
326
|
-
} else if (entityWatcher.eventName === "entity.delete") {
|
|
327
|
-
this.#entityDeleteEventEmitters.on(entityWatcher.modelSingularCode, entityWatcher.handler);
|
|
328
|
-
} else if (entityWatcher.eventName === "entity.addRelations") {
|
|
329
|
-
this.#entityAddRelationsEventEmitters.on(entityWatcher.modelSingularCode, entityWatcher.handler);
|
|
330
|
-
} else if (entityWatcher.eventName === "entity.removeRelations") {
|
|
331
|
-
this.#entityRemoveRelationsEventEmitters.on(entityWatcher.modelSingularCode, entityWatcher.handler);
|
|
332
|
-
} else if (entityWatcher.eventName === "entity.beforeResponse") {
|
|
333
|
-
this.#entityBeforeResponseEventEmitters.on(entityWatcher.modelSingularCode, entityWatcher.handler);
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
await this.configureApplication();
|
|
338
|
-
|
|
339
|
-
this.#logger.info(`Rapid server ready.`);
|
|
340
|
-
await pluginManager.onApplicationReady(this.#applicationConfig);
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
async configureApplication() {
|
|
344
|
-
this.#applicationConfig = cloneDeep(this.#bootstrapApplicationConfig) as RpdApplicationConfig;
|
|
345
|
-
|
|
346
|
-
const pluginManager = this.#pluginManager;
|
|
347
|
-
await pluginManager.onLoadingApplication(this.#applicationConfig);
|
|
348
|
-
await pluginManager.configureModels(this.#applicationConfig);
|
|
349
|
-
await pluginManager.configureModelProperties(this.#applicationConfig);
|
|
350
|
-
await pluginManager.configureServices(this.#applicationConfig);
|
|
351
|
-
await pluginManager.configureRoutes(this.#applicationConfig);
|
|
352
|
-
|
|
353
|
-
// TODO: check application configuration.
|
|
354
|
-
|
|
355
|
-
await pluginManager.onApplicationLoaded(this.#applicationConfig);
|
|
356
|
-
|
|
357
|
-
this.#buildedRoutes = await buildRoutes(this, this.#applicationConfig);
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
registerFacilityFactory(factory: FacilityFactory) {
|
|
361
|
-
this.#facilityFactories.set(factory.name, factory);
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
async getFacility<TFacility = any, TOptions = any>(name: string, options?: TOptions, nullIfUnknownFacility?: boolean): Promise<TFacility> {
|
|
365
|
-
const factory = this.#facilityFactories.get(name);
|
|
366
|
-
if (!factory) {
|
|
367
|
-
if (nullIfUnknownFacility) {
|
|
368
|
-
return null;
|
|
369
|
-
} else {
|
|
370
|
-
throw new Error(`Failed to get facility. Unknown facility name: ${name}`);
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
return await factory.createFacility(this, options);
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
async queryDatabaseObject(sql: string, params?: unknown[] | Record<string, unknown>, client?: IDatabaseClient): Promise<any[]> {
|
|
378
|
-
try {
|
|
379
|
-
return await this.#databaseAccessor.queryDatabaseObject(sql, params, client);
|
|
380
|
-
} catch (err) {
|
|
381
|
-
this.#logger.error("Failed to query database object.", { errorMessage: err.message, sql, params });
|
|
382
|
-
throw err;
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
async tryQueryDatabaseObject(sql: string, params?: unknown[] | Record<string, unknown>, client?: IDatabaseClient): Promise<any[]> {
|
|
387
|
-
try {
|
|
388
|
-
return await this.queryDatabaseObject(sql, params, client);
|
|
389
|
-
} catch (err) {
|
|
390
|
-
this.#logger.error("Failed to query database object.", { errorMessage: err.message, sql, params });
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
return [];
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
get middlewares() {
|
|
397
|
-
return this.#middlewares;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
async handleRequest(request: Request, next: Next) {
|
|
401
|
-
const rapidRequest = new RapidRequest(this, request);
|
|
402
|
-
await rapidRequest.parseBody();
|
|
403
|
-
const routeContext: RouteContext = new RouteContext(this, rapidRequest);
|
|
404
|
-
const { response } = routeContext;
|
|
405
|
-
|
|
406
|
-
try {
|
|
407
|
-
await this.#pluginManager.onPrepareRouteContext(routeContext);
|
|
408
|
-
await this.#buildedRoutes(routeContext, next);
|
|
409
|
-
} catch (ex) {
|
|
410
|
-
this.#logger.error("handle request error:", ex);
|
|
411
|
-
response.json(
|
|
412
|
-
{
|
|
413
|
-
error: {
|
|
414
|
-
message: ex.message || ex,
|
|
415
|
-
},
|
|
416
|
-
},
|
|
417
|
-
500,
|
|
418
|
-
);
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
if (!response.status && !response.body) {
|
|
422
|
-
response.json(
|
|
423
|
-
{
|
|
424
|
-
error: {
|
|
425
|
-
message: "No route handler was found to handle this request.",
|
|
426
|
-
},
|
|
427
|
-
},
|
|
428
|
-
404,
|
|
429
|
-
);
|
|
430
|
-
}
|
|
431
|
-
return response.getResponse();
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
async beforeRunRouteActions(handlerContext: ActionHandlerContext) {
|
|
435
|
-
await this.#pluginManager.beforeRunRouteActions(handlerContext);
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
async beforeCreateEntity(model: RpdDataModel, options: CreateEntityOptions) {
|
|
439
|
-
await this.#pluginManager.beforeCreateEntity(model, options);
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
async beforeUpdateEntity(model: RpdDataModel, options: UpdateEntityByIdOptions, currentEntity: any) {
|
|
443
|
-
await this.#pluginManager.beforeUpdateEntity(model, options, currentEntity);
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
async #handleEntityEvent(eventName: keyof RpdServerEventTypes, sender: RapidPlugin, payload: RpdEntityCreateEventPayload, routerContext?: RouteContext) {
|
|
447
|
-
const { modelSingularCode, baseModelSingularCode } = payload;
|
|
448
|
-
const entityWatchHandlerContext: EntityWatchHandlerContext<typeof eventName> = {
|
|
449
|
-
server: this,
|
|
450
|
-
payload,
|
|
451
|
-
routerContext,
|
|
452
|
-
};
|
|
453
|
-
|
|
454
|
-
let emitter: EventManager<Record<string, [EntityWatchHandlerContext<any>]>>;
|
|
455
|
-
if (eventName === "entity.beforeCreate") {
|
|
456
|
-
emitter = this.#entityBeforeCreateEventEmitters;
|
|
457
|
-
} else if (eventName === "entity.create") {
|
|
458
|
-
emitter = this.#entityCreateEventEmitters;
|
|
459
|
-
} else if (eventName === "entity.beforeUpdate") {
|
|
460
|
-
emitter = this.#entityBeforeUpdateEventEmitters;
|
|
461
|
-
} else if (eventName === "entity.update") {
|
|
462
|
-
emitter = this.#entityUpdateEventEmitters;
|
|
463
|
-
} else if (eventName === "entity.beforeDelete") {
|
|
464
|
-
emitter = this.#entityBeforeDeleteEventEmitters;
|
|
465
|
-
} else if (eventName === "entity.delete") {
|
|
466
|
-
emitter = this.#entityDeleteEventEmitters;
|
|
467
|
-
} else if (eventName === "entity.addRelations") {
|
|
468
|
-
emitter = this.#entityAddRelationsEventEmitters;
|
|
469
|
-
} else if (eventName === "entity.removeRelations") {
|
|
470
|
-
emitter = this.#entityRemoveRelationsEventEmitters;
|
|
471
|
-
} else if (eventName === "entity.beforeResponse") {
|
|
472
|
-
emitter = this.#entityBeforeResponseEventEmitters;
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
await emitter.emit(modelSingularCode, entityWatchHandlerContext);
|
|
476
|
-
if (baseModelSingularCode) {
|
|
477
|
-
await emitter.emit(baseModelSingularCode, entityWatchHandlerContext);
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
}
|
|
1
|
+
import DataAccessor from "./dataAccess/dataAccessor";
|
|
2
|
+
import {
|
|
3
|
+
GetDataAccessorOptions,
|
|
4
|
+
GetModelOptions,
|
|
5
|
+
IDatabaseAccessor,
|
|
6
|
+
IDatabaseConfig,
|
|
7
|
+
IQueryBuilder,
|
|
8
|
+
IRpdDataAccessor,
|
|
9
|
+
RpdApplicationConfig,
|
|
10
|
+
RpdDataModel,
|
|
11
|
+
RpdServerEventTypes,
|
|
12
|
+
RapidServerConfig,
|
|
13
|
+
RpdDataModelProperty,
|
|
14
|
+
CreateEntityOptions,
|
|
15
|
+
UpdateEntityByIdOptions,
|
|
16
|
+
EntityWatchHandlerContext,
|
|
17
|
+
EntityWatcherType,
|
|
18
|
+
RpdEntityCreateEventPayload,
|
|
19
|
+
EmitServerEventOptions,
|
|
20
|
+
IDatabaseClient,
|
|
21
|
+
} from "./types";
|
|
22
|
+
|
|
23
|
+
import QueryBuilder from "./queryBuilder/queryBuilder";
|
|
24
|
+
import PluginManager from "./core/pluginManager";
|
|
25
|
+
import EventManager from "./core/eventManager";
|
|
26
|
+
import { ActionHandler, ActionHandlerContext, IPluginActionHandler } from "./core/actionHandler";
|
|
27
|
+
import { IRpdServer, RapidPlugin } from "./core/server";
|
|
28
|
+
import { buildRoutes } from "./core/routesBuilder";
|
|
29
|
+
import { Next, RouteContext } from "./core/routeContext";
|
|
30
|
+
import { RapidRequest } from "./core/request";
|
|
31
|
+
import bootstrapApplicationConfig from "./bootstrapApplicationConfig";
|
|
32
|
+
import EntityManager from "./dataAccess/entityManager";
|
|
33
|
+
import { bind, cloneDeep, find, forEach, merge, omit } from "lodash";
|
|
34
|
+
import { Logger } from "./facilities/log/LogFacility";
|
|
35
|
+
import { FacilityFactory } from "./core/facility";
|
|
36
|
+
|
|
37
|
+
export interface InitServerOptions {
|
|
38
|
+
logger: Logger;
|
|
39
|
+
databaseAccessor: IDatabaseAccessor;
|
|
40
|
+
databaseConfig: IDatabaseConfig;
|
|
41
|
+
serverConfig: RapidServerConfig;
|
|
42
|
+
applicationConfig?: RpdApplicationConfig;
|
|
43
|
+
facilityFactories?: FacilityFactory[];
|
|
44
|
+
plugins?: RapidPlugin[];
|
|
45
|
+
entityWatchers?: EntityWatcherType[];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export class RapidServer implements IRpdServer {
|
|
49
|
+
#logger: Logger;
|
|
50
|
+
#facilityFactories: Map<string, FacilityFactory>;
|
|
51
|
+
#pluginManager: PluginManager;
|
|
52
|
+
#plugins: RapidPlugin[];
|
|
53
|
+
#eventManager: EventManager<RpdServerEventTypes>;
|
|
54
|
+
#middlewares: any[];
|
|
55
|
+
#bootstrapApplicationConfig: RpdApplicationConfig;
|
|
56
|
+
#applicationConfig: RpdApplicationConfig;
|
|
57
|
+
#actionHandlersMapByCode: Map<string, ActionHandler>;
|
|
58
|
+
#databaseAccessor: IDatabaseAccessor;
|
|
59
|
+
#cachedDataAccessors: Map<string, DataAccessor>;
|
|
60
|
+
|
|
61
|
+
#entityBeforeCreateEventEmitters: EventManager<Record<string, [EntityWatchHandlerContext<any>]>>;
|
|
62
|
+
#entityCreateEventEmitters: EventManager<Record<string, [EntityWatchHandlerContext<any>]>>;
|
|
63
|
+
#entityBeforeUpdateEventEmitters: EventManager<Record<string, [EntityWatchHandlerContext<any>]>>;
|
|
64
|
+
#entityUpdateEventEmitters: EventManager<Record<string, [EntityWatchHandlerContext<any>]>>;
|
|
65
|
+
#entityBeforeDeleteEventEmitters: EventManager<Record<string, [EntityWatchHandlerContext<any>]>>;
|
|
66
|
+
#entityDeleteEventEmitters: EventManager<Record<string, [EntityWatchHandlerContext<any>]>>;
|
|
67
|
+
#entityAddRelationsEventEmitters: EventManager<Record<string, [EntityWatchHandlerContext<any>]>>;
|
|
68
|
+
#entityRemoveRelationsEventEmitters: EventManager<Record<string, [EntityWatchHandlerContext<any>]>>;
|
|
69
|
+
#entityBeforeResponseEventEmitters: EventManager<Record<string, [EntityWatchHandlerContext<any>]>>;
|
|
70
|
+
#entityWatchers: EntityWatcherType[];
|
|
71
|
+
#appEntityWatchers: EntityWatcherType[];
|
|
72
|
+
|
|
73
|
+
#cachedEntityManager: Map<string, EntityManager>;
|
|
74
|
+
#services: Map<string, any>;
|
|
75
|
+
queryBuilder: IQueryBuilder;
|
|
76
|
+
config: RapidServerConfig;
|
|
77
|
+
databaseConfig: IDatabaseConfig;
|
|
78
|
+
#buildedRoutes: (ctx: any, next: any) => any;
|
|
79
|
+
|
|
80
|
+
constructor(options: InitServerOptions) {
|
|
81
|
+
this.#logger = options.logger;
|
|
82
|
+
|
|
83
|
+
this.#facilityFactories = new Map();
|
|
84
|
+
if (options.facilityFactories) {
|
|
85
|
+
forEach(options.facilityFactories, (factory) => {
|
|
86
|
+
this.registerFacilityFactory(factory);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
this.#pluginManager = new PluginManager(this);
|
|
91
|
+
this.#eventManager = new EventManager();
|
|
92
|
+
this.#middlewares = [];
|
|
93
|
+
this.#bootstrapApplicationConfig = options.applicationConfig || bootstrapApplicationConfig;
|
|
94
|
+
|
|
95
|
+
this.#applicationConfig = {} as RpdApplicationConfig;
|
|
96
|
+
this.#actionHandlersMapByCode = new Map();
|
|
97
|
+
this.#databaseAccessor = options.databaseAccessor;
|
|
98
|
+
this.#cachedDataAccessors = new Map();
|
|
99
|
+
this.#cachedEntityManager = new Map();
|
|
100
|
+
|
|
101
|
+
this.#entityBeforeCreateEventEmitters = new EventManager();
|
|
102
|
+
this.#entityCreateEventEmitters = new EventManager();
|
|
103
|
+
this.#entityBeforeUpdateEventEmitters = new EventManager();
|
|
104
|
+
this.#entityUpdateEventEmitters = new EventManager();
|
|
105
|
+
this.#entityBeforeDeleteEventEmitters = new EventManager();
|
|
106
|
+
this.#entityDeleteEventEmitters = new EventManager();
|
|
107
|
+
this.#entityAddRelationsEventEmitters = new EventManager();
|
|
108
|
+
this.#entityRemoveRelationsEventEmitters = new EventManager();
|
|
109
|
+
this.#entityBeforeResponseEventEmitters = new EventManager();
|
|
110
|
+
|
|
111
|
+
this.registerEventHandler("entity.beforeCreate", this.#handleEntityEvent.bind(this, "entity.beforeCreate"));
|
|
112
|
+
this.registerEventHandler("entity.create", this.#handleEntityEvent.bind(this, "entity.create"));
|
|
113
|
+
this.registerEventHandler("entity.beforeUpdate", this.#handleEntityEvent.bind(this, "entity.beforeUpdate"));
|
|
114
|
+
this.registerEventHandler("entity.update", this.#handleEntityEvent.bind(this, "entity.update"));
|
|
115
|
+
this.registerEventHandler("entity.beforeDelete", this.#handleEntityEvent.bind(this, "entity.beforeDelete"));
|
|
116
|
+
this.registerEventHandler("entity.delete", this.#handleEntityEvent.bind(this, "entity.delete"));
|
|
117
|
+
this.registerEventHandler("entity.addRelations", this.#handleEntityEvent.bind(this, "entity.addRelations"));
|
|
118
|
+
this.registerEventHandler("entity.removeRelations", this.#handleEntityEvent.bind(this, "entity.removeRelations"));
|
|
119
|
+
this.registerEventHandler("entity.beforeResponse", this.#handleEntityEvent.bind(this, "entity.beforeResponse"));
|
|
120
|
+
|
|
121
|
+
this.#entityWatchers = [];
|
|
122
|
+
this.#appEntityWatchers = options.entityWatchers || [];
|
|
123
|
+
|
|
124
|
+
this.#services = new Map();
|
|
125
|
+
|
|
126
|
+
this.queryBuilder = new QueryBuilder({
|
|
127
|
+
dbDefaultSchema: options.databaseConfig.dbDefaultSchema,
|
|
128
|
+
});
|
|
129
|
+
this.databaseConfig = options.databaseConfig;
|
|
130
|
+
this.config = options.serverConfig;
|
|
131
|
+
|
|
132
|
+
this.#plugins = options.plugins || [];
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
getLogger(): Logger {
|
|
136
|
+
return this.#logger;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
getApplicationConfig() {
|
|
140
|
+
return this.#applicationConfig;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
getDatabaseAccessor(): IDatabaseAccessor {
|
|
144
|
+
return this.#databaseAccessor;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
appendApplicationConfig(config: Partial<RpdApplicationConfig>) {
|
|
148
|
+
const { models, dataDictionaries, routes } = config;
|
|
149
|
+
if (models) {
|
|
150
|
+
for (const model of models) {
|
|
151
|
+
const originalModel = find(this.#applicationConfig.models, (item) => item.singularCode == model.singularCode);
|
|
152
|
+
if (originalModel) {
|
|
153
|
+
merge(
|
|
154
|
+
originalModel,
|
|
155
|
+
omit(model, ["id", "maintainedBy", "namespace", "singularCode", "pluralCode", "schema", "tableName", "properties", "extensions"]),
|
|
156
|
+
);
|
|
157
|
+
originalModel.name = model.name;
|
|
158
|
+
const originalProperties = originalModel.properties;
|
|
159
|
+
for (const property of model.properties) {
|
|
160
|
+
const originalProperty = find(originalProperties, (item) => item.code == property.code);
|
|
161
|
+
if (originalProperty) {
|
|
162
|
+
originalProperty.name = property.name;
|
|
163
|
+
} else {
|
|
164
|
+
originalProperties.push(property);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
} else {
|
|
168
|
+
this.#applicationConfig.models.push(model);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (dataDictionaries) {
|
|
174
|
+
for (const dataDictionary of dataDictionaries) {
|
|
175
|
+
const originalDataDictionary = find(this.#applicationConfig.dataDictionaries, (item) => item.code == dataDictionary.code);
|
|
176
|
+
if (originalDataDictionary) {
|
|
177
|
+
originalDataDictionary.name = dataDictionary.name;
|
|
178
|
+
originalDataDictionary.description = dataDictionary.description;
|
|
179
|
+
originalDataDictionary.entries = dataDictionary.entries;
|
|
180
|
+
} else {
|
|
181
|
+
this.#applicationConfig.dataDictionaries.push(dataDictionary);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (routes) {
|
|
186
|
+
for (const route of routes) {
|
|
187
|
+
const originalRoute = find(this.#applicationConfig.routes, (item) => item.code == route.code);
|
|
188
|
+
if (originalRoute) {
|
|
189
|
+
originalRoute.name = route.name;
|
|
190
|
+
originalRoute.actions = route.actions;
|
|
191
|
+
} else {
|
|
192
|
+
this.#applicationConfig.routes.push(route);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
appendModelProperties(modelSingularCode: string, properties: RpdDataModelProperty[]) {
|
|
199
|
+
const originalModel = find(this.#applicationConfig.models, (item) => item.singularCode == modelSingularCode);
|
|
200
|
+
if (!originalModel) {
|
|
201
|
+
throw new Error(`Cannot append model properties. Model '${modelSingularCode}' was not found.`);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const originalProperties = originalModel.properties;
|
|
205
|
+
for (const property of properties) {
|
|
206
|
+
const originalProperty = find(originalProperties, (item) => item.code == property.code);
|
|
207
|
+
if (originalProperty) {
|
|
208
|
+
originalProperty.name = property.name;
|
|
209
|
+
} else {
|
|
210
|
+
originalProperties.push(property);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
registerActionHandler(plugin: RapidPlugin, options: IPluginActionHandler) {
|
|
216
|
+
const handler = bind(options.handler, null, plugin);
|
|
217
|
+
this.#actionHandlersMapByCode.set(options.code, handler);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
getActionHandlerByCode(code: string) {
|
|
221
|
+
return this.#actionHandlersMapByCode.get(code);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
registerMiddleware(middleware: any) {
|
|
225
|
+
this.#middlewares.push(middleware);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
getDataAccessor<T = any>(options: GetDataAccessorOptions): IRpdDataAccessor<T> {
|
|
229
|
+
const { namespace, singularCode } = options;
|
|
230
|
+
|
|
231
|
+
let dataAccessor = this.#cachedDataAccessors.get(singularCode);
|
|
232
|
+
if (dataAccessor) {
|
|
233
|
+
return dataAccessor;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const model = this.getModel(options);
|
|
237
|
+
if (!model) {
|
|
238
|
+
throw new Error(`Data model ${namespace}.${singularCode} not found.`);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
dataAccessor = new DataAccessor<T>(this, this.#databaseAccessor, {
|
|
242
|
+
model,
|
|
243
|
+
queryBuilder: this.queryBuilder as QueryBuilder,
|
|
244
|
+
});
|
|
245
|
+
this.#cachedDataAccessors.set(singularCode, dataAccessor);
|
|
246
|
+
return dataAccessor;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
getModel(options: GetModelOptions): RpdDataModel | undefined {
|
|
250
|
+
if (options.namespace) {
|
|
251
|
+
return this.#applicationConfig?.models.find((e) => e.namespace === options.namespace && e.singularCode === options.singularCode);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return this.#applicationConfig?.models.find((e) => e.singularCode === options.singularCode);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
getEntityManager<TEntity = any>(singularCode: string): EntityManager<TEntity> {
|
|
258
|
+
let entityManager = this.#cachedEntityManager.get(singularCode);
|
|
259
|
+
if (entityManager) {
|
|
260
|
+
return entityManager;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const dataAccessor = this.getDataAccessor({ singularCode });
|
|
264
|
+
entityManager = new EntityManager(this, dataAccessor);
|
|
265
|
+
this.#cachedEntityManager.set(singularCode, entityManager);
|
|
266
|
+
return entityManager;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
registerEventHandler<K extends keyof RpdServerEventTypes>(eventName: K, listener: (...args: RpdServerEventTypes[K]) => void) {
|
|
270
|
+
this.#eventManager.on(eventName, listener);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
registerEntityWatcher(entityWatcher: EntityWatcherType) {
|
|
274
|
+
this.#entityWatchers.push(entityWatcher);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
async emitEvent<TEventName extends keyof RpdServerEventTypes>(event: EmitServerEventOptions<TEventName>) {
|
|
278
|
+
const { eventName, payload, sender, routeContext: routerContext } = event;
|
|
279
|
+
this.#logger.debug(`Emitting '${eventName}' event.`, { eventName });
|
|
280
|
+
this.#logger.verbose(`Event payload: `, { payload });
|
|
281
|
+
await this.#eventManager.emit<TEventName>(eventName, sender, payload as any, routerContext);
|
|
282
|
+
|
|
283
|
+
// TODO: should move this logic into metaManager
|
|
284
|
+
// if (
|
|
285
|
+
// (eventName === "entity.create" || eventName === "entity.update" ||
|
|
286
|
+
// eventName === "entity.delete") &&
|
|
287
|
+
// payload.namespace === "meta"
|
|
288
|
+
// ) {
|
|
289
|
+
// await this.configureApplication();
|
|
290
|
+
// }
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
registerService(name: string, service: any) {
|
|
294
|
+
this.#services.set(name, service);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
getService<TService>(name: string): TService {
|
|
298
|
+
return this.#services.get(name);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
async start() {
|
|
302
|
+
this.#logger.info("Starting rapid server...");
|
|
303
|
+
const pluginManager = this.#pluginManager;
|
|
304
|
+
await pluginManager.loadPlugins(this.#plugins);
|
|
305
|
+
|
|
306
|
+
await pluginManager.initPlugins();
|
|
307
|
+
|
|
308
|
+
await pluginManager.registerMiddlewares();
|
|
309
|
+
await pluginManager.registerActionHandlers();
|
|
310
|
+
await pluginManager.registerEventHandlers();
|
|
311
|
+
await pluginManager.registerMessageHandlers();
|
|
312
|
+
await pluginManager.registerTaskProcessors();
|
|
313
|
+
|
|
314
|
+
this.#entityWatchers = this.#entityWatchers.concat(this.#appEntityWatchers);
|
|
315
|
+
for (const entityWatcher of this.#entityWatchers) {
|
|
316
|
+
if (entityWatcher.eventName === "entity.beforeCreate") {
|
|
317
|
+
this.#entityBeforeCreateEventEmitters.on(entityWatcher.modelSingularCode, entityWatcher.handler);
|
|
318
|
+
} else if (entityWatcher.eventName === "entity.create") {
|
|
319
|
+
this.#entityCreateEventEmitters.on(entityWatcher.modelSingularCode, entityWatcher.handler);
|
|
320
|
+
} else if (entityWatcher.eventName === "entity.beforeUpdate") {
|
|
321
|
+
this.#entityBeforeUpdateEventEmitters.on(entityWatcher.modelSingularCode, entityWatcher.handler);
|
|
322
|
+
} else if (entityWatcher.eventName === "entity.update") {
|
|
323
|
+
this.#entityUpdateEventEmitters.on(entityWatcher.modelSingularCode, entityWatcher.handler);
|
|
324
|
+
} else if (entityWatcher.eventName === "entity.beforeDelete") {
|
|
325
|
+
this.#entityBeforeDeleteEventEmitters.on(entityWatcher.modelSingularCode, entityWatcher.handler);
|
|
326
|
+
} else if (entityWatcher.eventName === "entity.delete") {
|
|
327
|
+
this.#entityDeleteEventEmitters.on(entityWatcher.modelSingularCode, entityWatcher.handler);
|
|
328
|
+
} else if (entityWatcher.eventName === "entity.addRelations") {
|
|
329
|
+
this.#entityAddRelationsEventEmitters.on(entityWatcher.modelSingularCode, entityWatcher.handler);
|
|
330
|
+
} else if (entityWatcher.eventName === "entity.removeRelations") {
|
|
331
|
+
this.#entityRemoveRelationsEventEmitters.on(entityWatcher.modelSingularCode, entityWatcher.handler);
|
|
332
|
+
} else if (entityWatcher.eventName === "entity.beforeResponse") {
|
|
333
|
+
this.#entityBeforeResponseEventEmitters.on(entityWatcher.modelSingularCode, entityWatcher.handler);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
await this.configureApplication();
|
|
338
|
+
|
|
339
|
+
this.#logger.info(`Rapid server ready.`);
|
|
340
|
+
await pluginManager.onApplicationReady(this.#applicationConfig);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
async configureApplication() {
|
|
344
|
+
this.#applicationConfig = cloneDeep(this.#bootstrapApplicationConfig) as RpdApplicationConfig;
|
|
345
|
+
|
|
346
|
+
const pluginManager = this.#pluginManager;
|
|
347
|
+
await pluginManager.onLoadingApplication(this.#applicationConfig);
|
|
348
|
+
await pluginManager.configureModels(this.#applicationConfig);
|
|
349
|
+
await pluginManager.configureModelProperties(this.#applicationConfig);
|
|
350
|
+
await pluginManager.configureServices(this.#applicationConfig);
|
|
351
|
+
await pluginManager.configureRoutes(this.#applicationConfig);
|
|
352
|
+
|
|
353
|
+
// TODO: check application configuration.
|
|
354
|
+
|
|
355
|
+
await pluginManager.onApplicationLoaded(this.#applicationConfig);
|
|
356
|
+
|
|
357
|
+
this.#buildedRoutes = await buildRoutes(this, this.#applicationConfig);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
registerFacilityFactory(factory: FacilityFactory) {
|
|
361
|
+
this.#facilityFactories.set(factory.name, factory);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
async getFacility<TFacility = any, TOptions = any>(name: string, options?: TOptions, nullIfUnknownFacility?: boolean): Promise<TFacility> {
|
|
365
|
+
const factory = this.#facilityFactories.get(name);
|
|
366
|
+
if (!factory) {
|
|
367
|
+
if (nullIfUnknownFacility) {
|
|
368
|
+
return null;
|
|
369
|
+
} else {
|
|
370
|
+
throw new Error(`Failed to get facility. Unknown facility name: ${name}`);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
return await factory.createFacility(this, options);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
async queryDatabaseObject(sql: string, params?: unknown[] | Record<string, unknown>, client?: IDatabaseClient): Promise<any[]> {
|
|
378
|
+
try {
|
|
379
|
+
return await this.#databaseAccessor.queryDatabaseObject(sql, params, client);
|
|
380
|
+
} catch (err) {
|
|
381
|
+
this.#logger.error("Failed to query database object.", { errorMessage: err.message, sql, params });
|
|
382
|
+
throw err;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
async tryQueryDatabaseObject(sql: string, params?: unknown[] | Record<string, unknown>, client?: IDatabaseClient): Promise<any[]> {
|
|
387
|
+
try {
|
|
388
|
+
return await this.queryDatabaseObject(sql, params, client);
|
|
389
|
+
} catch (err) {
|
|
390
|
+
this.#logger.error("Failed to query database object.", { errorMessage: err.message, sql, params });
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
return [];
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
get middlewares() {
|
|
397
|
+
return this.#middlewares;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
async handleRequest(request: Request, next: Next) {
|
|
401
|
+
const rapidRequest = new RapidRequest(this, request);
|
|
402
|
+
await rapidRequest.parseBody();
|
|
403
|
+
const routeContext: RouteContext = new RouteContext(this, rapidRequest);
|
|
404
|
+
const { response } = routeContext;
|
|
405
|
+
|
|
406
|
+
try {
|
|
407
|
+
await this.#pluginManager.onPrepareRouteContext(routeContext);
|
|
408
|
+
await this.#buildedRoutes(routeContext, next);
|
|
409
|
+
} catch (ex) {
|
|
410
|
+
this.#logger.error("handle request error:", ex);
|
|
411
|
+
response.json(
|
|
412
|
+
{
|
|
413
|
+
error: {
|
|
414
|
+
message: ex.message || ex,
|
|
415
|
+
},
|
|
416
|
+
},
|
|
417
|
+
500,
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
if (!response.status && !response.body) {
|
|
422
|
+
response.json(
|
|
423
|
+
{
|
|
424
|
+
error: {
|
|
425
|
+
message: "No route handler was found to handle this request.",
|
|
426
|
+
},
|
|
427
|
+
},
|
|
428
|
+
404,
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
return response.getResponse();
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
async beforeRunRouteActions(handlerContext: ActionHandlerContext) {
|
|
435
|
+
await this.#pluginManager.beforeRunRouteActions(handlerContext);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
async beforeCreateEntity(model: RpdDataModel, options: CreateEntityOptions) {
|
|
439
|
+
await this.#pluginManager.beforeCreateEntity(model, options);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
async beforeUpdateEntity(model: RpdDataModel, options: UpdateEntityByIdOptions, currentEntity: any) {
|
|
443
|
+
await this.#pluginManager.beforeUpdateEntity(model, options, currentEntity);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
async #handleEntityEvent(eventName: keyof RpdServerEventTypes, sender: RapidPlugin, payload: RpdEntityCreateEventPayload, routerContext?: RouteContext) {
|
|
447
|
+
const { modelSingularCode, baseModelSingularCode } = payload;
|
|
448
|
+
const entityWatchHandlerContext: EntityWatchHandlerContext<typeof eventName> = {
|
|
449
|
+
server: this,
|
|
450
|
+
payload,
|
|
451
|
+
routerContext,
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
let emitter: EventManager<Record<string, [EntityWatchHandlerContext<any>]>>;
|
|
455
|
+
if (eventName === "entity.beforeCreate") {
|
|
456
|
+
emitter = this.#entityBeforeCreateEventEmitters;
|
|
457
|
+
} else if (eventName === "entity.create") {
|
|
458
|
+
emitter = this.#entityCreateEventEmitters;
|
|
459
|
+
} else if (eventName === "entity.beforeUpdate") {
|
|
460
|
+
emitter = this.#entityBeforeUpdateEventEmitters;
|
|
461
|
+
} else if (eventName === "entity.update") {
|
|
462
|
+
emitter = this.#entityUpdateEventEmitters;
|
|
463
|
+
} else if (eventName === "entity.beforeDelete") {
|
|
464
|
+
emitter = this.#entityBeforeDeleteEventEmitters;
|
|
465
|
+
} else if (eventName === "entity.delete") {
|
|
466
|
+
emitter = this.#entityDeleteEventEmitters;
|
|
467
|
+
} else if (eventName === "entity.addRelations") {
|
|
468
|
+
emitter = this.#entityAddRelationsEventEmitters;
|
|
469
|
+
} else if (eventName === "entity.removeRelations") {
|
|
470
|
+
emitter = this.#entityRemoveRelationsEventEmitters;
|
|
471
|
+
} else if (eventName === "entity.beforeResponse") {
|
|
472
|
+
emitter = this.#entityBeforeResponseEventEmitters;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
await emitter.emit(modelSingularCode, entityWatchHandlerContext);
|
|
476
|
+
if (baseModelSingularCode) {
|
|
477
|
+
await emitter.emit(baseModelSingularCode, entityWatchHandlerContext);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|