@entity-access/entity-access 1.0.306 → 1.0.308
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/common/symbols/symbols.d.ts +1 -0
- package/dist/common/symbols/symbols.d.ts.map +1 -1
- package/dist/common/symbols/symbols.js +1 -0
- package/dist/common/symbols/symbols.js.map +1 -1
- package/dist/drivers/base/BaseDriver.d.ts +18 -14
- package/dist/drivers/base/BaseDriver.d.ts.map +1 -1
- package/dist/drivers/base/BaseDriver.js +52 -25
- package/dist/drivers/base/BaseDriver.js.map +1 -1
- package/dist/drivers/postgres/PostgreSqlDriver.d.ts.map +1 -1
- package/dist/drivers/postgres/PostgreSqlDriver.js +23 -12
- package/dist/drivers/postgres/PostgreSqlDriver.js.map +1 -1
- package/dist/drivers/sql-server/SqlServerDriver.d.ts +1 -1
- package/dist/drivers/sql-server/SqlServerDriver.d.ts.map +1 -1
- package/dist/drivers/sql-server/SqlServerDriver.js +30 -11
- package/dist/drivers/sql-server/SqlServerDriver.js.map +1 -1
- package/dist/model/EntityContext.d.ts.map +1 -1
- package/dist/model/EntityContext.js +28 -10
- package/dist/model/EntityContext.js.map +1 -1
- package/dist/model/EntitySource.d.ts.map +1 -1
- package/dist/model/EntitySource.js +2 -1
- package/dist/model/EntitySource.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/workflows/WorkflowStorage.d.ts.map +1 -1
- package/dist/workflows/WorkflowStorage.js +17 -18
- package/dist/workflows/WorkflowStorage.js.map +1 -1
- package/package.json +1 -1
- package/src/common/symbols/symbols.ts +1 -0
- package/src/drivers/base/BaseDriver.ts +69 -40
- package/src/drivers/postgres/PostgreSqlDriver.ts +28 -13
- package/src/drivers/sql-server/SqlServerDriver.ts +39 -13
- package/src/model/EntityContext.ts +27 -21
- package/src/model/EntitySource.ts +2 -1
- package/src/workflows/WorkflowStorage.ts +11 -26
|
@@ -47,41 +47,75 @@ export interface IQueryResult {
|
|
|
47
47
|
updated?: number;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
dispose(): Promise<void>;
|
|
54
|
-
}
|
|
50
|
+
const currentTransaction = Symbol("currentTrnsaction");
|
|
51
|
+
|
|
52
|
+
export abstract class EntityTransaction {
|
|
55
53
|
|
|
56
|
-
|
|
54
|
+
private committedOrRolledBack = false;
|
|
57
55
|
|
|
58
|
-
|
|
56
|
+
private disposed = false;
|
|
57
|
+
|
|
58
|
+
constructor(protected conn: BaseConnection) {
|
|
59
|
+
conn[currentTransaction] = this;
|
|
60
|
+
}
|
|
59
61
|
|
|
60
|
-
|
|
62
|
+
begin() {
|
|
63
|
+
return this.beginTransaction();
|
|
64
|
+
}
|
|
61
65
|
|
|
62
66
|
commit() {
|
|
63
67
|
this.committedOrRolledBack = true;
|
|
64
|
-
return this.
|
|
68
|
+
return this.commitTransaction();
|
|
65
69
|
}
|
|
66
70
|
|
|
67
71
|
rollback() {
|
|
68
72
|
this.committedOrRolledBack = true;
|
|
69
|
-
return this.
|
|
73
|
+
return this.rollbackTransaction();
|
|
70
74
|
}
|
|
71
75
|
|
|
72
76
|
async dispose() {
|
|
77
|
+
if (this.disposed) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
this.disposed = true;
|
|
73
81
|
if(!this.committedOrRolledBack) {
|
|
74
|
-
await this.
|
|
82
|
+
await this.rollbackTransaction();
|
|
75
83
|
}
|
|
76
|
-
await this.
|
|
84
|
+
await this.disposeTransaction();
|
|
77
85
|
}
|
|
78
86
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
87
|
+
[Symbol.asyncDispose]() {
|
|
88
|
+
return this.dispose();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
protected abstract disposeTransaction(): Promise<void>;
|
|
92
|
+
|
|
93
|
+
protected abstract commitTransaction(): Promise<void>;
|
|
94
|
+
|
|
95
|
+
protected abstract rollbackTransaction(): Promise<void>;
|
|
96
|
+
|
|
97
|
+
protected abstract beginTransaction(): Promise<void>;
|
|
98
|
+
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const emptyResolve = Promise.resolve();
|
|
102
|
+
|
|
103
|
+
class EmptyTransaction extends EntityTransaction {
|
|
104
|
+
|
|
105
|
+
protected disposeTransaction() {
|
|
106
|
+
return emptyResolve;
|
|
107
|
+
}
|
|
108
|
+
protected commitTransaction() {
|
|
109
|
+
return emptyResolve;
|
|
110
|
+
}
|
|
111
|
+
protected rollbackTransaction() {
|
|
112
|
+
return emptyResolve;
|
|
84
113
|
}
|
|
114
|
+
|
|
115
|
+
protected beginTransaction() {
|
|
116
|
+
return emptyResolve;
|
|
117
|
+
}
|
|
118
|
+
|
|
85
119
|
}
|
|
86
120
|
|
|
87
121
|
export abstract class BaseConnection {
|
|
@@ -90,7 +124,7 @@ export abstract class BaseConnection {
|
|
|
90
124
|
|
|
91
125
|
protected connectionString: IDbConnectionString;
|
|
92
126
|
|
|
93
|
-
private currentTransaction: EntityTransaction;
|
|
127
|
+
private [currentTransaction]: EntityTransaction;
|
|
94
128
|
|
|
95
129
|
|
|
96
130
|
constructor(public driver: BaseDriver) {
|
|
@@ -106,35 +140,30 @@ export abstract class BaseConnection {
|
|
|
106
140
|
*/
|
|
107
141
|
public abstract automaticMigrations(): Migrations;
|
|
108
142
|
|
|
143
|
+
public async runInTransaction<T = any>(fx?: () => Promise<T>) {
|
|
144
|
+
await using tx = await this.createTransaction();
|
|
145
|
+
const result = await fx();
|
|
146
|
+
await tx.commit();
|
|
147
|
+
return result;
|
|
148
|
+
}
|
|
149
|
+
|
|
109
150
|
|
|
110
151
|
public abstract executeReader(command: IQuery, signal?: AbortSignal): Promise<IDbReader>;
|
|
111
152
|
|
|
112
153
|
public abstract executeQuery(command: IQuery, signal?: AbortSignal): Promise<IQueryResult>;
|
|
113
154
|
|
|
114
|
-
public
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
// nested transactions... do not worry
|
|
119
|
-
// just pass through
|
|
120
|
-
return await fx();
|
|
121
|
-
}
|
|
122
|
-
let failed = true;
|
|
123
|
-
let tx: EntityTransaction;
|
|
124
|
-
try {
|
|
125
|
-
tx = this.currentTransaction = await this.createTransaction();
|
|
126
|
-
const result = await fx();
|
|
127
|
-
await tx.commit();
|
|
128
|
-
failed = false;
|
|
129
|
-
return result;
|
|
130
|
-
} finally {
|
|
131
|
-
if (failed) {
|
|
132
|
-
await tx?.rollback();
|
|
133
|
-
}
|
|
134
|
-
await tx?.[Symbol.asyncDispose]();
|
|
135
|
-
this.currentTransaction = null;
|
|
155
|
+
public async createTransaction() {
|
|
156
|
+
if (this[currentTransaction]) {
|
|
157
|
+
// return fake one...
|
|
158
|
+
return new EmptyTransaction(this);
|
|
136
159
|
}
|
|
160
|
+
const tx = this[currentTransaction] = await this.createDbTransaction();
|
|
161
|
+
await tx.begin();
|
|
162
|
+
return tx;
|
|
137
163
|
}
|
|
164
|
+
|
|
165
|
+
protected abstract createDbTransaction(): Promise<EntityTransaction>;
|
|
166
|
+
|
|
138
167
|
}
|
|
139
168
|
|
|
140
169
|
export type DirectSaveType =
|
|
@@ -3,7 +3,7 @@ import ObjectPool, { IPooledObject } from "../../common/ObjectPool.js";
|
|
|
3
3
|
import QueryCompiler from "../../compiler/QueryCompiler.js";
|
|
4
4
|
import Migrations from "../../migrations/Migrations.js";
|
|
5
5
|
import PostgresAutomaticMigrations from "../../migrations/postgres/PostgresAutomaticMigrations.js";
|
|
6
|
-
import { BaseConnection, BaseDriver, EntityTransaction,
|
|
6
|
+
import { BaseConnection, BaseDriver, EntityTransaction, IDbConnectionString, IDbReader, IQuery, toQuery } from "../base/BaseDriver.js";
|
|
7
7
|
import pg from "pg";
|
|
8
8
|
import Cursor from "pg-cursor";
|
|
9
9
|
export interface IPgSqlConnectionString extends IDbConnectionString {
|
|
@@ -118,6 +118,28 @@ export default class PostgreSqlDriver extends BaseDriver {
|
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
+
class PostgresTransaction extends EntityTransaction {
|
|
122
|
+
|
|
123
|
+
constructor(conn: PostgreSqlConnection, private tx: IPooledObject<pg.Client>) {
|
|
124
|
+
super(conn);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
protected disposeTransaction() {
|
|
128
|
+
(this.conn as any).transaction = null;
|
|
129
|
+
return this.tx[Symbol.asyncDispose]();
|
|
130
|
+
}
|
|
131
|
+
protected commitTransaction() {
|
|
132
|
+
return this.tx.query("COMMIT") as any;
|
|
133
|
+
}
|
|
134
|
+
protected rollbackTransaction() {
|
|
135
|
+
return this.tx.query("ROLLBACK") as any;
|
|
136
|
+
}
|
|
137
|
+
protected beginTransaction() {
|
|
138
|
+
return this.tx.query("BEGIN") as any;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
}
|
|
142
|
+
|
|
121
143
|
class PostgreSqlConnection extends BaseConnection {
|
|
122
144
|
|
|
123
145
|
public get isInTransaction() {
|
|
@@ -134,18 +156,6 @@ class PostgreSqlConnection extends BaseConnection {
|
|
|
134
156
|
super(driver);
|
|
135
157
|
}
|
|
136
158
|
|
|
137
|
-
public async createTransaction(): Promise<EntityTransaction> {
|
|
138
|
-
const tx = await this.getConnection();
|
|
139
|
-
await tx.query("BEGIN");
|
|
140
|
-
return new EntityTransaction({
|
|
141
|
-
commit: () => tx.query("COMMIT"),
|
|
142
|
-
rollback: () => tx.query("ROLLBACK"),
|
|
143
|
-
dispose: () => {
|
|
144
|
-
this.transaction = null;
|
|
145
|
-
return tx[Symbol.asyncDispose]();
|
|
146
|
-
}
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
159
|
|
|
150
160
|
public automaticMigrations(): Migrations {
|
|
151
161
|
return new PostgresAutomaticMigrations(this.compiler);
|
|
@@ -226,6 +236,11 @@ class PostgreSqlConnection extends BaseConnection {
|
|
|
226
236
|
return client;
|
|
227
237
|
}
|
|
228
238
|
|
|
239
|
+
protected async createDbTransaction(): Promise<EntityTransaction> {
|
|
240
|
+
const tx = this.transaction = await this.getConnection();
|
|
241
|
+
return new PostgresTransaction(this, tx);
|
|
242
|
+
}
|
|
243
|
+
|
|
229
244
|
private async kill(id) {
|
|
230
245
|
const client = new pg.Client(this.config);
|
|
231
246
|
try {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
2
|
import QueryCompiler from "../../compiler/QueryCompiler.js";
|
|
3
3
|
import Migrations from "../../migrations/Migrations.js";
|
|
4
|
-
import { BaseConnection, BaseDriver, EntityTransaction,
|
|
4
|
+
import { BaseConnection, BaseDriver, EntityTransaction, IDbConnectionString, IDbReader, IQuery, toQuery } from "../base/BaseDriver.js";
|
|
5
5
|
import sql from "mssql";
|
|
6
6
|
import SqlServerQueryCompiler from "./SqlServerQueryCompiler.js";
|
|
7
7
|
import SqlServerAutomaticMigrations from "../../migrations/sql-server/SqlServerAutomaticMigrations.js";
|
|
@@ -34,6 +34,39 @@ export default class SqlServerDriver extends BaseDriver {
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
const emptyResolve = Promise.resolve();
|
|
38
|
+
|
|
39
|
+
class SqlEntityTransaction extends EntityTransaction {
|
|
40
|
+
|
|
41
|
+
rolledBack: any;
|
|
42
|
+
|
|
43
|
+
constructor(conn: SqlServerConnection, private tx: sql.Transaction) {
|
|
44
|
+
super(conn);
|
|
45
|
+
tx.on("rollback", (aborted) => {
|
|
46
|
+
this.rolledBack = aborted;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
protected async beginTransaction() {
|
|
51
|
+
this.tx = await this.tx.begin();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
protected disposeTransaction(): Promise<void> {
|
|
55
|
+
(this.conn as any).transaction = null;
|
|
56
|
+
return emptyResolve;
|
|
57
|
+
}
|
|
58
|
+
protected async commitTransaction() {
|
|
59
|
+
return this.tx.commit();
|
|
60
|
+
}
|
|
61
|
+
protected async rollbackTransaction() {
|
|
62
|
+
if(this.rolledBack) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
await this.tx.rollback();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
}
|
|
69
|
+
|
|
37
70
|
export class SqlServerConnection extends BaseConnection {
|
|
38
71
|
|
|
39
72
|
private transaction: sql.Transaction;
|
|
@@ -114,22 +147,15 @@ export class SqlServerConnection extends BaseConnection {
|
|
|
114
147
|
return value;
|
|
115
148
|
}
|
|
116
149
|
|
|
117
|
-
public async createTransaction(): Promise<EntityTransaction> {
|
|
118
|
-
this.transaction = new sql.Transaction(await this.newConnection());
|
|
119
|
-
let rolledBack = false;
|
|
120
|
-
this.transaction.on("rollback", (aborted) => rolledBack = aborted);
|
|
121
|
-
await this.transaction.begin();
|
|
122
|
-
return new EntityTransaction({
|
|
123
|
-
commit: () => this.transaction.commit(),
|
|
124
|
-
rollback: async () => !rolledBack && await this.transaction.rollback(),
|
|
125
|
-
dispose: () => this.transaction = void 0
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
|
|
129
150
|
public automaticMigrations(): Migrations {
|
|
130
151
|
return new SqlServerAutomaticMigrations(this.sqlQueryCompiler);
|
|
131
152
|
}
|
|
132
153
|
|
|
154
|
+
protected async createDbTransaction(): Promise<EntityTransaction> {
|
|
155
|
+
const tx = this.transaction = new sql.Transaction(await this.newConnection());
|
|
156
|
+
return new SqlEntityTransaction(this, tx);
|
|
157
|
+
}
|
|
158
|
+
|
|
133
159
|
protected async newRequest(signal: AbortSignal) {
|
|
134
160
|
let request: sql.Request;
|
|
135
161
|
if (this.transaction) {
|
|
@@ -12,6 +12,7 @@ import Inject, { ServiceProvider } from "../di/di.js";
|
|
|
12
12
|
import EntityAccessError from "../common/EntityAccessError.js";
|
|
13
13
|
import Logger from "../common/Logger.js";
|
|
14
14
|
import { FilteredExpression } from "./events/FilteredExpression.js";
|
|
15
|
+
import { traceSymbol } from "../common/symbols/symbols.js";
|
|
15
16
|
|
|
16
17
|
const isChanging = Symbol("isChanging");
|
|
17
18
|
|
|
@@ -121,32 +122,37 @@ export default class EntityContext {
|
|
|
121
122
|
return 0;
|
|
122
123
|
}
|
|
123
124
|
|
|
124
|
-
|
|
125
|
-
|
|
125
|
+
await using tx = await this.connection.createTransaction();
|
|
126
|
+
const oldTraceSymbol = this[traceSymbol];
|
|
127
|
+
this[traceSymbol] = options?.trace;
|
|
128
|
+
try {
|
|
126
129
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
+
if(!this.raiseEvents) {
|
|
131
|
+
const rx = await this.saveChangesInternalWithoutEvents(options);
|
|
132
|
+
await tx.commit();
|
|
133
|
+
return rx;
|
|
134
|
+
}
|
|
130
135
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
136
|
+
this[isChanging] = true;
|
|
137
|
+
const r = await this.saveChangesInternal(options);
|
|
138
|
+
const postSaveChanges = this.postSaveChangesQueue;
|
|
139
|
+
this.postSaveChangesQueue = void 0;
|
|
140
|
+
this[isChanging] = false;
|
|
141
|
+
if (postSaveChanges?.length) {
|
|
142
|
+
postSaveChanges.sort((a, b) => a.order - b.order);
|
|
143
|
+
for (const { task } of postSaveChanges) {
|
|
144
|
+
const p = task();
|
|
145
|
+
if (p?.then) {
|
|
146
|
+
await p;
|
|
143
147
|
}
|
|
144
148
|
}
|
|
145
|
-
return r;
|
|
146
|
-
} finally {
|
|
147
|
-
this[isChanging] = false;
|
|
148
149
|
}
|
|
149
|
-
|
|
150
|
+
await tx.commit();
|
|
151
|
+
return r;
|
|
152
|
+
} finally {
|
|
153
|
+
this[isChanging] = false;
|
|
154
|
+
this[traceSymbol] = oldTraceSymbol;
|
|
155
|
+
}
|
|
150
156
|
}
|
|
151
157
|
|
|
152
158
|
public queuePostSaveTask(task: () => any, order = Number.MAX_SAFE_INTEGER) {
|
|
@@ -2,7 +2,7 @@ import type EntityContext from "./EntityContext.js";
|
|
|
2
2
|
import type EntityType from "../entity-query/EntityType.js";
|
|
3
3
|
import type { IBaseQuery, IEntityQuery, IFilterExpression } from "./IFilterWithParameter.js";
|
|
4
4
|
import EntityQuery from "./EntityQuery.js";
|
|
5
|
-
import { contextSymbol, modelSymbol } from "../common/symbols/symbols.js";
|
|
5
|
+
import { contextSymbol, modelSymbol, traceSymbol } from "../common/symbols/symbols.js";
|
|
6
6
|
import { Expression, ExpressionAs, Identifier, InsertStatement, TableLiteral } from "../query/ast/Expressions.js";
|
|
7
7
|
import { DirectSaveType } from "../drivers/base/BaseDriver.js";
|
|
8
8
|
import IdentityService from "./identity/IdentityService.js";
|
|
@@ -233,6 +233,7 @@ export class EntitySource<T = any> {
|
|
|
233
233
|
selectStatement.model = model;
|
|
234
234
|
return new EntityQuery<T>({
|
|
235
235
|
context,
|
|
236
|
+
trace: context[traceSymbol],
|
|
236
237
|
type: model,
|
|
237
238
|
selectStatement
|
|
238
239
|
}) as any as IEntityQuery<T>;
|
|
@@ -224,32 +224,17 @@ export default class WorkflowStorage {
|
|
|
224
224
|
async save(state: Partial<WorkflowItem>) {
|
|
225
225
|
const db = new WorkflowContext(this.driver);
|
|
226
226
|
const connection = db.connection;
|
|
227
|
-
await connection.
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
// }
|
|
239
|
-
// }
|
|
240
|
-
|
|
241
|
-
// w.state ||= "queued";
|
|
242
|
-
// w.updated ??= DateTime.now;
|
|
243
|
-
state.state ||= "queued";
|
|
244
|
-
state.updated ??= DateTime.now;
|
|
245
|
-
state.taskGroup ||= "default";
|
|
246
|
-
// await db.saveChanges();
|
|
247
|
-
if(state[loadedFromDb]) {
|
|
248
|
-
await db.workflows.saveDirect({ mode: "update", changes: state });
|
|
249
|
-
} else {
|
|
250
|
-
await db.workflows.saveDirect({ mode: "upsert", changes: state });
|
|
251
|
-
}
|
|
252
|
-
});
|
|
227
|
+
await using tx = await connection.createTransaction();
|
|
228
|
+
state.state ||= "queued";
|
|
229
|
+
state.updated ??= DateTime.now;
|
|
230
|
+
state.taskGroup ||= "default";
|
|
231
|
+
// await db.saveChanges();
|
|
232
|
+
if(state[loadedFromDb]) {
|
|
233
|
+
await db.workflows.saveDirect({ mode: "update", changes: state });
|
|
234
|
+
} else {
|
|
235
|
+
await db.workflows.saveDirect({ mode: "upsert", changes: state });
|
|
236
|
+
}
|
|
237
|
+
await tx.commit();
|
|
253
238
|
}
|
|
254
239
|
|
|
255
240
|
async dequeue(taskGroup: string, signal?: AbortSignal) {
|