@ruiapp/rapid-core 0.3.1 → 0.4.0

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.
Files changed (50) hide show
  1. package/dist/core/routeContext.d.ts +9 -0
  2. package/dist/core/server.d.ts +2 -1
  3. package/dist/dataAccess/dataAccessor.d.ts +8 -8
  4. package/dist/helpers/runCollectionEntityActionHandler.d.ts +1 -1
  5. package/dist/index.js +288 -202
  6. package/dist/plugins/dataManage/actionHandlers/deleteCollectionEntities.d.ts +1 -0
  7. package/dist/plugins/sequence/SequenceService.d.ts +3 -2
  8. package/dist/plugins/sequence/segments/autoIncrement.d.ts +2 -1
  9. package/dist/plugins/sequence/segments/dayOfMonth.d.ts +2 -1
  10. package/dist/plugins/sequence/segments/literal.d.ts +2 -1
  11. package/dist/plugins/sequence/segments/month.d.ts +2 -1
  12. package/dist/plugins/sequence/segments/parameter.d.ts +2 -1
  13. package/dist/plugins/sequence/segments/year.d.ts +2 -1
  14. package/dist/server.d.ts +1 -0
  15. package/dist/types.d.ts +13 -8
  16. package/package.json +1 -1
  17. package/src/core/routeContext.ts +53 -0
  18. package/src/core/server.ts +2 -0
  19. package/src/dataAccess/dataAccessor.ts +15 -15
  20. package/src/dataAccess/entityManager.ts +66 -50
  21. package/src/helpers/runCollectionEntityActionHandler.ts +37 -7
  22. package/src/plugins/auth/actionHandlers/changePassword.ts +22 -15
  23. package/src/plugins/auth/actionHandlers/createSession.ts +14 -11
  24. package/src/plugins/auth/actionHandlers/resetPassword.ts +21 -14
  25. package/src/plugins/dataManage/actionHandlers/addEntityRelations.ts +7 -12
  26. package/src/plugins/dataManage/actionHandlers/countCollectionEntities.ts +3 -2
  27. package/src/plugins/dataManage/actionHandlers/createCollectionEntitiesBatch.ts +52 -13
  28. package/src/plugins/dataManage/actionHandlers/createCollectionEntity.ts +12 -16
  29. package/src/plugins/dataManage/actionHandlers/deleteCollectionEntities.ts +32 -25
  30. package/src/plugins/dataManage/actionHandlers/deleteCollectionEntityById.ts +12 -14
  31. package/src/plugins/dataManage/actionHandlers/findCollectionEntities.ts +3 -2
  32. package/src/plugins/dataManage/actionHandlers/findCollectionEntityById.ts +12 -12
  33. package/src/plugins/dataManage/actionHandlers/removeEntityRelations.ts +8 -13
  34. package/src/plugins/dataManage/actionHandlers/updateCollectionEntityById.ts +26 -29
  35. package/src/plugins/fileManage/actionHandlers/downloadDocument.ts +6 -6
  36. package/src/plugins/fileManage/actionHandlers/downloadFile.ts +3 -3
  37. package/src/plugins/metaManage/MetaManagePlugin.ts +3 -2
  38. package/src/plugins/sequence/SequencePlugin.ts +29 -19
  39. package/src/plugins/sequence/SequenceService.ts +25 -14
  40. package/src/plugins/sequence/actionHandlers/generateSn.ts +3 -3
  41. package/src/plugins/sequence/segments/autoIncrement.ts +36 -24
  42. package/src/plugins/sequence/segments/dayOfMonth.ts +2 -0
  43. package/src/plugins/sequence/segments/literal.ts +2 -0
  44. package/src/plugins/sequence/segments/month.ts +2 -0
  45. package/src/plugins/sequence/segments/parameter.ts +2 -0
  46. package/src/plugins/sequence/segments/year.ts +2 -0
  47. package/src/plugins/stateMachine/StateMachinePlugin.ts +26 -16
  48. package/src/plugins/stateMachine/actionHandlers/sendStateMachineEvent.ts +14 -11
  49. package/src/server.ts +4 -0
  50. package/src/types.ts +14 -8
@@ -3,6 +3,7 @@ import { ActionHandlerContext } from "../../../core/actionHandler";
3
3
  import { RapidPlugin } from "../../../core/server";
4
4
  export interface DeleteCollectionEntitiesInput {
5
5
  filters: FindEntityOptions["filters"];
6
+ noTransaction?: boolean;
6
7
  }
7
8
  export declare const code = "deleteCollectionEntities";
8
9
  export declare function handler(plugin: RapidPlugin, ctx: ActionHandlerContext, options: RunEntityActionHandlerOptions): Promise<void>;
@@ -1,5 +1,6 @@
1
1
  import { IRpdServer } from "../../core/server";
2
2
  import { SequenceSegmentConfig } from "./SequencePluginTypes";
3
+ import { RouteContext } from "../../core/routeContext";
3
4
  export interface GenerateSequenceNumbersInput {
4
5
  ruleCode: string;
5
6
  parameters: Record<string, string>;
@@ -10,10 +11,10 @@ export interface GenerateSequenceNumbersOutput {
10
11
  }
11
12
  export interface SegmentResolver {
12
13
  segmentType: string;
13
- resolveSegmentValue(server: IRpdServer, ruleCode: string, config: SequenceSegmentConfig, input: GenerateSequenceNumbersInput): Promise<string>;
14
+ resolveSegmentValue(routeContext: RouteContext, server: IRpdServer, ruleCode: string, config: SequenceSegmentConfig, input: GenerateSequenceNumbersInput): Promise<string>;
14
15
  }
15
16
  export default class SequenceService {
16
17
  #private;
17
18
  constructor(server: IRpdServer);
18
- generateSn(server: IRpdServer, input: GenerateSequenceNumbersInput): Promise<string[]>;
19
+ generateSn(routeContext: RouteContext | null, server: IRpdServer, input: GenerateSequenceNumbersInput): Promise<string[]>;
19
20
  }
@@ -1,5 +1,6 @@
1
1
  import { GenerateSequenceNumbersInput } from "../SequenceService";
2
2
  import { IRpdServer } from "../../../core/server";
3
3
  import { SequenceAutoIncrementSegmentConfig } from "../SequencePluginTypes";
4
+ import { RouteContext } from "../../../core/routeContext";
4
5
  export declare const segmentType = "autoIncrement";
5
- export declare function resolveSegmentValue(server: IRpdServer, ruleCode: string, config: SequenceAutoIncrementSegmentConfig, input: GenerateSequenceNumbersInput): Promise<string>;
6
+ export declare function resolveSegmentValue(routeContext: RouteContext, server: IRpdServer, ruleCode: string, config: SequenceAutoIncrementSegmentConfig, input: GenerateSequenceNumbersInput): Promise<string>;
@@ -1,5 +1,6 @@
1
+ import { RouteContext } from "../../../core/routeContext";
1
2
  import { SequenceDayOfMonthSegmentConfig } from "../SequencePluginTypes";
2
3
  import { GenerateSequenceNumbersInput } from "../SequenceService";
3
4
  import { IRpdServer } from "../../../core/server";
4
5
  export declare const segmentType = "dayOfMonth";
5
- export declare function resolveSegmentValue(server: IRpdServer, ruleCode: string, config: SequenceDayOfMonthSegmentConfig, input: GenerateSequenceNumbersInput): Promise<string>;
6
+ export declare function resolveSegmentValue(routeContext: RouteContext, server: IRpdServer, ruleCode: string, config: SequenceDayOfMonthSegmentConfig, input: GenerateSequenceNumbersInput): Promise<string>;
@@ -1,5 +1,6 @@
1
+ import { RouteContext } from "../../../core/routeContext";
1
2
  import { SequenceLiteralSegmentConfig } from "../SequencePluginTypes";
2
3
  import { GenerateSequenceNumbersInput } from "../SequenceService";
3
4
  import { IRpdServer } from "../../../core/server";
4
5
  export declare const segmentType = "literal";
5
- export declare function resolveSegmentValue(server: IRpdServer, ruleCode: string, config: SequenceLiteralSegmentConfig, input: GenerateSequenceNumbersInput): Promise<string>;
6
+ export declare function resolveSegmentValue(routeContext: RouteContext, server: IRpdServer, ruleCode: string, config: SequenceLiteralSegmentConfig, input: GenerateSequenceNumbersInput): Promise<string>;
@@ -1,5 +1,6 @@
1
+ import { RouteContext } from "../../../core/routeContext";
1
2
  import { SequenceMonthSegmentConfig } from "../SequencePluginTypes";
2
3
  import { GenerateSequenceNumbersInput } from "../SequenceService";
3
4
  import { IRpdServer } from "../../../core/server";
4
5
  export declare const segmentType = "month";
5
- export declare function resolveSegmentValue(server: IRpdServer, ruleCode: string, config: SequenceMonthSegmentConfig, input: GenerateSequenceNumbersInput): Promise<string>;
6
+ export declare function resolveSegmentValue(routeContext: RouteContext, server: IRpdServer, ruleCode: string, config: SequenceMonthSegmentConfig, input: GenerateSequenceNumbersInput): Promise<string>;
@@ -1,5 +1,6 @@
1
+ import { RouteContext } from "../../../core/routeContext";
1
2
  import { SequenceParameterSegmentConfig } from "../SequencePluginTypes";
2
3
  import { GenerateSequenceNumbersInput } from "../SequenceService";
3
4
  import { IRpdServer } from "../../../core/server";
4
5
  export declare const segmentType = "parameter";
5
- export declare function resolveSegmentValue(server: IRpdServer, ruleCode: string, config: SequenceParameterSegmentConfig, input: GenerateSequenceNumbersInput): Promise<string>;
6
+ export declare function resolveSegmentValue(routeContext: RouteContext, server: IRpdServer, ruleCode: string, config: SequenceParameterSegmentConfig, input: GenerateSequenceNumbersInput): Promise<string>;
@@ -1,5 +1,6 @@
1
+ import { RouteContext } from "../../../core/routeContext";
1
2
  import { SequenceYearSegmentConfig } from "../SequencePluginTypes";
2
3
  import { GenerateSequenceNumbersInput } from "../SequenceService";
3
4
  import { IRpdServer } from "../../../core/server";
4
5
  export declare const segmentType = "year";
5
- export declare function resolveSegmentValue(server: IRpdServer, ruleCode: string, config: SequenceYearSegmentConfig, input: GenerateSequenceNumbersInput): Promise<string>;
6
+ export declare function resolveSegmentValue(routeContext: RouteContext, server: IRpdServer, ruleCode: string, config: SequenceYearSegmentConfig, input: GenerateSequenceNumbersInput): Promise<string>;
package/dist/server.d.ts CHANGED
@@ -23,6 +23,7 @@ export declare class RapidServer implements IRpdServer {
23
23
  constructor(options: InitServerOptions);
24
24
  getLogger(): Logger;
25
25
  getApplicationConfig(): RpdApplicationConfig;
26
+ getDatabaseAccessor(): IDatabaseAccessor;
26
27
  appendApplicationConfig(config: Partial<RpdApplicationConfig>): void;
27
28
  appendModelProperties(modelSingularCode: string, properties: RpdDataModelProperty[]): void;
28
29
  registerActionHandler(plugin: RapidPlugin, options: IPluginActionHandler): void;
package/dist/types.d.ts CHANGED
@@ -20,8 +20,13 @@ export type DatabaseQuery = {
20
20
  command: string;
21
21
  params?: unknown[] | Record<string, unknown>;
22
22
  };
23
+ export interface IDatabaseClient {
24
+ release(): any;
25
+ query(sql: any, params?: any): Promise<any>;
26
+ }
23
27
  export interface IDatabaseAccessor {
24
- queryDatabaseObject: (sql: string, params?: unknown[] | Record<string, unknown>) => Promise<any[]>;
28
+ getClient(): Promise<IDatabaseClient>;
29
+ queryDatabaseObject: (sql: string, params?: unknown[] | Record<string, unknown>, client?: IDatabaseClient) => Promise<any[]>;
25
30
  }
26
31
  export interface RunEntityActionHandlerOptions {
27
32
  /** 模型所在的命名空间 */
@@ -380,13 +385,13 @@ export interface RpdRouteActionConfig {
380
385
  }
381
386
  export interface IRpdDataAccessor<T = any> {
382
387
  getModel(): RpdDataModel;
383
- create(entity: any): Promise<any>;
384
- updateById(id: any, entity: any): Promise<any>;
385
- find(options: FindRowOptions): Promise<T[]>;
386
- findOne(options: FindRowOptions): Promise<T | null>;
387
- findById(id: any): Promise<T | null>;
388
- count(options: CountRowOptions): Promise<number>;
389
- deleteById(id: any): Promise<void>;
388
+ create(entity: any, databaseClient: IDatabaseClient | null): Promise<any>;
389
+ updateById(id: any, entity: any, databaseClient: IDatabaseClient | null): Promise<any>;
390
+ find(options: FindRowOptions, databaseClient: IDatabaseClient | null): Promise<T[]>;
391
+ findOne(options: FindRowOptions, databaseClient: IDatabaseClient | null): Promise<T | null>;
392
+ findById(id: any, databaseClient: IDatabaseClient | null): Promise<T | null>;
393
+ count(options: CountRowOptions, databaseClient: IDatabaseClient | null): Promise<number>;
394
+ deleteById(id: any, databaseClient: IDatabaseClient | null): Promise<void>;
390
395
  }
391
396
  export type EntityFilterRelationalOperators = "eq" | "ne" | "lt" | "lte" | "gt" | "gte" | "contains" | "notContains" | "containsCS" | "notContainsCS" | "startsWith" | "notStartsWith" | "endsWith" | "notEndsWith";
392
397
  export type EntityFilterArrayOperators = "arrayContains" | "arrayOverlap";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ruiapp/rapid-core",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -4,23 +4,32 @@ import { RapidResponse } from "./response";
4
4
  import { HttpStatus, ResponseData } from "./http-types";
5
5
  import { IRpdServer } from "./server";
6
6
  import { Logger } from "~/facilities/log/LogFacility";
7
+ import { IDatabaseAccessor, IDatabaseClient } from "~/types";
7
8
 
8
9
  export type Next = () => Promise<void>;
9
10
 
11
+ // TODO: should divide to RequestContext and OperationContext
12
+
10
13
  export class RouteContext {
11
14
  readonly request: RapidRequest;
12
15
  readonly response: RapidResponse;
13
16
  readonly state: Record<string, any>;
17
+ readonly databaseAccessor: IDatabaseAccessor;
14
18
  method: string;
15
19
  path: string;
16
20
  params: Record<string, string>;
17
21
  routeConfig: any;
22
+ #server: IRpdServer;
23
+ #dbTransactionClient: IDatabaseClient | null;
18
24
 
19
25
  static newSystemOperationContext(server: IRpdServer) {
20
26
  return new RouteContext(server);
21
27
  }
22
28
 
23
29
  constructor(server: IRpdServer, request?: RapidRequest) {
30
+ this.#server = server;
31
+ this.#dbTransactionClient = null;
32
+ this.databaseAccessor = server.getDatabaseAccessor();
24
33
  this.request = request;
25
34
  this.state = {};
26
35
  this.response = new RapidResponse();
@@ -32,6 +41,20 @@ export class RouteContext {
32
41
  }
33
42
  }
34
43
 
44
+ clone(): RouteContext {
45
+ const clonedContext = new RouteContext(this.#server);
46
+ clonedContext.method = this.method;
47
+ clonedContext.path = this.path;
48
+ clonedContext.params = this.params;
49
+ clonedContext.setState(this.state);
50
+
51
+ return clonedContext;
52
+ }
53
+
54
+ setState(state: Record<string, any>) {
55
+ Object.assign(this.state, state);
56
+ }
57
+
35
58
  // `koa-tree-router` uses this method to set headers
36
59
  set(headerName: string, headerValue: string) {
37
60
  this.response.headers.set(headerName, headerValue);
@@ -44,4 +67,34 @@ export class RouteContext {
44
67
  redirect(url: string, status?: HttpStatus) {
45
68
  this.response.redirect(url, status);
46
69
  }
70
+
71
+ getDbTransactionClient(): IDatabaseClient | null {
72
+ return this.#dbTransactionClient;
73
+ }
74
+
75
+ async beginDbTransaction(): Promise<IDatabaseClient> {
76
+ let dbClient = this.#dbTransactionClient;
77
+ if (dbClient) {
78
+ throw new Error("Database transaction has been started. You can not start a transaction more than once in a request context.");
79
+ }
80
+
81
+ dbClient = await this.databaseAccessor.getClient();
82
+ await this.databaseAccessor.queryDatabaseObject("BEGIN", [], dbClient);
83
+ this.#dbTransactionClient = dbClient;
84
+ return dbClient;
85
+ }
86
+
87
+ async commitDbTransaction(): Promise<void> {
88
+ if (!this.#dbTransactionClient) {
89
+ throw new Error("Database transaction has not been started. You should call beginDbTransaction() first.");
90
+ }
91
+ await this.databaseAccessor.queryDatabaseObject("COMMIT", [], this.#dbTransactionClient);
92
+ }
93
+
94
+ async rollbackDbTransaction(): Promise<void> {
95
+ if (!this.#dbTransactionClient) {
96
+ throw new Error("Database transaction has not been started. You should call beginDbTransaction() first.");
97
+ }
98
+ await this.databaseAccessor.queryDatabaseObject("ROLLBACK", [], this.#dbTransactionClient);
99
+ }
47
100
  }
@@ -4,6 +4,7 @@ import {
4
4
  EntityWatcherType,
5
5
  GetDataAccessorOptions,
6
6
  GetModelOptions,
7
+ IDatabaseAccessor,
7
8
  IDatabaseConfig,
8
9
  IQueryBuilder,
9
10
  IRpdDataAccessor,
@@ -30,6 +31,7 @@ export interface IRpdServer {
30
31
 
31
32
  getFacility<TFacility = any>(name: string, options?: any): Promise<TFacility>;
32
33
 
34
+ getDatabaseAccessor(): IDatabaseAccessor;
33
35
  queryDatabaseObject: (sql: string, params?: unknown[] | Record<string, unknown>) => Promise<any[]>;
34
36
  tryQueryDatabaseObject: (sql: string, params?: unknown[] | Record<string, unknown>) => Promise<any[]>;
35
37
  registerMiddleware(middleware: any): void;
@@ -1,4 +1,4 @@
1
- import { CreateEntityOptions, IRpdDataAccessor, RpdDataModel, IDatabaseAccessor, DatabaseQuery } from "~/types";
1
+ import { CreateEntityOptions, IRpdDataAccessor, RpdDataModel, IDatabaseAccessor, DatabaseQuery, IDatabaseClient } from "~/types";
2
2
  import QueryBuilder from "~/queryBuilder/queryBuilder";
3
3
  import { first, set } from "lodash";
4
4
  import { IRpdServer } from "~/core/server";
@@ -30,16 +30,16 @@ export default class DataAccessor<T = any> implements IRpdDataAccessor<T> {
30
30
  return this.#model;
31
31
  }
32
32
 
33
- async create(entity: Partial<T>): Promise<T> {
33
+ async create(entity: Partial<T>, databaseClient: IDatabaseClient | null): Promise<T> {
34
34
  const options: CreateEntityOptions = {
35
35
  entity,
36
36
  };
37
37
  const query = this.#queryBuilder.insert(this.#model, options);
38
- const result = await this.#databaseAccessor.queryDatabaseObject(query.command, query.params);
38
+ const result = await this.#databaseAccessor.queryDatabaseObject(query.command, query.params, databaseClient);
39
39
  return first(result);
40
40
  }
41
41
 
42
- async updateById(id: any, entity: Partial<T>): Promise<{ count: number }> {
42
+ async updateById(id: any, entity: Partial<T>, databaseClient: IDatabaseClient | null): Promise<{ count: number }> {
43
43
  const options: UpdateRowOptions = {
44
44
  entity,
45
45
  filters: [
@@ -53,11 +53,11 @@ export default class DataAccessor<T = any> implements IRpdDataAccessor<T> {
53
53
  ],
54
54
  };
55
55
  const query = this.#queryBuilder.update(this.#model, options);
56
- const result = await this.#databaseAccessor.queryDatabaseObject(query.command, query.params);
56
+ const result = await this.#databaseAccessor.queryDatabaseObject(query.command, query.params, databaseClient);
57
57
  return first(result);
58
58
  }
59
59
 
60
- async find(options: FindRowOptions): Promise<T[]> {
60
+ async find(options: FindRowOptions, databaseClient: IDatabaseClient | null): Promise<T[]> {
61
61
  this.#logger.debug(`Finding '${this.#model.singularCode}' entity.`, { options });
62
62
  let query: DatabaseQuery;
63
63
  if (this.#model.base) {
@@ -70,19 +70,19 @@ export default class DataAccessor<T = any> implements IRpdDataAccessor<T> {
70
70
  }
71
71
 
72
72
  try {
73
- return await this.#databaseAccessor.queryDatabaseObject(query.command, query.params);
73
+ return await this.#databaseAccessor.queryDatabaseObject(query.command, query.params, databaseClient);
74
74
  } catch (err) {
75
75
  throw newDatabaseError(`Failed to find entities. ${err.message}`, err);
76
76
  }
77
77
  }
78
78
 
79
- async findOne(options: FindRowOptions): Promise<T> {
79
+ async findOne(options: FindRowOptions, databaseClient: IDatabaseClient | null): Promise<T> {
80
80
  set(options, "pagination.limit", 1);
81
- const list = await this.find(options);
81
+ const list = await this.find(options, databaseClient);
82
82
  return first(list);
83
83
  }
84
84
 
85
- async findById(id: any): Promise<T | null> {
85
+ async findById(id: any, databaseClient: IDatabaseClient | null): Promise<T | null> {
86
86
  const options: FindRowOptions = {
87
87
  filters: [
88
88
  {
@@ -94,11 +94,11 @@ export default class DataAccessor<T = any> implements IRpdDataAccessor<T> {
94
94
  },
95
95
  ],
96
96
  };
97
- const result = await this.findOne(options);
97
+ const result = await this.findOne(options, databaseClient);
98
98
  return result;
99
99
  }
100
100
 
101
- async count(options: CountRowOptions): Promise<number> {
101
+ async count(options: CountRowOptions, databaseClient: IDatabaseClient | null): Promise<number> {
102
102
  let query: DatabaseQuery;
103
103
  if (this.#model.base) {
104
104
  const baseModel = this.#server.getModel({
@@ -108,7 +108,7 @@ export default class DataAccessor<T = any> implements IRpdDataAccessor<T> {
108
108
  } else {
109
109
  query = this.#queryBuilder.count(this.#model, options);
110
110
  }
111
- const result = await this.#databaseAccessor.queryDatabaseObject(query.command, query.params);
111
+ const result = await this.#databaseAccessor.queryDatabaseObject(query.command, query.params, databaseClient);
112
112
 
113
113
  const row = first(result);
114
114
  if (row) {
@@ -117,7 +117,7 @@ export default class DataAccessor<T = any> implements IRpdDataAccessor<T> {
117
117
  return 0;
118
118
  }
119
119
 
120
- async deleteById(id: any) {
120
+ async deleteById(id: any, databaseClient: IDatabaseClient | null) {
121
121
  const options: FindRowOptions = {
122
122
  filters: [
123
123
  {
@@ -130,6 +130,6 @@ export default class DataAccessor<T = any> implements IRpdDataAccessor<T> {
130
130
  ],
131
131
  };
132
132
  const query = this.#queryBuilder.delete(this.#model, options);
133
- await this.#databaseAccessor.queryDatabaseObject(query.command, query.params);
133
+ await this.#databaseAccessor.queryDatabaseObject(query.command, query.params, databaseClient);
134
134
  }
135
135
  }
@@ -143,6 +143,7 @@ function convertEntityOrderByToRowOrderBy(server: IRpdServer, model: RpdDataMode
143
143
  }
144
144
 
145
145
  async function findEntities(server: IRpdServer, dataAccessor: IRpdDataAccessor, options: FindEntityOptions) {
146
+ const routeContext = options.routeContext;
146
147
  const model = dataAccessor.getModel();
147
148
  let baseModel: RpdDataModel | undefined;
148
149
  if (model.base) {
@@ -242,14 +243,14 @@ async function findEntities(server: IRpdServer, dataAccessor: IRpdDataAccessor,
242
243
  });
243
244
  }
244
245
 
245
- const rowFilters = await convertEntityFiltersToRowFilters(server, model, baseModel, options.filters);
246
+ const rowFilters = await convertEntityFiltersToRowFilters(routeContext, server, model, baseModel, options.filters);
246
247
  const findRowOptions: FindRowOptions = {
247
248
  filters: rowFilters,
248
249
  orderBy: convertEntityOrderByToRowOrderBy(server, model, baseModel, options.orderBy),
249
250
  pagination: options.pagination,
250
251
  fields: columnsToSelect,
251
252
  };
252
- const rows = await dataAccessor.find(findRowOptions);
253
+ const rows = await dataAccessor.find(findRowOptions, routeContext?.getDbTransactionClient());
253
254
  if (!rows.length) {
254
255
  return [];
255
256
  }
@@ -374,6 +375,7 @@ async function findById(server: IRpdServer, dataAccessor: IRpdDataAccessor, opti
374
375
  }
375
376
 
376
377
  async function convertEntityFiltersToRowFilters(
378
+ routeContext: RouteContext,
377
379
  server: IRpdServer,
378
380
  model: RpdDataModel,
379
381
  baseModel: RpdDataModel,
@@ -389,7 +391,7 @@ async function convertEntityFiltersToRowFilters(
389
391
  if (operator === "and" || operator === "or") {
390
392
  replacedFilters.push({
391
393
  operator: operator,
392
- filters: await convertEntityFiltersToRowFilters(server, model, baseModel, filter.filters),
394
+ filters: await convertEntityFiltersToRowFilters(routeContext, server, model, baseModel, filter.filters),
393
395
  });
394
396
  } else if (operator === "exists" || operator === "notExists") {
395
397
  const relationProperty: RpdDataModelProperty = getEntityPropertyByCode(server, model, filter.field);
@@ -444,15 +446,18 @@ async function convertEntityFiltersToRowFilters(
444
446
  singularCode: relatedModel.base,
445
447
  });
446
448
  }
447
- const rows = await dataAccessor.find({
448
- filters: await convertEntityFiltersToRowFilters(server, relatedModel, relatedBaseModel, filter.filters),
449
- fields: [
450
- {
451
- name: "id",
452
- tableName: relatedModel.tableName,
453
- },
454
- ],
455
- });
449
+ const rows = await dataAccessor.find(
450
+ {
451
+ filters: await convertEntityFiltersToRowFilters(routeContext, server, relatedModel, relatedBaseModel, filter.filters),
452
+ fields: [
453
+ {
454
+ name: "id",
455
+ tableName: relatedModel.tableName,
456
+ },
457
+ ],
458
+ },
459
+ routeContext?.getDbTransactionClient(),
460
+ );
456
461
  const entityIds = map(rows, (entity: any) => entity["id"]);
457
462
  replacedFilters.push({
458
463
  field: {
@@ -478,15 +483,18 @@ async function convertEntityFiltersToRowFilters(
478
483
  singularCode: relatedModel.base,
479
484
  });
480
485
  }
481
- const targetEntities = await targetEntityDataAccessor.find({
482
- filters: await convertEntityFiltersToRowFilters(server, relatedModel, relatedBaseModel, filter.filters),
483
- fields: [
484
- {
485
- name: relationProperty.selfIdColumnName,
486
- tableName: relatedModel.tableName,
487
- },
488
- ],
489
- });
486
+ const targetEntities = await targetEntityDataAccessor.find(
487
+ {
488
+ filters: await convertEntityFiltersToRowFilters(routeContext, server, relatedModel, relatedBaseModel, filter.filters),
489
+ fields: [
490
+ {
491
+ name: relationProperty.selfIdColumnName,
492
+ tableName: relatedModel.tableName,
493
+ },
494
+ ],
495
+ },
496
+ routeContext?.getDbTransactionClient(),
497
+ );
490
498
  const selfEntityIds = map(targetEntities, (entity: any) => entity[relationProperty.selfIdColumnName!]);
491
499
  replacedFilters.push({
492
500
  field: {
@@ -519,15 +527,18 @@ async function convertEntityFiltersToRowFilters(
519
527
  singularCode: relatedModel.base,
520
528
  });
521
529
  }
522
- const targetEntities = await targetEntityDataAccessor.find({
523
- filters: await convertEntityFiltersToRowFilters(server, relatedModel, relatedBaseModel, filter.filters),
524
- fields: [
525
- {
526
- name: "id",
527
- tableName: relatedModel.tableName,
528
- },
529
- ],
530
- });
530
+ const targetEntities = await targetEntityDataAccessor.find(
531
+ {
532
+ filters: await convertEntityFiltersToRowFilters(routeContext, server, relatedModel, relatedBaseModel, filter.filters),
533
+ fields: [
534
+ {
535
+ name: "id",
536
+ tableName: relatedModel.tableName,
537
+ },
538
+ ],
539
+ },
540
+ routeContext?.getDbTransactionClient(),
541
+ );
531
542
  const targetEntityIds = map(targetEntities, (entity: any) => entity["id"]);
532
543
 
533
544
  const command = `SELECT * FROM ${server.queryBuilder.quoteTable({
@@ -880,7 +891,7 @@ async function createEntity(server: IRpdServer, dataAccessor: IRpdDataAccessor,
880
891
 
881
892
  row.id = newBaseRow.id;
882
893
  }
883
- const newRow = await dataAccessor.create(row);
894
+ const newRow = await dataAccessor.create(row, routeContext?.getDbTransactionClient());
884
895
  const newEntity = mapDbRowToEntity(server, model, Object.assign({}, newBaseRow, newRow, newEntityOneRelationProps), true);
885
896
 
886
897
  // save one-relation properties that has selfIdColumnName
@@ -908,7 +919,7 @@ async function createEntity(server: IRpdServer, dataAccessor: IRpdDataAccessor,
908
919
  const relationFieldChanges = {
909
920
  [property.targetIdColumnName]: newTargetEntity.id,
910
921
  };
911
- await dataAccessorOfMainEntity.updateById(newEntity.id, relationFieldChanges);
922
+ await dataAccessorOfMainEntity.updateById(newEntity.id, relationFieldChanges, routeContext?.getDbTransactionClient());
912
923
  newEntity[property.code] = newTargetEntity;
913
924
  }
914
925
  }
@@ -955,7 +966,7 @@ async function createEntity(server: IRpdServer, dataAccessor: IRpdDataAccessor,
955
966
  newEntity[property.code].push(newTargetEntity);
956
967
  } else {
957
968
  // related entity is existed
958
- const targetEntity = await targetDataAccessor.findById(relatedEntityId);
969
+ const targetEntity = await targetDataAccessor.findById(relatedEntityId, routeContext?.getDbTransactionClient());
959
970
  if (!targetEntity) {
960
971
  throw new Error(`Entity with id '${relatedEntityId}' in field '${property.code}' is not exists.`);
961
972
  }
@@ -968,7 +979,7 @@ async function createEntity(server: IRpdServer, dataAccessor: IRpdDataAccessor,
968
979
  const params = [newEntity.id, relatedEntityId];
969
980
  await server.queryDatabaseObject(command, params);
970
981
  } else {
971
- await targetDataAccessor.updateById(targetEntity.id, { [property.selfIdColumnName!]: newEntity.id });
982
+ await targetDataAccessor.updateById(targetEntity.id, { [property.selfIdColumnName!]: newEntity.id }, routeContext?.getDbTransactionClient());
972
983
  targetEntity[property.selfIdColumnName!] = newEntity.id;
973
984
  }
974
985
  newEntity[property.code].push(targetEntity);
@@ -976,7 +987,7 @@ async function createEntity(server: IRpdServer, dataAccessor: IRpdDataAccessor,
976
987
  } else {
977
988
  // fieldValue is id
978
989
  relatedEntityId = relatedEntityToBeSaved;
979
- const targetEntity = await targetDataAccessor.findById(relatedEntityId);
990
+ const targetEntity = await targetDataAccessor.findById(relatedEntityId, routeContext?.getDbTransactionClient());
980
991
  if (!targetEntity) {
981
992
  throw new Error(`Entity with id '${relatedEntityId}' in field '${property.code}' is not exists.`);
982
993
  }
@@ -989,7 +1000,7 @@ async function createEntity(server: IRpdServer, dataAccessor: IRpdDataAccessor,
989
1000
  const params = [newEntity.id, relatedEntityId];
990
1001
  await server.queryDatabaseObject(command, params);
991
1002
  } else {
992
- await targetDataAccessor.updateById(targetEntity.id, { [property.selfIdColumnName!]: newEntity.id });
1003
+ await targetDataAccessor.updateById(targetEntity.id, { [property.selfIdColumnName!]: newEntity.id }, routeContext?.getDbTransactionClient());
993
1004
  targetEntity[property.selfIdColumnName!] = newEntity.id;
994
1005
  }
995
1006
 
@@ -1205,7 +1216,7 @@ async function updateEntityById(server: IRpdServer, dataAccessor: IRpdDataAccess
1205
1216
 
1206
1217
  let updatedRow = row;
1207
1218
  if (Object.keys(row).length) {
1208
- updatedRow = await dataAccessor.updateById(id, row);
1219
+ updatedRow = await dataAccessor.updateById(id, row, routeContext?.getDbTransactionClient());
1209
1220
  }
1210
1221
  let updatedBaseRow = baseRow;
1211
1222
  let baseDataAccessor: any;
@@ -1246,7 +1257,7 @@ async function updateEntityById(server: IRpdServer, dataAccessor: IRpdDataAccess
1246
1257
  const relationFieldChanges = {
1247
1258
  [property.targetIdColumnName]: newTargetEntity.id,
1248
1259
  };
1249
- await dataAccessorOfMainEntity.updateById(updatedEntity.id, relationFieldChanges);
1260
+ await dataAccessorOfMainEntity.updateById(updatedEntity.id, relationFieldChanges, routeContext?.getDbTransactionClient());
1250
1261
  updatedEntity[property.code] = newTargetEntity;
1251
1262
  changes[property.code] = newTargetEntity;
1252
1263
  }
@@ -1339,7 +1350,7 @@ async function updateEntityById(server: IRpdServer, dataAccessor: IRpdDataAccess
1339
1350
  relatedEntities.push(newTargetEntity);
1340
1351
  } else {
1341
1352
  // related entity is existed
1342
- let targetEntity = await targetDataAccessor.findById(relatedEntityId);
1353
+ let targetEntity = await targetDataAccessor.findById(relatedEntityId, routeContext?.getDbTransactionClient());
1343
1354
  if (!targetEntity) {
1344
1355
  throw new Error(`Entity with id '${relatedEntityId}' in field '${property.code}' does not exist.`);
1345
1356
  }
@@ -1377,7 +1388,7 @@ async function updateEntityById(server: IRpdServer, dataAccessor: IRpdDataAccess
1377
1388
  const params = [id, relatedEntityId];
1378
1389
  await server.queryDatabaseObject(command, params);
1379
1390
  } else {
1380
- await targetDataAccessor.updateById(targetEntity.id, { [property.selfIdColumnName!]: id });
1391
+ await targetDataAccessor.updateById(targetEntity.id, { [property.selfIdColumnName!]: id }, routeContext?.getDbTransactionClient());
1381
1392
  targetEntity[property.selfIdColumnName!] = id;
1382
1393
  }
1383
1394
  }
@@ -1386,7 +1397,7 @@ async function updateEntityById(server: IRpdServer, dataAccessor: IRpdDataAccess
1386
1397
  } else {
1387
1398
  // fieldValue is id
1388
1399
  relatedEntityId = relatedEntityToBeSaved;
1389
- const targetEntity = await targetDataAccessor.findById(relatedEntityId);
1400
+ const targetEntity = await targetDataAccessor.findById(relatedEntityId, routeContext?.getDbTransactionClient());
1390
1401
  if (!targetEntity) {
1391
1402
  throw new Error(`Entity with id '${relatedEntityId}' in field '${property.code}' is not exists.`);
1392
1403
  }
@@ -1400,7 +1411,7 @@ async function updateEntityById(server: IRpdServer, dataAccessor: IRpdDataAccess
1400
1411
  const params = [id, relatedEntityId];
1401
1412
  await server.queryDatabaseObject(command, params);
1402
1413
  } else {
1403
- await targetDataAccessor.updateById(targetEntity.id, { [property.selfIdColumnName!]: id });
1414
+ await targetDataAccessor.updateById(targetEntity.id, { [property.selfIdColumnName!]: id }, routeContext?.getDbTransactionClient());
1404
1415
  targetEntity[property.selfIdColumnName!] = id;
1405
1416
  }
1406
1417
  }
@@ -1537,6 +1548,7 @@ export default class EntityManager<TEntity = any> {
1537
1548
  }
1538
1549
 
1539
1550
  async count(options: CountEntityOptions): Promise<number> {
1551
+ const routeContext = options.routeContext;
1540
1552
  const model = this.#dataAccessor.getModel();
1541
1553
  let baseModel: RpdDataModel;
1542
1554
  if (model.base) {
@@ -1545,9 +1557,9 @@ export default class EntityManager<TEntity = any> {
1545
1557
  });
1546
1558
  }
1547
1559
  const countRowOptions: CountRowOptions = {
1548
- filters: await convertEntityFiltersToRowFilters(this.#server, model, baseModel, options.filters),
1560
+ filters: await convertEntityFiltersToRowFilters(routeContext, this.#server, model, baseModel, options.filters),
1549
1561
  };
1550
- return await this.#dataAccessor.count(countRowOptions);
1562
+ return await this.#dataAccessor.count(countRowOptions, routeContext?.getDbTransactionClient());
1551
1563
  }
1552
1564
 
1553
1565
  async deleteById(options: DeleteEntityByIdOptions | string | number, plugin?: RapidPlugin): Promise<void> {
@@ -1593,17 +1605,21 @@ export default class EntityManager<TEntity = any> {
1593
1605
  })
1594
1606
  : this.#dataAccessor;
1595
1607
  const currentUserId = routeContext?.state?.userId;
1596
- await dataAccessor.updateById(id, {
1597
- deleted_at: getNowStringWithTimezone(),
1598
- deleter_id: currentUserId,
1599
- });
1608
+ await dataAccessor.updateById(
1609
+ id,
1610
+ {
1611
+ deleted_at: getNowStringWithTimezone(),
1612
+ deleter_id: currentUserId,
1613
+ },
1614
+ routeContext?.getDbTransactionClient(),
1615
+ );
1600
1616
  } else {
1601
- await this.#dataAccessor.deleteById(id);
1617
+ await this.#dataAccessor.deleteById(id, routeContext?.getDbTransactionClient());
1602
1618
  if (model.base) {
1603
1619
  const baseDataAccessor = this.#server.getDataAccessor({
1604
1620
  singularCode: model.base,
1605
1621
  });
1606
- await baseDataAccessor.deleteById(id);
1622
+ await baseDataAccessor.deleteById(id, routeContext?.getDbTransactionClient());
1607
1623
  }
1608
1624
  }
1609
1625