@entity-access/entity-access 1.0.164 → 1.0.166
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/decorators/IColumn.d.ts +2 -0
- package/dist/decorators/IColumn.d.ts.map +1 -1
- package/dist/decorators/IForeignKeyConstraint.d.ts +12 -0
- package/dist/decorators/IForeignKeyConstraint.d.ts.map +1 -0
- package/dist/decorators/IForeignKeyConstraint.js +2 -0
- package/dist/decorators/IForeignKeyConstraint.js.map +1 -0
- package/dist/decorators/Relate.d.ts +5 -0
- package/dist/decorators/Relate.d.ts.map +1 -1
- package/dist/decorators/Relate.js +2 -1
- package/dist/decorators/Relate.js.map +1 -1
- package/dist/drivers/base/BaseDriver.d.ts +2 -1
- package/dist/drivers/base/BaseDriver.d.ts.map +1 -1
- package/dist/drivers/base/BaseDriver.js +60 -1
- package/dist/drivers/base/BaseDriver.js.map +1 -1
- package/dist/drivers/sql-server/ExpressionToSqlServer.d.ts +2 -1
- package/dist/drivers/sql-server/ExpressionToSqlServer.d.ts.map +1 -1
- package/dist/drivers/sql-server/ExpressionToSqlServer.js +35 -2
- package/dist/drivers/sql-server/ExpressionToSqlServer.js.map +1 -1
- package/dist/entity-query/EntityType.d.ts.map +1 -1
- package/dist/entity-query/EntityType.js +8 -0
- package/dist/entity-query/EntityType.js.map +1 -1
- package/dist/migrations/Migrations.d.ts +3 -1
- package/dist/migrations/Migrations.d.ts.map +1 -1
- package/dist/migrations/Migrations.js +17 -0
- package/dist/migrations/Migrations.js.map +1 -1
- package/dist/migrations/postgres/PostgresAutomaticMigrations.d.ts +2 -0
- package/dist/migrations/postgres/PostgresAutomaticMigrations.d.ts.map +1 -1
- package/dist/migrations/postgres/PostgresAutomaticMigrations.js +39 -0
- package/dist/migrations/postgres/PostgresAutomaticMigrations.js.map +1 -1
- package/dist/migrations/sql-server/SqlServerAutomaticMigrations.d.ts +2 -0
- package/dist/migrations/sql-server/SqlServerAutomaticMigrations.d.ts.map +1 -1
- package/dist/migrations/sql-server/SqlServerAutomaticMigrations.js +39 -0
- package/dist/migrations/sql-server/SqlServerAutomaticMigrations.js.map +1 -1
- package/dist/model/EntitySource.d.ts +2 -0
- package/dist/model/EntitySource.d.ts.map +1 -1
- package/dist/model/EntitySource.js +7 -0
- package/dist/model/EntitySource.js.map +1 -1
- package/dist/query/ast/ExpressionToSql.d.ts +2 -1
- package/dist/query/ast/ExpressionToSql.d.ts.map +1 -1
- package/dist/query/ast/ExpressionToSql.js +28 -1
- package/dist/query/ast/ExpressionToSql.js.map +1 -1
- package/dist/query/ast/Expressions.d.ts +8 -1
- package/dist/query/ast/Expressions.d.ts.map +1 -1
- package/dist/query/ast/Expressions.js +6 -0
- package/dist/query/ast/Expressions.js.map +1 -1
- package/dist/query/ast/Visitor.d.ts +2 -1
- package/dist/query/ast/Visitor.d.ts.map +1 -1
- package/dist/query/ast/Visitor.js +5 -0
- package/dist/query/ast/Visitor.js.map +1 -1
- package/dist/tests/model/ShoppingContext.d.ts.map +1 -1
- package/dist/tests/model/ShoppingContext.js +4 -1
- package/dist/tests/model/ShoppingContext.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/workflows/WorkflowContext.d.ts +15 -12
- package/dist/workflows/WorkflowContext.d.ts.map +1 -1
- package/dist/workflows/WorkflowContext.js +6 -5
- package/dist/workflows/WorkflowContext.js.map +1 -1
- package/dist/workflows/WorkflowStorage.d.ts +7 -2
- package/dist/workflows/WorkflowStorage.d.ts.map +1 -1
- package/dist/workflows/WorkflowStorage.js +33 -20
- package/dist/workflows/WorkflowStorage.js.map +1 -1
- package/package.json +3 -3
- package/src/decorators/IColumn.ts +3 -0
- package/src/decorators/IForeignKeyConstraint.ts +19 -0
- package/src/decorators/Relate.ts +8 -1
- package/src/drivers/base/BaseDriver.ts +70 -1
- package/src/drivers/sql-server/ExpressionToSqlServer.ts +45 -3
- package/src/entity-query/EntityType.ts +9 -0
- package/src/migrations/Migrations.ts +25 -2
- package/src/migrations/postgres/PostgresAutomaticMigrations.ts +50 -0
- package/src/migrations/sql-server/SqlServerAutomaticMigrations.ts +47 -0
- package/src/model/EntitySource.ts +13 -1
- package/src/query/ast/ExpressionToSql.ts +37 -2
- package/src/query/ast/Expressions.ts +10 -1
- package/src/query/ast/Visitor.ts +6 -1
- package/src/tests/model/ShoppingContext.ts +4 -1
- package/src/workflows/WorkflowContext.ts +25 -10
- package/src/workflows/WorkflowStorage.ts +36 -23
- package/tsconfig.json +1 -1
|
@@ -3,7 +3,7 @@ import EntityType, { IEntityProperty } from "../../entity-query/EntityType.js";
|
|
|
3
3
|
import EntityQuery from "../../model/EntityQuery.js";
|
|
4
4
|
import { FilteredExpression, filteredSymbol } from "../../model/events/FilteredExpression.js";
|
|
5
5
|
import { NotSupportedError } from "../parser/NotSupportedError.js";
|
|
6
|
-
import { ArrowFunctionExpression, BigIntLiteral, BinaryExpression, BooleanLiteral, CallExpression, CoalesceExpression, ConditionalExpression, Constant, DeleteStatement, ExistsExpression, Expression, ExpressionAs, ExpressionType, Identifier, InsertStatement, JoinExpression, MemberExpression, NewObjectExpression, NotExits, NullExpression, NumberLiteral, OrderByExpression, ParameterExpression, ReturnUpdated, SelectStatement, StringLiteral, TableLiteral, TemplateLiteral, UnionAllStatement, UpdateStatement, ValuesStatement } from "./Expressions.js";
|
|
6
|
+
import { ArrowFunctionExpression, BigIntLiteral, BinaryExpression, BooleanLiteral, CallExpression, CoalesceExpression, ConditionalExpression, Constant, DeleteStatement, ExistsExpression, Expression, ExpressionAs, ExpressionType, Identifier, InsertStatement, JoinExpression, MemberExpression, UpsertStatement, NewObjectExpression, NotExits, NullExpression, NumberLiteral, OrderByExpression, ParameterExpression, ReturnUpdated, SelectStatement, StringLiteral, TableLiteral, TemplateLiteral, UnionAllStatement, UpdateStatement, ValuesStatement } from "./Expressions.js";
|
|
7
7
|
import { ITextQuery, QueryParameter, prepare, prepareJoin } from "./IStringTransformer.js";
|
|
8
8
|
import ParameterScope from "./ParameterScope.js";
|
|
9
9
|
import Visitor from "./Visitor.js";
|
|
@@ -457,7 +457,7 @@ export default class ExpressionToSql extends Visitor<ITextQuery> {
|
|
|
457
457
|
}
|
|
458
458
|
|
|
459
459
|
visitInsertStatement(e: InsertStatement): ITextQuery {
|
|
460
|
-
const returnValues = this.visit(e.returnValues);
|
|
460
|
+
const returnValues = e.returnValues ? this.visit(e.returnValues) : [];
|
|
461
461
|
if (e.values instanceof ValuesStatement) {
|
|
462
462
|
|
|
463
463
|
const rows = [];
|
|
@@ -490,6 +490,41 @@ export default class ExpressionToSql extends Visitor<ITextQuery> {
|
|
|
490
490
|
return prepare `UPDATE ${table} SET ${set} WHERE ${where}`;
|
|
491
491
|
}
|
|
492
492
|
|
|
493
|
+
visitUpsertStatement(e: UpsertStatement): ITextQuery {
|
|
494
|
+
const table = this.visit(e.table);
|
|
495
|
+
|
|
496
|
+
const insertColumns = [];
|
|
497
|
+
const insertValues = [];
|
|
498
|
+
const updateSet = [];
|
|
499
|
+
|
|
500
|
+
const compare = [];
|
|
501
|
+
|
|
502
|
+
for (const { left, right } of e.insert) {
|
|
503
|
+
const c = this.visit(left);
|
|
504
|
+
const v = this.visit(right);
|
|
505
|
+
insertColumns.push(c);
|
|
506
|
+
insertValues.push(v);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
for (const { left, right } of e.update) {
|
|
510
|
+
const c = this.visit(left);
|
|
511
|
+
const v = this.visit(right);
|
|
512
|
+
updateSet.push(prepare `${c} = ${v}`);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
for (const { left, right } of e.keys) {
|
|
516
|
+
const c = this.visit(left);
|
|
517
|
+
compare.push(c);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
return prepare `INSERT INTO ${table} (${prepareJoin(insertColumns)})
|
|
522
|
+
VALUES (${prepareJoin(insertValues)})
|
|
523
|
+
ON CONFLICT(${prepareJoin(compare)})
|
|
524
|
+
DO UPDATE SET
|
|
525
|
+
${prepareJoin(updateSet)} `;
|
|
526
|
+
}
|
|
527
|
+
|
|
493
528
|
visitNewObjectExpression(e: NewObjectExpression): ITextQuery {
|
|
494
529
|
return prepare `FROM (${this.visitArray(e.properties)})`;
|
|
495
530
|
}
|
|
@@ -392,6 +392,14 @@ export class UpdateStatement extends Expression {
|
|
|
392
392
|
|
|
393
393
|
}
|
|
394
394
|
|
|
395
|
+
export class UpsertStatement extends Expression {
|
|
396
|
+
readonly type = "UpsertStatement";
|
|
397
|
+
table: TableLiteral | Identifier;
|
|
398
|
+
insert: BinaryExpression[];
|
|
399
|
+
update: BinaryExpression[];
|
|
400
|
+
keys: BinaryExpression[];
|
|
401
|
+
}
|
|
402
|
+
|
|
395
403
|
export class UnionAllStatement extends Expression {
|
|
396
404
|
readonly type = "UnionAllStatement";
|
|
397
405
|
queries: Expression[];
|
|
@@ -399,7 +407,7 @@ export class UnionAllStatement extends Expression {
|
|
|
399
407
|
|
|
400
408
|
export class DeleteStatement extends Expression {
|
|
401
409
|
readonly type = "DeleteStatement";
|
|
402
|
-
table: TableLiteral | Identifier
|
|
410
|
+
table: TableLiteral | Identifier;
|
|
403
411
|
where: Expression;
|
|
404
412
|
}
|
|
405
413
|
|
|
@@ -414,6 +422,7 @@ export type ExpressionType =
|
|
|
414
422
|
InsertStatement|
|
|
415
423
|
UpdateStatement|
|
|
416
424
|
DeleteStatement|
|
|
425
|
+
UpsertStatement|
|
|
417
426
|
ReturnUpdated|
|
|
418
427
|
OrderByExpression|
|
|
419
428
|
JoinExpression|
|
package/src/query/ast/Visitor.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NotSupportedError } from "../parser/NotSupportedError.js";
|
|
2
|
-
import { ArrayExpression, ArrowFunctionExpression, BigIntLiteral, BinaryExpression, BooleanLiteral, CallExpression, CoalesceExpression, ConditionalExpression, Constant, DeleteStatement, ExistsExpression, Expression, ExpressionAs, ExpressionType, Identifier, InsertStatement, JoinExpression, MemberExpression, NewObjectExpression, NotExits, NullExpression, NumberLiteral, OrderByExpression, ParameterExpression, ReturnUpdated, SelectStatement, StringLiteral, TableLiteral, TemplateElement, TemplateLiteral, UnionAllStatement, UpdateStatement, ValuesStatement } from "./Expressions.js";
|
|
2
|
+
import { ArrayExpression, ArrowFunctionExpression, BigIntLiteral, BinaryExpression, BooleanLiteral, CallExpression, CoalesceExpression, ConditionalExpression, Constant, DeleteStatement, ExistsExpression, Expression, ExpressionAs, ExpressionType, Identifier, InsertStatement, JoinExpression, MemberExpression, UpsertStatement, NewObjectExpression, NotExits, NullExpression, NumberLiteral, OrderByExpression, ParameterExpression, ReturnUpdated, SelectStatement, StringLiteral, TableLiteral, TemplateElement, TemplateLiteral, UnionAllStatement, UpdateStatement, ValuesStatement } from "./Expressions.js";
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
export default abstract class Visitor<T = any> {
|
|
@@ -71,10 +71,15 @@ export default abstract class Visitor<T = any> {
|
|
|
71
71
|
return this.visitNotExists(e);
|
|
72
72
|
case "UnionAllStatement":
|
|
73
73
|
return this.visitUnionAllStatement(e);
|
|
74
|
+
case "UpsertStatement":
|
|
75
|
+
return this.visitUpsertStatement(e);
|
|
74
76
|
}
|
|
75
77
|
const c: never = e;
|
|
76
78
|
throw new Error(`${e1.type} Not implemented`);
|
|
77
79
|
}
|
|
80
|
+
visitUpsertStatement(e: UpsertStatement): T {
|
|
81
|
+
throw new Error("Method not implemented.");
|
|
82
|
+
}
|
|
78
83
|
visitUnionAllStatement(e: UnionAllStatement): T {
|
|
79
84
|
throw new NotSupportedError("Union All");
|
|
80
85
|
}
|
|
@@ -297,7 +297,10 @@ export class OrderItem {
|
|
|
297
297
|
@RelateTo({
|
|
298
298
|
type: () => Order,
|
|
299
299
|
property: (orderItem) => orderItem.order,
|
|
300
|
-
inverseProperty: (order) => order.orderItems
|
|
300
|
+
inverseProperty: (order) => order.orderItems,
|
|
301
|
+
foreignKeyConstraint: {
|
|
302
|
+
cascade: "delete"
|
|
303
|
+
}
|
|
301
304
|
})
|
|
302
305
|
public orderID: number;
|
|
303
306
|
|
|
@@ -129,6 +129,19 @@ export interface IWorkflowResult<T> {
|
|
|
129
129
|
error: string;
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
export interface IWorkflowQueueParameter {
|
|
133
|
+
id?: string;
|
|
134
|
+
throwIfExists?: boolean;
|
|
135
|
+
eta?: DateTime;
|
|
136
|
+
parentID?: string;
|
|
137
|
+
taskGroup?: string;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export interface IWorkflowStartParams {
|
|
141
|
+
taskGroup?: string;
|
|
142
|
+
signal?: AbortSignal;
|
|
143
|
+
}
|
|
144
|
+
|
|
132
145
|
export default class WorkflowContext {
|
|
133
146
|
|
|
134
147
|
private registry: Map<string, IWorkflowSchema> = new Map();
|
|
@@ -144,11 +157,11 @@ export default class WorkflowContext {
|
|
|
144
157
|
this.registry.set(type.name, WorkflowRegistry.register(type, void 0));
|
|
145
158
|
}
|
|
146
159
|
|
|
147
|
-
public async start({
|
|
160
|
+
public async start({ taskGroup = "default", signal = void 0 as AbortSignal }: IWorkflowStartParams = {}) {
|
|
148
161
|
console.log(`Started executing workflow jobs`);
|
|
149
162
|
while(!signal?.aborted) {
|
|
150
163
|
try {
|
|
151
|
-
const total = await this.processQueueOnce({
|
|
164
|
+
const total = await this.processQueueOnce({ taskGroup, signal });
|
|
152
165
|
if (total > 0) {
|
|
153
166
|
// do not wait till we have zero messages to process
|
|
154
167
|
continue;
|
|
@@ -177,12 +190,13 @@ export default class WorkflowContext {
|
|
|
177
190
|
public async queue<T>(
|
|
178
191
|
type: IClassOf<Workflow<T>>,
|
|
179
192
|
input: T,
|
|
180
|
-
{
|
|
181
|
-
id
|
|
182
|
-
throwIfExists
|
|
183
|
-
eta
|
|
184
|
-
parentID
|
|
185
|
-
|
|
193
|
+
{
|
|
194
|
+
id,
|
|
195
|
+
throwIfExists,
|
|
196
|
+
eta,
|
|
197
|
+
parentID,
|
|
198
|
+
taskGroup = "default"
|
|
199
|
+
}: IWorkflowQueueParameter = {}) {
|
|
186
200
|
const clock = this.storage.clock;
|
|
187
201
|
let tries = 1;
|
|
188
202
|
if (id) {
|
|
@@ -215,6 +229,7 @@ export default class WorkflowContext {
|
|
|
215
229
|
eta ??= now;
|
|
216
230
|
await this.storage.save({
|
|
217
231
|
id,
|
|
232
|
+
taskGroup,
|
|
218
233
|
name: schema.name,
|
|
219
234
|
input: JSON.stringify(input),
|
|
220
235
|
isWorkflow: true,
|
|
@@ -272,8 +287,8 @@ export default class WorkflowContext {
|
|
|
272
287
|
// console.log(... a);
|
|
273
288
|
}
|
|
274
289
|
|
|
275
|
-
public async processQueueOnce({
|
|
276
|
-
const pending = await this.storage.dequeue(
|
|
290
|
+
public async processQueueOnce({ taskGroup = "default", signal = void 0 as AbortSignal } = {}) {
|
|
291
|
+
const pending = await this.storage.dequeue(taskGroup, signal);
|
|
277
292
|
// run...
|
|
278
293
|
for (const iterator of pending) {
|
|
279
294
|
try {
|
|
@@ -10,6 +10,8 @@ import DateTime from "../types/DateTime.js";
|
|
|
10
10
|
import WorkflowClock from "./WorkflowClock.js";
|
|
11
11
|
import RawQuery from "../compiler/RawQuery.js";
|
|
12
12
|
|
|
13
|
+
const loadedFromDb = Symbol("loadedFromDB");
|
|
14
|
+
|
|
13
15
|
@Table("Workflows")
|
|
14
16
|
@Index({
|
|
15
17
|
name: "IX_Workflows_Group",
|
|
@@ -17,10 +19,10 @@ import RawQuery from "../compiler/RawQuery.js";
|
|
|
17
19
|
filter: (x) => x.groupName !== null
|
|
18
20
|
})
|
|
19
21
|
@Index({
|
|
20
|
-
name: "
|
|
22
|
+
name: "IX_Workflows_taskGroup_ETA",
|
|
21
23
|
columns: [
|
|
22
24
|
{ name: (x) => x.eta, descending: false },
|
|
23
|
-
{ name: (x) => x.
|
|
25
|
+
{ name: (x) => x.taskGroup, descending: false }
|
|
24
26
|
],
|
|
25
27
|
filter: (x) => x.isWorkflow === true
|
|
26
28
|
})
|
|
@@ -57,7 +59,7 @@ export class WorkflowItem {
|
|
|
57
59
|
dataType: "Char", length: 50,
|
|
58
60
|
default: () => `default`
|
|
59
61
|
})
|
|
60
|
-
public
|
|
62
|
+
public taskGroup: string;
|
|
61
63
|
|
|
62
64
|
@Column({ dataType: "Int", default: () => 0})
|
|
63
65
|
public priority: number;
|
|
@@ -124,7 +126,9 @@ export default class WorkflowStorage {
|
|
|
124
126
|
state: r.state,
|
|
125
127
|
output: r.output,
|
|
126
128
|
error: r.error,
|
|
127
|
-
lastID: r.lastID
|
|
129
|
+
lastID: r.lastID,
|
|
130
|
+
taskGroup: r.taskGroup,
|
|
131
|
+
[loadedFromDb]: true,
|
|
128
132
|
};
|
|
129
133
|
}
|
|
130
134
|
return null;
|
|
@@ -146,7 +150,8 @@ export default class WorkflowStorage {
|
|
|
146
150
|
state: r.state,
|
|
147
151
|
output: r.output,
|
|
148
152
|
error: r.error,
|
|
149
|
-
lastID: r.lastID
|
|
153
|
+
lastID: r.lastID,
|
|
154
|
+
[loadedFromDb]: true
|
|
150
155
|
};
|
|
151
156
|
}
|
|
152
157
|
return null;
|
|
@@ -185,26 +190,34 @@ export default class WorkflowStorage {
|
|
|
185
190
|
const db = new WorkflowContext(this.driver);
|
|
186
191
|
const connection = db.connection;
|
|
187
192
|
await connection.runInTransaction(async () => {
|
|
188
|
-
let w = await db.workflows.where(state, (p) => (x) => x.id === p.id).first();
|
|
189
|
-
if (!w) {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
193
|
+
// let w = await db.workflows.where(state, (p) => (x) => x.id === p.id).first();
|
|
194
|
+
// if (!w) {
|
|
195
|
+
// w = db.workflows.add(state);
|
|
196
|
+
// w.taskGroup ||= "default";
|
|
197
|
+
// }
|
|
198
|
+
|
|
199
|
+
// for (const key in state) {
|
|
200
|
+
// if (Object.prototype.hasOwnProperty.call(state, key)) {
|
|
201
|
+
// const element = state[key];
|
|
202
|
+
// w[key] = element;
|
|
203
|
+
// }
|
|
204
|
+
// }
|
|
205
|
+
|
|
206
|
+
// w.state ||= "queued";
|
|
207
|
+
// w.updated ??= DateTime.utcNow;
|
|
208
|
+
state.state ||= "queued";
|
|
209
|
+
state.updated ??= DateTime.utcNow;
|
|
210
|
+
state.taskGroup ||= "default";
|
|
211
|
+
// await db.saveChanges();
|
|
212
|
+
if(state[loadedFromDb]) {
|
|
213
|
+
await db.workflows.saveDirect(state, "update");
|
|
214
|
+
} else {
|
|
215
|
+
await db.workflows.saveDirect(state, "upsert");
|
|
198
216
|
}
|
|
199
|
-
|
|
200
|
-
w.state ||= "queued";
|
|
201
|
-
w.workerGroup ||= "default";
|
|
202
|
-
w.updated ??= DateTime.utcNow;
|
|
203
|
-
await db.saveChanges();
|
|
204
217
|
});
|
|
205
218
|
}
|
|
206
219
|
|
|
207
|
-
async dequeue(
|
|
220
|
+
async dequeue(taskGroup: string, signal?: AbortSignal) {
|
|
208
221
|
const db = new WorkflowContext(this.driver);
|
|
209
222
|
const now = this.clock.utcNow;
|
|
210
223
|
|
|
@@ -250,11 +263,11 @@ export default class WorkflowStorage {
|
|
|
250
263
|
const q = this.lockQuery;
|
|
251
264
|
|
|
252
265
|
const items = await db.workflows
|
|
253
|
-
.where({now,
|
|
266
|
+
.where({now, taskGroup}, (p) => (x) => x.eta <= p.now
|
|
254
267
|
&& (x.lockedTTL === null || x.lockedTTL <= p.now)
|
|
255
268
|
&& x.lockToken === null
|
|
256
269
|
&& x.isWorkflow === true
|
|
257
|
-
&& x.
|
|
270
|
+
&& x.taskGroup === p.taskGroup)
|
|
258
271
|
.orderBy({}, (p) => (x) => x.eta)
|
|
259
272
|
.thenBy({}, (p) => (x) => x.priority)
|
|
260
273
|
.limit(20)
|