@ruiapp/rapid-core 0.1.8 → 0.1.9

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/dist/server.d.ts CHANGED
@@ -2,6 +2,7 @@ import { GetDataAccessorOptions, GetModelOptions, IDatabaseAccessor, IDatabaseCo
2
2
  import { ActionHandler, IPluginActionHandler } from "./core/actionHandler";
3
3
  import { IRpdServer, RapidPlugin } from "./core/server";
4
4
  import { Next } from "./core/routeContext";
5
+ import EntityManager from "./dataAccess/entityManager";
5
6
  export interface InitServerOptions {
6
7
  databaseAccessor: IDatabaseAccessor;
7
8
  databaseConfig: IDatabaseConfig;
@@ -22,6 +23,7 @@ export declare class RapidServer implements IRpdServer {
22
23
  registerMiddleware(middleware: any): void;
23
24
  getDataAccessor<T = any>(options: GetDataAccessorOptions): IRpdDataAccessor<T>;
24
25
  getModel(options: GetModelOptions): RpdDataModel | undefined;
26
+ getEntityManager(singularCode: string): EntityManager;
25
27
  registerEventHandler<K extends keyof RpdServerEventTypes>(eventName: K, listener: (...args: RpdServerEventTypes[K]) => void): this;
26
28
  emitEvent<K extends keyof RpdServerEventTypes>(eventName: K, sender: RapidPlugin, payload: RpdServerEventTypes[K][1]): Promise<void>;
27
29
  start(): Promise<void>;
package/dist/types.d.ts CHANGED
@@ -309,6 +309,9 @@ export interface FindEntityOrderByOptions {
309
309
  export interface CountEntityOptions {
310
310
  filters?: EntityFilterOptions[];
311
311
  }
312
+ export interface CountEntityResult {
313
+ count: number;
314
+ }
312
315
  export interface CreateEntityOptions {
313
316
  entity: any;
314
317
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ruiapp/rapid-core",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "keywords": [],
@@ -71,84 +71,77 @@ class PluginManager {
71
71
 
72
72
  /** 在加载应用前调用。 */
73
73
  async onLoadingApplication(
74
- server: IRpdServer,
75
74
  applicationConfig: RpdApplicationConfig,
76
75
  ) {
77
76
  for (const plugin of this.#plugins) {
78
77
  if (plugin.onLoadingApplication) {
79
- await plugin.onLoadingApplication(server, applicationConfig);
78
+ await plugin.onLoadingApplication(this.#server, applicationConfig);
80
79
  }
81
80
  }
82
81
  }
83
82
 
84
83
  /** 配置数据模型 */
85
84
  async configureModels(
86
- server: IRpdServer,
87
85
  applicationConfig: RpdApplicationConfig,
88
86
  ) {
89
87
  for (const plugin of this.#plugins) {
90
88
  if (plugin.configureModels) {
91
- await plugin.configureModels(server, applicationConfig);
89
+ await plugin.configureModels(this.#server, applicationConfig);
92
90
  }
93
91
  }
94
92
  }
95
93
 
96
94
  /** 配置模型属性 */
97
95
  async configureModelProperties(
98
- server: IRpdServer,
99
96
  applicationConfig: RpdApplicationConfig,
100
97
  ) {
101
98
  for (const plugin of this.#plugins) {
102
99
  if (plugin.configureModelProperties) {
103
- await plugin.configureModelProperties(server, applicationConfig);
100
+ await plugin.configureModelProperties(this.#server, applicationConfig);
104
101
  }
105
102
  }
106
103
  }
107
104
 
108
105
  /** 配置路由 */
109
106
  async configureRoutes(
110
- server: IRpdServer,
111
107
  applicationConfig: RpdApplicationConfig,
112
108
  ) {
113
109
  for (const plugin of this.#plugins) {
114
110
  if (plugin.configureRoutes) {
115
- await plugin.configureRoutes(server, applicationConfig);
111
+ await plugin.configureRoutes(this.#server, applicationConfig);
116
112
  }
117
113
  }
118
114
  }
119
115
 
120
116
  /** 在应用配置加载完成后调用。此时插件可以进行一些数据的初始化工作。 */
121
117
  async onApplicationLoaded(
122
- server: IRpdServer,
123
118
  applicationConfig: RpdApplicationConfig,
124
119
  ) {
125
120
  for (const plugin of this.#plugins) {
126
121
  if (plugin.onApplicationLoaded) {
127
- await plugin.onApplicationLoaded(server, applicationConfig);
122
+ await plugin.onApplicationLoaded(this.#server, applicationConfig);
128
123
  }
129
124
  }
130
125
  }
131
126
 
132
127
  /** 在应用准备完成后调用。此时服务器已经可以处理网络请求。 */
133
128
  async onApplicationReady(
134
- server: IRpdServer,
135
129
  applicationConfig: RpdApplicationConfig,
136
130
  ) {
137
131
  for (const plugin of this.#plugins) {
138
132
  if (plugin.onApplicationReady) {
139
- await plugin.onApplicationReady(server, applicationConfig);
133
+ await plugin.onApplicationReady(this.#server, applicationConfig);
140
134
  }
141
135
  }
142
136
  }
143
137
 
144
138
  /** 在接收到HTTP请求,准备路由上下文时调用。 */
145
139
  async onPrepareRouteContext(
146
- server: IRpdServer,
147
140
  routeContext: RouteContext,
148
141
  ) {
149
142
  for (const plugin of this.#plugins) {
150
143
  if (plugin.onPrepareRouteContext) {
151
- await plugin.onPrepareRouteContext(server, routeContext);
144
+ await plugin.onPrepareRouteContext(this.#server, routeContext);
152
145
  }
153
146
  }
154
147
  }
@@ -1,6 +1,7 @@
1
1
  import { GetDataAccessorOptions, GetModelOptions, IDatabaseConfig, IQueryBuilder, IRpdDataAccessor, RapidServerConfig, RpdApplicationConfig, RpdDataModel, RpdServerEventTypes } from "~/types";
2
2
  import { IPluginActionHandler, ActionHandler } from "./actionHandler";
3
3
  import { Next, RouteContext } from "./routeContext";
4
+ import EntityManager from "~/dataAccess/entityManager";
4
5
 
5
6
  export interface IRpdServer {
6
7
  config: RapidServerConfig;
@@ -23,6 +24,7 @@ export interface IRpdServer {
23
24
  getDataAccessor<T = any>(
24
25
  options: GetDataAccessorOptions,
25
26
  ): IRpdDataAccessor<T>;
27
+ getEntityManager<TEntity = any>(singularCode: string): EntityManager<TEntity>;
26
28
  getApplicationConfig(): RpdApplicationConfig;
27
29
  appendApplicationConfig(config: Partial<RpdApplicationConfig>);
28
30
  getModel(options: GetModelOptions): RpdDataModel | undefined;
@@ -1,5 +1,7 @@
1
1
  import * as _ from "lodash";
2
2
  import {
3
+ CountEntityOptions,
4
+ CountEntityResult,
3
5
  CreateEntityOptions,
4
6
  EntityFilterOperators,
5
7
  EntityFilterOptions,
@@ -29,7 +31,7 @@ function convertToDataAccessOrderBy(model: RpdDataModel, orderByList?: FindEntit
29
31
  })
30
32
  }
31
33
 
32
- export async function findEntities(
34
+ async function findEntities(
33
35
  server: IRpdServer,
34
36
  dataAccessor: IRpdDataAccessor,
35
37
  options: FindEntityOptions,
@@ -159,7 +161,7 @@ export async function findEntities(
159
161
  return entities.map(item => mapDbRowToEntity(model, item));
160
162
  }
161
163
 
162
- export async function findEntity(
164
+ async function findEntity(
163
165
  server: IRpdServer,
164
166
  dataAccessor: IRpdDataAccessor,
165
167
  options: FindEntityOptions,
@@ -396,7 +398,7 @@ function findOneRelatedEntitiesViaIdPropertyCode(
396
398
  return dataAccessor.find(findEntityOptions);
397
399
  }
398
400
 
399
- export async function createEntity(
401
+ async function createEntity(
400
402
  server: IRpdServer,
401
403
  dataAccessor: IRpdDataAccessor,
402
404
  options: CreateEntityOptions,
@@ -527,8 +529,7 @@ export async function createEntity(
527
529
  return newEntity;
528
530
  }
529
531
 
530
-
531
- export async function updateEntityById(
532
+ async function updateEntityById(
532
533
  server: IRpdServer,
533
534
  dataAccessor: IRpdDataAccessor,
534
535
  options: UpdateEntityByIdOptions,
@@ -648,4 +649,54 @@ export async function updateEntityById(
648
649
  }
649
650
 
650
651
  return updatedEntity;
651
- }
652
+ }
653
+
654
+ export default class EntityManager<TEntity=any> {
655
+ #server: IRpdServer;
656
+ #dataAccessor: IRpdDataAccessor;
657
+
658
+ constructor(server: IRpdServer, dataAccessor: IRpdDataAccessor) {
659
+ this.#server = server;
660
+ this.#dataAccessor = dataAccessor;
661
+ }
662
+
663
+ async findEntities(options: FindEntityOptions): Promise<TEntity[]> {
664
+ return await findEntities(this.#server, this.#dataAccessor, options);
665
+ }
666
+
667
+ async findEntity(options: FindEntityOptions): Promise<TEntity | null> {
668
+ return await findEntity(this.#server, this.#dataAccessor, options);
669
+ }
670
+
671
+ async findById(id: any): Promise<TEntity | null> {
672
+ return await this.findEntity({
673
+ filters: [
674
+ {
675
+ operator: "eq",
676
+ field: "id",
677
+ value: id,
678
+ }
679
+ ]
680
+ });
681
+ }
682
+
683
+ async createEntity(options: CreateEntityOptions): Promise<TEntity> {
684
+ return await createEntity(this.#server, this.#dataAccessor, options);
685
+ }
686
+
687
+ async updateEntityById(options: UpdateEntityByIdOptions): Promise<TEntity> {
688
+ return await updateEntityById(this.#server, this.#dataAccessor, options);
689
+ }
690
+
691
+ async count(options: CountEntityOptions): Promise<CountEntityResult> {
692
+ return await this.#dataAccessor.count(options);
693
+ }
694
+
695
+ async deleteById(id: any): Promise<void> {
696
+ return await this.#dataAccessor.deleteById(id);
697
+ }
698
+
699
+ getModel(): RpdDataModel {
700
+ return this.#dataAccessor.getModel();
701
+ }
702
+ }
@@ -2,9 +2,10 @@ import * as _ from "lodash";
2
2
  import { IRpdDataAccessor, RunEntityActionHandlerOptions } from "~/types";
3
3
  import { mergeInput } from "./inputHelper";
4
4
  import { ActionHandlerContext } from "~/core/actionHandler";
5
+ import EntityManager from "~/dataAccess/entityManager";
5
6
 
6
- type DataAccessHandler = (
7
- dataAccessor: IRpdDataAccessor,
7
+ type EntityActionHandler = (
8
+ entityManager: EntityManager,
8
9
  input: any,
9
10
  ) => Promise<any>;
10
11
 
@@ -12,7 +13,7 @@ export default async function runCollectionEntityActionHandler(
12
13
  ctx: ActionHandlerContext,
13
14
  options: RunEntityActionHandlerOptions,
14
15
  code: string,
15
- handleDataAccess: DataAccessHandler,
16
+ handleEntityAction: EntityActionHandler,
16
17
  ) {
17
18
  const { server, input } = ctx;
18
19
  const { defaultInput, fixedInput } = options;
@@ -24,8 +25,8 @@ export default async function runCollectionEntityActionHandler(
24
25
  console.debug(`fixedInput: ${JSON.stringify(fixedInput)}`);
25
26
  console.debug(`mergedInput: ${JSON.stringify(mergedInput)}`);
26
27
 
27
- const dataAccessor = server.getDataAccessor(options);
28
- const result = handleDataAccess(dataAccessor, mergedInput);
28
+ const entityManager = server.getEntityManager(options.singularCode);
29
+ const result = handleEntityAction(entityManager, mergedInput);
29
30
  if (result instanceof Promise) {
30
31
  ctx.output = await result;
31
32
  } else {
@@ -96,9 +96,13 @@ class AuthPlugin implements RapidPlugin {
96
96
  token = request.cookies[server.config.sessionCookieName];
97
97
  }
98
98
 
99
- const tokenPayload = verifyJwt(token, server.config.jwtKey);
100
- routeContext.state.userId = tokenPayload.aud as string;
101
- routeContext.state.userLogin = tokenPayload.act as string;
99
+ try {
100
+ const tokenPayload = verifyJwt(token, server.config.jwtKey);
101
+ routeContext.state.userId = tokenPayload.aud as string;
102
+ routeContext.state.userLogin = tokenPayload.act as string;
103
+ } catch (err) {
104
+ console.warn(err);
105
+ }
102
106
  }
103
107
  }
104
108
 
@@ -1,4 +1,3 @@
1
- import { findEntity } from "~/dataAccess/entityManager";
2
1
  import { ActionHandlerContext } from "~/core/actionHandler";
3
2
  import { RapidPlugin } from "~/core/server";
4
3
 
@@ -22,11 +21,8 @@ export async function handler(
22
21
  return;
23
22
  }
24
23
 
25
- const userDataAccessor = server.getDataAccessor({
26
- singularCode: "oc_user",
27
- });
28
-
29
- const user = await findEntity(server, userDataAccessor, {
24
+ const entityManager = server.getEntityManager("oc_user");
25
+ const user = await entityManager.findEntity({
30
26
  filters: [
31
27
  {
32
28
  operator: "eq",
@@ -15,9 +15,9 @@ export async function handler(
15
15
  ctx,
16
16
  options,
17
17
  code,
18
- (dataAccessor, input) => {
18
+ (entityManager, input) => {
19
19
  input.filters = removeFiltersWithNullValue(input.filters);
20
- return dataAccessor.count(input);
20
+ return entityManager.count(input);
21
21
  },
22
22
  );
23
23
  }
@@ -1,6 +1,5 @@
1
1
  import { RunEntityActionHandlerOptions } from "~/types";
2
2
  import { mergeInput } from "~/helpers/inputHelper";
3
- import { createEntity } from "~/dataAccess/entityManager";
4
3
  import { isArray } from "lodash";
5
4
  import { ActionHandlerContext } from "~/core/actionHandler";
6
5
  import { RapidPlugin } from "~/core/server";
@@ -35,8 +34,8 @@ export async function handler(
35
34
  mergedEntity.createdBy = userId;
36
35
  }
37
36
 
38
- const dataAccessor = server.getDataAccessor(options);
39
- const newEntity = await createEntity(server, dataAccessor, {
37
+ const entityManager = server.getEntityManager(options.singularCode);
38
+ const newEntity = await entityManager.createEntity({
40
39
  entity: mergedEntity,
41
40
  });
42
41
 
@@ -1,6 +1,5 @@
1
1
  import { RunEntityActionHandlerOptions } from "~/types";
2
2
  import { mergeInput } from "~/helpers/inputHelper";
3
- import { createEntity } from "~/dataAccess/entityManager";
4
3
  import { ActionHandlerContext } from "~/core/actionHandler";
5
4
  import { RapidPlugin } from "~/core/server";
6
5
 
@@ -26,8 +25,8 @@ export async function handler(
26
25
  input.createdBy = userId;
27
26
  }
28
27
 
29
- const dataAccessor = server.getDataAccessor(options);
30
- const output = await createEntity(server, dataAccessor, {
28
+ const entityManager = server.getEntityManager(options.singularCode);
29
+ const output = await entityManager.createEntity({
31
30
  entity: input,
32
31
  });
33
32
  ctx.output = output;
@@ -13,17 +13,17 @@ export async function handler(
13
13
  console.debug(`Running ${code} handler...`);
14
14
  const { server, input } = ctx;
15
15
 
16
- const dataAccessor = server.getDataAccessor(options);
16
+ const entityManager = server.getEntityManager(options.singularCode);
17
17
  const id = input.id;
18
- const row = await dataAccessor.findById(id);
18
+ const row = await entityManager.findById(id);
19
19
  if (!row) {
20
20
  ctx.status = 200;
21
21
  return;
22
22
  }
23
23
 
24
- await dataAccessor.deleteById(id);
24
+ await entityManager.deleteById(id);
25
25
 
26
- const entity = mapDbRowToEntity(dataAccessor.getModel(), row);
26
+ const entity = mapDbRowToEntity(entityManager.getModel(), row);
27
27
 
28
28
  server.emitEvent(
29
29
  "entity.delete",
@@ -1,7 +1,6 @@
1
1
  import * as _ from "lodash";
2
2
  import { FindEntityOptions, RunEntityActionHandlerOptions } from "~/types";
3
3
  import runCollectionEntityActionHandler from "~/helpers/runCollectionEntityActionHandler";
4
- import { findEntities } from "~/dataAccess/entityManager";
5
4
  import { removeFiltersWithNullValue } from "~/dataAccess/filterHelper";
6
5
  import { ActionHandlerContext } from "~/core/actionHandler";
7
6
  import { RapidPlugin } from "~/core/server";
@@ -17,9 +16,9 @@ export async function handler(
17
16
  ctx,
18
17
  options,
19
18
  code,
20
- async (dataAccessor, input: FindEntityOptions) => {
19
+ async (entityManager, input: FindEntityOptions) => {
21
20
  input.filters = removeFiltersWithNullValue(input.filters);
22
- const entities = await findEntities(ctx.server, dataAccessor, input);
21
+ const entities = await entityManager.findEntities(input);
23
22
  const result: {
24
23
  list: any;
25
24
  total?: any;
@@ -27,7 +26,7 @@ export async function handler(
27
26
 
28
27
  if (input.pagination && !input.pagination.withoutTotal) {
29
28
  // TOOD: impl count entities by using entity manager, because DataAccessor does not support 'exists' and 'notExists' filter.
30
- const countResult = await dataAccessor.count(input);
29
+ const countResult = await entityManager.count(input);
31
30
  result.total = countResult.count;
32
31
  }
33
32
  return result;
@@ -1,5 +1,4 @@
1
1
  import { RunEntityActionHandlerOptions } from "~/types";
2
- import { findEntity } from "~/dataAccess/entityManager";
3
2
  import { ActionHandlerContext } from "~/core/actionHandler";
4
3
  import { RapidPlugin } from "~/core/server";
5
4
 
@@ -14,18 +13,10 @@ export async function handler(
14
13
  const { server, input } = ctx;
15
14
  const { id } = input;
16
15
 
17
- const dataAccessor = server.getDataAccessor(options);
18
- const user = await findEntity(ctx.server, dataAccessor, {
19
- filters: [
20
- {
21
- operator: "eq",
22
- field: "id",
23
- value: id,
24
- }
25
- ],
26
- });
27
- if (!user) {
16
+ const entityManager = server.getEntityManager(options.singularCode);
17
+ const entity = await entityManager.findById(id);
18
+ if (!entity) {
28
19
  throw new Error(`${options.namespace}.${options.singularCode} with id "${id}" was not found.`);
29
20
  }
30
- ctx.output = user;
21
+ ctx.output = entity;
31
22
  }
@@ -1,7 +1,6 @@
1
1
  import { RunEntityActionHandlerOptions } from "~/types";
2
2
  import { getEntityPartChanges } from "~/helpers/entityHelpers";
3
3
  import { mergeInput } from "~/helpers/inputHelper";
4
- import { updateEntityById } from "~/dataAccess/entityManager";
5
4
  import { mapDbRowToEntity } from "~/dataAccess/entityMapper";
6
5
  import { ActionHandlerContext } from "~/core/actionHandler";
7
6
  import { RapidPlugin } from "~/core/server";
@@ -23,21 +22,21 @@ export async function handler(
23
22
  console.debug(`fixedInput: ${JSON.stringify(fixedInput)}`);
24
23
  console.debug(`mergedInput: ${JSON.stringify(mergedInput)}`);
25
24
 
26
- const dataAccessor = server.getDataAccessor(options);
25
+ const entityManager = server.getEntityManager(options.singularCode);
27
26
  const id = mergedInput.id;
28
- const row = await dataAccessor.findById(id);
27
+ const row = await entityManager.findById(id);
29
28
  if (!row) {
30
29
  throw new Error(`${options.namespace}.${options.singularCode} with id "${id}" was not found.`);
31
30
  }
32
31
 
33
- const entity = mapDbRowToEntity(dataAccessor.getModel(), row);
32
+ const entity = mapDbRowToEntity(entityManager.getModel(), row);
34
33
  const changes = getEntityPartChanges(entity, mergedInput);
35
34
  if (!changes) {
36
35
  ctx.output = entity;
37
36
  return;
38
37
  }
39
38
 
40
- const output = await updateEntityById(server, dataAccessor, { id, entity, changes });
39
+ const output = await entityManager.updateEntityById({ id, entity, changes });
41
40
  ctx.output = output;
42
41
 
43
42
  server.emitEvent(
@@ -3,7 +3,6 @@
3
3
  */
4
4
 
5
5
  import * as _ from "lodash";
6
- import { findEntities } from "~/dataAccess/entityManager";
7
6
  import {
8
7
  IQueryBuilder,
9
8
  QuoteTableOptions,
@@ -206,13 +205,10 @@ function listCollections(
206
205
  server: IRpdServer,
207
206
  applicationConfig: RpdApplicationConfig,
208
207
  ) {
209
- const dataAccessor = server.getDataAccessor({
210
- namespace: "meta",
211
- singularCode: "model",
212
- });
213
- const model = dataAccessor.getModel();
208
+ const entityManager = server.getEntityManager("model");
209
+ const model = entityManager.getModel();
214
210
 
215
- return findEntities(server, dataAccessor, {
211
+ return entityManager.findEntities({
216
212
  properties: model.properties.map((item) => item.code),
217
213
  });
218
214
  }
@@ -6,7 +6,6 @@ import {
6
6
  RpdApplicationConfig,
7
7
  } from "~/types";
8
8
  import { RpdServerPluginExtendingAbilities, RpdServerPluginConfigurableTargetOptions, RpdConfigurationItemOptions, IRpdServer, RapidPlugin } from "~/core/server";
9
- import { findEntities } from "../../dataAccess/entityManager";
10
9
  import * as httpProxy from "./actionHandlers/httpProxy";
11
10
 
12
11
 
@@ -65,12 +64,8 @@ class RouteManager implements RapidPlugin {
65
64
 
66
65
  async configureRoutes(server: IRpdServer, applicationConfig: RpdApplicationConfig): Promise<any> {
67
66
  try {
68
- const dataAccessor = server.getDataAccessor({
69
- namespace: "meta",
70
- singularCode: "route",
71
- });
72
-
73
- const routes = await findEntities(server, dataAccessor, {
67
+ const entityManager = server.getEntityManager("route");
68
+ const routes = await entityManager.findEntities({
74
69
  orderBy: [
75
70
  { field: "endpoint" },
76
71
  ],
@@ -12,7 +12,6 @@ import {
12
12
  } from "~/types";
13
13
  import { RpdServerPluginExtendingAbilities, RpdServerPluginConfigurableTargetOptions, RpdConfigurationItemOptions, IRpdServer, RapidPlugin } from "~/core/server";
14
14
  import { fetchWithTimeout } from "~/utilities/httpUtility";
15
- import { findEntities } from "~/dataAccess/entityManager";
16
15
  import pluginConfig from "./pluginConfig";
17
16
 
18
17
 
@@ -31,12 +30,8 @@ export interface Webhook {
31
30
  function listWebhooks(
32
31
  server: IRpdServer,
33
32
  ) {
34
- const dataAccessor = server.getDataAccessor({
35
- namespace: "sys",
36
- singularCode: "webhook",
37
- });
38
-
39
- return findEntities(server, dataAccessor, {
33
+ const entityManager = server.getEntityManager("webhook");
34
+ return entityManager.findEntities({
40
35
  filters: [
41
36
  {
42
37
  field: "enabled",
package/src/server.ts CHANGED
@@ -22,6 +22,7 @@ import { buildRoutes } from "./core/routesBuilder";
22
22
  import { Next, RouteContext } from "./core/routeContext";
23
23
  import { RapidRequest } from "./core/request";
24
24
  import bootstrapApplicationConfig from "./bootstrapApplicationConfig";
25
+ import EntityManager from "./dataAccess/entityManager";
25
26
 
26
27
  export interface InitServerOptions {
27
28
  databaseAccessor: IDatabaseAccessor;
@@ -40,6 +41,8 @@ export class RapidServer implements IRpdServer {
40
41
  #applicationConfig: RpdApplicationConfig;
41
42
  #actionHandlersMapByCode: Map<string, ActionHandler>;
42
43
  #databaseAccessor: IDatabaseAccessor;
44
+ #cachedDataAccessors: Map<string, DataAccessor>;
45
+ #cachedEntityManager: Map<string, EntityManager>;
43
46
  queryBuilder: IQueryBuilder;
44
47
  config: RapidServerConfig;
45
48
  databaseConfig: IDatabaseConfig;
@@ -54,6 +57,8 @@ export class RapidServer implements IRpdServer {
54
57
  this.#applicationConfig = {} as RpdApplicationConfig;
55
58
  this.#actionHandlersMapByCode = new Map();
56
59
  this.#databaseAccessor = options.databaseAccessor;
60
+ this.#cachedDataAccessors = new Map();
61
+ this.#cachedEntityManager = new Map();
57
62
 
58
63
  this.queryBuilder = new QueryBuilder({
59
64
  dbDefaultSchema: options.databaseConfig.dbDefaultSchema,
@@ -123,16 +128,22 @@ export class RapidServer implements IRpdServer {
123
128
  options: GetDataAccessorOptions,
124
129
  ): IRpdDataAccessor<T> {
125
130
  const { namespace, singularCode } = options;
126
- // TODO: Should reuse the and DataAccessor instance
131
+
132
+ let dataAccessor = this.#cachedDataAccessors.get(singularCode);
133
+ if (dataAccessor) {
134
+ return dataAccessor;
135
+ }
136
+
127
137
  const model = this.getModel(options);
128
138
  if (!model) {
129
139
  throw new Error(`Data model ${namespace}.${singularCode} not found.`);
130
140
  }
131
141
 
132
- const dataAccessor = new DataAccessor<T>(this.#databaseAccessor, {
142
+ dataAccessor = new DataAccessor<T>(this.#databaseAccessor, {
133
143
  model,
134
144
  queryBuilder: this.queryBuilder as QueryBuilder,
135
145
  });
146
+ this.#cachedDataAccessors.set(singularCode, dataAccessor);
136
147
  return dataAccessor;
137
148
  }
138
149
 
@@ -144,6 +155,18 @@ export class RapidServer implements IRpdServer {
144
155
  return this.#applicationConfig?.models.find((e) => e.singularCode === options.singularCode);
145
156
  }
146
157
 
158
+ getEntityManager<TEntity = any>(singularCode: string): EntityManager<TEntity> {
159
+ let entityManager = this.#cachedEntityManager.get(singularCode);
160
+ if (entityManager) {
161
+ return entityManager;
162
+ }
163
+
164
+ const dataAccessor = this.getDataAccessor({ singularCode });
165
+ entityManager = new EntityManager(this, dataAccessor);
166
+ this.#cachedEntityManager.set(singularCode, entityManager);
167
+ return entityManager;
168
+ }
169
+
147
170
  registerEventHandler<K extends keyof RpdServerEventTypes>(
148
171
  eventName: K,
149
172
  listener: (...args: RpdServerEventTypes[K]) => void,
@@ -186,7 +209,7 @@ export class RapidServer implements IRpdServer {
186
209
  await this.configureApplication();
187
210
 
188
211
  console.log(`Application ready.`);
189
- await pluginManager.onApplicationReady(this, this.#applicationConfig);
212
+ await pluginManager.onApplicationReady(this.#applicationConfig);
190
213
  }
191
214
 
192
215
  async configureApplication() {
@@ -196,14 +219,14 @@ export class RapidServer implements IRpdServer {
196
219
  ) as RpdApplicationConfig;
197
220
 
198
221
  const pluginManager = this.#pluginManager;
199
- await pluginManager.onLoadingApplication(this, this.#applicationConfig);
200
- await pluginManager.configureModels(this, this.#applicationConfig);
201
- await pluginManager.configureModelProperties(this, this.#applicationConfig);
202
- await pluginManager.configureRoutes(this, this.#applicationConfig);
222
+ await pluginManager.onLoadingApplication(this.#applicationConfig);
223
+ await pluginManager.configureModels(this.#applicationConfig);
224
+ await pluginManager.configureModelProperties(this.#applicationConfig);
225
+ await pluginManager.configureRoutes(this.#applicationConfig);
203
226
 
204
227
  // TODO: check application configuration.
205
228
 
206
- await pluginManager.onApplicationLoaded(this, this.#applicationConfig);
229
+ await pluginManager.onApplicationLoaded(this.#applicationConfig);
207
230
 
208
231
  this.#buildedRoutes = await buildRoutes(this, this.#applicationConfig);
209
232
  }
@@ -230,6 +253,7 @@ export class RapidServer implements IRpdServer {
230
253
  const rapidRequest = new RapidRequest(request);
231
254
  await rapidRequest.parseBody();
232
255
  const routeContext = new RouteContext(rapidRequest);
256
+ this.#pluginManager.onPrepareRouteContext(routeContext);
233
257
 
234
258
  await this.#buildedRoutes(routeContext, next);
235
259
  return routeContext.response.getResponse();
package/src/types.ts CHANGED
@@ -416,6 +416,10 @@ export interface CountEntityOptions {
416
416
  filters?: EntityFilterOptions[];
417
417
  }
418
418
 
419
+ export interface CountEntityResult {
420
+ count: number;
421
+ }
422
+
419
423
  export interface CreateEntityOptions {
420
424
  entity: any;
421
425
  }