@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.
Files changed (79) hide show
  1. package/dist/decorators/IColumn.d.ts +2 -0
  2. package/dist/decorators/IColumn.d.ts.map +1 -1
  3. package/dist/decorators/IForeignKeyConstraint.d.ts +12 -0
  4. package/dist/decorators/IForeignKeyConstraint.d.ts.map +1 -0
  5. package/dist/decorators/IForeignKeyConstraint.js +2 -0
  6. package/dist/decorators/IForeignKeyConstraint.js.map +1 -0
  7. package/dist/decorators/Relate.d.ts +5 -0
  8. package/dist/decorators/Relate.d.ts.map +1 -1
  9. package/dist/decorators/Relate.js +2 -1
  10. package/dist/decorators/Relate.js.map +1 -1
  11. package/dist/drivers/base/BaseDriver.d.ts +2 -1
  12. package/dist/drivers/base/BaseDriver.d.ts.map +1 -1
  13. package/dist/drivers/base/BaseDriver.js +60 -1
  14. package/dist/drivers/base/BaseDriver.js.map +1 -1
  15. package/dist/drivers/sql-server/ExpressionToSqlServer.d.ts +2 -1
  16. package/dist/drivers/sql-server/ExpressionToSqlServer.d.ts.map +1 -1
  17. package/dist/drivers/sql-server/ExpressionToSqlServer.js +35 -2
  18. package/dist/drivers/sql-server/ExpressionToSqlServer.js.map +1 -1
  19. package/dist/entity-query/EntityType.d.ts.map +1 -1
  20. package/dist/entity-query/EntityType.js +8 -0
  21. package/dist/entity-query/EntityType.js.map +1 -1
  22. package/dist/migrations/Migrations.d.ts +3 -1
  23. package/dist/migrations/Migrations.d.ts.map +1 -1
  24. package/dist/migrations/Migrations.js +17 -0
  25. package/dist/migrations/Migrations.js.map +1 -1
  26. package/dist/migrations/postgres/PostgresAutomaticMigrations.d.ts +2 -0
  27. package/dist/migrations/postgres/PostgresAutomaticMigrations.d.ts.map +1 -1
  28. package/dist/migrations/postgres/PostgresAutomaticMigrations.js +39 -0
  29. package/dist/migrations/postgres/PostgresAutomaticMigrations.js.map +1 -1
  30. package/dist/migrations/sql-server/SqlServerAutomaticMigrations.d.ts +2 -0
  31. package/dist/migrations/sql-server/SqlServerAutomaticMigrations.d.ts.map +1 -1
  32. package/dist/migrations/sql-server/SqlServerAutomaticMigrations.js +39 -0
  33. package/dist/migrations/sql-server/SqlServerAutomaticMigrations.js.map +1 -1
  34. package/dist/model/EntitySource.d.ts +2 -0
  35. package/dist/model/EntitySource.d.ts.map +1 -1
  36. package/dist/model/EntitySource.js +7 -0
  37. package/dist/model/EntitySource.js.map +1 -1
  38. package/dist/query/ast/ExpressionToSql.d.ts +2 -1
  39. package/dist/query/ast/ExpressionToSql.d.ts.map +1 -1
  40. package/dist/query/ast/ExpressionToSql.js +28 -1
  41. package/dist/query/ast/ExpressionToSql.js.map +1 -1
  42. package/dist/query/ast/Expressions.d.ts +8 -1
  43. package/dist/query/ast/Expressions.d.ts.map +1 -1
  44. package/dist/query/ast/Expressions.js +6 -0
  45. package/dist/query/ast/Expressions.js.map +1 -1
  46. package/dist/query/ast/Visitor.d.ts +2 -1
  47. package/dist/query/ast/Visitor.d.ts.map +1 -1
  48. package/dist/query/ast/Visitor.js +5 -0
  49. package/dist/query/ast/Visitor.js.map +1 -1
  50. package/dist/tests/model/ShoppingContext.d.ts.map +1 -1
  51. package/dist/tests/model/ShoppingContext.js +4 -1
  52. package/dist/tests/model/ShoppingContext.js.map +1 -1
  53. package/dist/tsconfig.tsbuildinfo +1 -1
  54. package/dist/workflows/WorkflowContext.d.ts +15 -12
  55. package/dist/workflows/WorkflowContext.d.ts.map +1 -1
  56. package/dist/workflows/WorkflowContext.js +6 -5
  57. package/dist/workflows/WorkflowContext.js.map +1 -1
  58. package/dist/workflows/WorkflowStorage.d.ts +7 -2
  59. package/dist/workflows/WorkflowStorage.d.ts.map +1 -1
  60. package/dist/workflows/WorkflowStorage.js +33 -20
  61. package/dist/workflows/WorkflowStorage.js.map +1 -1
  62. package/package.json +3 -3
  63. package/src/decorators/IColumn.ts +3 -0
  64. package/src/decorators/IForeignKeyConstraint.ts +19 -0
  65. package/src/decorators/Relate.ts +8 -1
  66. package/src/drivers/base/BaseDriver.ts +70 -1
  67. package/src/drivers/sql-server/ExpressionToSqlServer.ts +45 -3
  68. package/src/entity-query/EntityType.ts +9 -0
  69. package/src/migrations/Migrations.ts +25 -2
  70. package/src/migrations/postgres/PostgresAutomaticMigrations.ts +50 -0
  71. package/src/migrations/sql-server/SqlServerAutomaticMigrations.ts +47 -0
  72. package/src/model/EntitySource.ts +13 -1
  73. package/src/query/ast/ExpressionToSql.ts +37 -2
  74. package/src/query/ast/Expressions.ts +10 -1
  75. package/src/query/ast/Visitor.ts +6 -1
  76. package/src/tests/model/ShoppingContext.ts +4 -1
  77. package/src/workflows/WorkflowContext.ts +25 -10
  78. package/src/workflows/WorkflowStorage.ts +36 -23
  79. 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|
@@ -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({ workerGroup = "default", signal = void 0 as AbortSignal }) {
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({ workerGroup, signal });
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
- { id, throwIfExists, eta, parentID }: {
181
- id?: string,
182
- throwIfExists?: boolean,
183
- eta?: DateTime,
184
- parentID?: string
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({ workerGroup = "default", signal = void 0 as AbortSignal } = {}) {
276
- const pending = await this.storage.dequeue(workerGroup, signal);
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: "IX_Workflows_WorkerGroup_ETA",
22
+ name: "IX_Workflows_taskGroup_ETA",
21
23
  columns: [
22
24
  { name: (x) => x.eta, descending: false },
23
- { name: (x) => x.workerGroup, descending: false }
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 workerGroup: string;
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
- w = db.workflows.add(state);
191
- }
192
-
193
- for (const key in state) {
194
- if (Object.prototype.hasOwnProperty.call(state, key)) {
195
- const element = state[key];
196
- w[key] = element;
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(workerGroup: string, signal?: AbortSignal) {
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, workerGroup}, (p) => (x) => x.eta <= p.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.workerGroup === p.workerGroup)
270
+ && x.taskGroup === p.taskGroup)
258
271
  .orderBy({}, (p) => (x) => x.eta)
259
272
  .thenBy({}, (p) => (x) => x.priority)
260
273
  .limit(20)
package/tsconfig.json CHANGED
@@ -13,7 +13,7 @@
13
13
  "emitDecoratorMetadata": true,
14
14
  "lib": [
15
15
  "ES2018",
16
- "esnext.disposable"
16
+ "ESNext.Disposable"
17
17
  ]
18
18
  },
19
19
  "include": [