@ruiapp/rapid-core 0.8.9 → 0.8.10

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.
@@ -4,6 +4,7 @@ import { HttpStatus } from "./http-types";
4
4
  import { IRpdServer } from "./server";
5
5
  import { IDatabaseAccessor, IDatabaseClient } from "../types";
6
6
  export type Next = () => Promise<void>;
7
+ export type TransactionState = "uninited" | "inited" | "started";
7
8
  export declare class RouteContext {
8
9
  #private;
9
10
  readonly request: RapidRequest;
@@ -22,7 +23,8 @@ export declare class RouteContext {
22
23
  json(obj: any, status?: HttpStatus, headers?: HeadersInit): void;
23
24
  redirect(url: string, status?: HttpStatus): void;
24
25
  getDbTransactionClient(): IDatabaseClient | undefined;
25
- beginDbTransaction(): Promise<IDatabaseClient>;
26
+ initDbTransactionClient(): Promise<IDatabaseClient>;
27
+ beginDbTransaction(): Promise<void>;
26
28
  commitDbTransaction(): Promise<void>;
27
29
  rollbackDbTransaction(): Promise<void>;
28
30
  }
package/dist/index.js CHANGED
@@ -1052,12 +1052,14 @@ class RouteContext {
1052
1052
  routeConfig;
1053
1053
  #server;
1054
1054
  #dbTransactionClient;
1055
+ #dbTransactionState;
1055
1056
  static newSystemOperationContext(server) {
1056
1057
  return new RouteContext(server);
1057
1058
  }
1058
1059
  constructor(server, request) {
1059
1060
  this.#server = server;
1060
1061
  this.databaseAccessor = server.getDatabaseAccessor();
1062
+ this.#dbTransactionState = "uninited";
1061
1063
  this.request = request;
1062
1064
  this.state = {};
1063
1065
  this.response = new RapidResponse();
@@ -1091,27 +1093,45 @@ class RouteContext {
1091
1093
  getDbTransactionClient() {
1092
1094
  return this.#dbTransactionClient;
1093
1095
  }
1094
- async beginDbTransaction() {
1096
+ async initDbTransactionClient() {
1095
1097
  let dbClient = this.#dbTransactionClient;
1096
1098
  if (dbClient) {
1097
- throw new Error("Database transaction has been started. You can not start a transaction more than once in a request context.");
1099
+ return dbClient;
1098
1100
  }
1099
1101
  dbClient = await this.databaseAccessor.getClient();
1100
- await this.databaseAccessor.queryDatabaseObject("BEGIN", [], dbClient);
1102
+ this.#dbTransactionState = "inited";
1101
1103
  this.#dbTransactionClient = dbClient;
1102
1104
  return dbClient;
1103
1105
  }
1106
+ async beginDbTransaction() {
1107
+ if (!this.#dbTransactionClient) {
1108
+ throw new Error("Database transaction has not been inited. You should call initDbTransactionClient() first.");
1109
+ }
1110
+ if (this.#dbTransactionState === "started") {
1111
+ throw new Error("Database transaction has been started. You can not begin a new transaction before you commit or rollback it.");
1112
+ }
1113
+ await this.databaseAccessor.queryDatabaseObject("BEGIN", [], this.#dbTransactionClient);
1114
+ this.#dbTransactionState = "started";
1115
+ }
1104
1116
  async commitDbTransaction() {
1105
1117
  if (!this.#dbTransactionClient) {
1118
+ throw new Error("Database transaction has not been inited. You should call initDbTransactionClient() first.");
1119
+ }
1120
+ if (this.#dbTransactionState !== "started") {
1106
1121
  throw new Error("Database transaction has not been started. You should call beginDbTransaction() first.");
1107
1122
  }
1108
1123
  await this.databaseAccessor.queryDatabaseObject("COMMIT", [], this.#dbTransactionClient);
1124
+ this.#dbTransactionState = "inited";
1109
1125
  }
1110
1126
  async rollbackDbTransaction() {
1111
1127
  if (!this.#dbTransactionClient) {
1128
+ throw new Error("Database transaction has not been inited. You should call initDbTransactionClient() first.");
1129
+ }
1130
+ if (this.#dbTransactionState !== "started") {
1112
1131
  throw new Error("Database transaction has not been started. You should call beginDbTransaction() first.");
1113
1132
  }
1114
1133
  await this.databaseAccessor.queryDatabaseObject("ROLLBACK", [], this.#dbTransactionClient);
1134
+ this.#dbTransactionState = "inited";
1115
1135
  }
1116
1136
  }
1117
1137
 
@@ -5593,7 +5613,8 @@ async function runCollectionEntityActionHandler(ctx, options, code, autoMergeInp
5593
5613
  if (runInTransaction) {
5594
5614
  let transactionDbClient;
5595
5615
  try {
5596
- transactionDbClient = await routeContext.beginDbTransaction();
5616
+ transactionDbClient = await routeContext.initDbTransactionClient();
5617
+ await routeContext.beginDbTransaction();
5597
5618
  const result = handleEntityAction(entityManager, autoMergeInput ? mergedInput : input);
5598
5619
  if (result instanceof Promise) {
5599
5620
  ctx.output = await result;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ruiapp/rapid-core",
3
- "version": "0.8.9",
3
+ "version": "0.8.10",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,13 +1,13 @@
1
- import { isArray, isObject } from "lodash";
2
1
  import { RapidRequest } from "./request";
3
2
  import { RapidResponse } from "./response";
4
- import { HttpStatus, ResponseData } from "./http-types";
3
+ import { HttpStatus } from "./http-types";
5
4
  import { IRpdServer } from "./server";
6
- import { Logger } from "~/facilities/log/LogFacility";
7
5
  import { IDatabaseAccessor, IDatabaseClient } from "~/types";
8
6
 
9
7
  export type Next = () => Promise<void>;
10
8
 
9
+ export type TransactionState = "uninited" | "inited" | "started";
10
+
11
11
  // TODO: should divide to RequestContext and OperationContext
12
12
 
13
13
  export class RouteContext {
@@ -21,6 +21,7 @@ export class RouteContext {
21
21
  routeConfig: any;
22
22
  #server: IRpdServer;
23
23
  #dbTransactionClient: IDatabaseClient | undefined;
24
+ #dbTransactionState: TransactionState;
24
25
 
25
26
  static newSystemOperationContext(server: IRpdServer) {
26
27
  return new RouteContext(server);
@@ -29,6 +30,8 @@ export class RouteContext {
29
30
  constructor(server: IRpdServer, request?: RapidRequest) {
30
31
  this.#server = server;
31
32
  this.databaseAccessor = server.getDatabaseAccessor();
33
+ this.#dbTransactionState = "uninited";
34
+
32
35
  this.request = request;
33
36
  this.state = {};
34
37
  this.response = new RapidResponse();
@@ -71,29 +74,54 @@ export class RouteContext {
71
74
  return this.#dbTransactionClient;
72
75
  }
73
76
 
74
- async beginDbTransaction(): Promise<IDatabaseClient> {
77
+ async initDbTransactionClient(): Promise<IDatabaseClient> {
75
78
  let dbClient = this.#dbTransactionClient;
76
79
  if (dbClient) {
77
- throw new Error("Database transaction has been started. You can not start a transaction more than once in a request context.");
80
+ return dbClient;
78
81
  }
79
82
 
80
83
  dbClient = await this.databaseAccessor.getClient();
81
- await this.databaseAccessor.queryDatabaseObject("BEGIN", [], dbClient);
84
+ this.#dbTransactionState = "inited";
82
85
  this.#dbTransactionClient = dbClient;
83
86
  return dbClient;
84
87
  }
85
88
 
89
+ async beginDbTransaction(): Promise<void> {
90
+ if (!this.#dbTransactionClient) {
91
+ throw new Error("Database transaction has not been inited. You should call initDbTransactionClient() first.");
92
+ }
93
+
94
+ if (this.#dbTransactionState === "started") {
95
+ throw new Error("Database transaction has been started. You can not begin a new transaction before you commit or rollback it.");
96
+ }
97
+
98
+ await this.databaseAccessor.queryDatabaseObject("BEGIN", [], this.#dbTransactionClient);
99
+ this.#dbTransactionState = "started";
100
+ }
101
+
86
102
  async commitDbTransaction(): Promise<void> {
87
103
  if (!this.#dbTransactionClient) {
104
+ throw new Error("Database transaction has not been inited. You should call initDbTransactionClient() first.");
105
+ }
106
+
107
+ if (this.#dbTransactionState !== "started") {
88
108
  throw new Error("Database transaction has not been started. You should call beginDbTransaction() first.");
89
109
  }
110
+
90
111
  await this.databaseAccessor.queryDatabaseObject("COMMIT", [], this.#dbTransactionClient);
112
+ this.#dbTransactionState = "inited";
91
113
  }
92
114
 
93
115
  async rollbackDbTransaction(): Promise<void> {
94
116
  if (!this.#dbTransactionClient) {
117
+ throw new Error("Database transaction has not been inited. You should call initDbTransactionClient() first.");
118
+ }
119
+
120
+ if (this.#dbTransactionState !== "started") {
95
121
  throw new Error("Database transaction has not been started. You should call beginDbTransaction() first.");
96
122
  }
123
+
97
124
  await this.databaseAccessor.queryDatabaseObject("ROLLBACK", [], this.#dbTransactionClient);
125
+ this.#dbTransactionState = "inited";
98
126
  }
99
127
  }
@@ -28,7 +28,8 @@ export default async function runCollectionEntityActionHandler(
28
28
  let transactionDbClient: IDatabaseClient;
29
29
 
30
30
  try {
31
- transactionDbClient = await routeContext.beginDbTransaction();
31
+ transactionDbClient = await routeContext.initDbTransactionClient();
32
+ await routeContext.beginDbTransaction();
32
33
 
33
34
  const result = handleEntityAction(entityManager, autoMergeInput ? mergedInput : input);
34
35
  if (result instanceof Promise) {