@ruiapp/rapid-core 0.11.6 → 0.11.8

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.
@@ -40,6 +40,8 @@ declare class PluginManager {
40
40
  beforeRunRouteActions(handlerContext: ActionHandlerContext): Promise<void>;
41
41
  /** 在执行 action hanlder 前调用。 */
42
42
  beforeRunActionHandler(handlerContext: ActionHandlerContext, actionConfig: RpdRouteActionConfig): Promise<void>;
43
+ /** 在执行 action handler 后调用。 */
44
+ afterRunActionHandler(handlerContext: ActionHandlerContext, actionConfig: RpdRouteActionConfig, error?: Error): Promise<void>;
43
45
  /** 在创建实体前调用。 */
44
46
  beforeCreateEntity(model: RpdDataModel, options: CreateEntityOptions): Promise<void>;
45
47
  /** 在更新实体前调用。 */
@@ -34,6 +34,7 @@ export interface IRpdServer {
34
34
  runActionHandlers(handlerContext: ActionHandlerContext, actions: RpdRouteActionConfig[]): Promise<void>;
35
35
  beforeRunRouteActions(handlerContext: ActionHandlerContext): Promise<void>;
36
36
  beforeRunActionHandler(handlerContext: ActionHandlerContext, actionConfig: RpdRouteActionConfig): Promise<void>;
37
+ afterRunActionHandler(handlerContext: ActionHandlerContext, actionConfig: RpdRouteActionConfig, error?: Error): Promise<void>;
37
38
  beforeCreateEntity(model: RpdDataModel, options: CreateEntityOptions): Promise<void>;
38
39
  beforeUpdateEntity(model: RpdDataModel, options: UpdateEntityByIdOptions, currentEntity: any): Promise<void>;
39
40
  registerCronJob(job: CronJobConfiguration): void;
@@ -112,6 +113,8 @@ export interface RapidPlugin {
112
113
  beforeRunRouteActions?: (server: IRpdServer, handlerContext: ActionHandlerContext) => Promise<any>;
113
114
  /** 在执行 action hanlder 前调用。 */
114
115
  beforeRunActionHandler?: (server: IRpdServer, handlerContext: ActionHandlerContext, actionConfig: RpdRouteActionConfig) => Promise<any>;
116
+ /** 在执行 action handler 后调用。 */
117
+ afterRunActionHandler?: (server: IRpdServer, handlerContext: ActionHandlerContext, actionConfig: RpdRouteActionConfig, error?: Error) => Promise<any>;
115
118
  /** 在创建实体前调用。 */
116
119
  beforeCreateEntity?: (server: IRpdServer, model: RpdDataModel, options: CreateEntityOptions) => Promise<any>;
117
120
  /** 在更新实体前调用。 */
@@ -33,7 +33,7 @@ export default class EntityManager<TEntity = any> {
33
33
  createEntity(options: CreateEntityOptions, plugin?: RapidPlugin): Promise<TEntity>;
34
34
  updateEntityById(options: UpdateEntityByIdOptions, plugin?: RapidPlugin): Promise<TEntity>;
35
35
  count(options: CountEntityOptions): Promise<number>;
36
- deleteById(options: DeleteEntityByIdOptions | string | number, plugin?: RapidPlugin): Promise<void>;
37
- addRelations(options: AddEntityRelationsOptions, plugin?: RapidPlugin): Promise<void>;
38
- removeRelations(options: RemoveEntityRelationsOptions, plugin?: RapidPlugin): Promise<void>;
36
+ deleteById(options: DeleteEntityByIdOptions | string | number, plugin?: RapidPlugin): Promise<TEntity>;
37
+ addRelations(options: AddEntityRelationsOptions, plugin?: RapidPlugin): Promise<any>;
38
+ removeRelations(options: RemoveEntityRelationsOptions, plugin?: RapidPlugin): Promise<any>;
39
39
  }
package/dist/index.js CHANGED
@@ -936,6 +936,14 @@ class PluginManager {
936
936
  }
937
937
  }
938
938
  }
939
+ /** 在执行 action handler 后调用。 */
940
+ async afterRunActionHandler(handlerContext, actionConfig, error) {
941
+ for (const plugin of this.#plugins) {
942
+ if (plugin.afterRunActionHandler) {
943
+ await plugin.afterRunActionHandler(this.#server, handlerContext, actionConfig, error);
944
+ }
945
+ }
946
+ }
939
947
  /** 在创建实体前调用。 */
940
948
  async beforeCreateEntity(model, options) {
941
949
  for (const plugin of this.#plugins) {
@@ -1044,9 +1052,19 @@ async function executeHandlerOfActions(server, routeConfig, handlerContext) {
1044
1052
  throw new Error("Unknown handler: " + actionCode);
1045
1053
  }
1046
1054
  await server.beforeRunActionHandler(handlerContext, actionConfig);
1047
- const result = handler(handlerContext, actionConfig.config);
1048
- if (result instanceof Promise) {
1049
- await result;
1055
+ let err;
1056
+ try {
1057
+ const result = handler(handlerContext, actionConfig.config);
1058
+ if (result instanceof Promise) {
1059
+ await result;
1060
+ }
1061
+ }
1062
+ catch (error) {
1063
+ err = error;
1064
+ throw error;
1065
+ }
1066
+ finally {
1067
+ await server.afterRunActionHandler(handlerContext, actionConfig, err);
1050
1068
  }
1051
1069
  }
1052
1070
  }
@@ -2957,6 +2975,17 @@ async function findEntities(server, dataAccessor, options) {
2957
2975
  else {
2958
2976
  propertiesToSelect = getEntityPropertiesIncludingBase(server, model).filter((property) => options.properties.includes(property.code) || relationPropertyCodes.includes(property.code));
2959
2977
  }
2978
+ const isEntitySoftDeleteEnabled = baseModel ? baseModel.softDelete || model.softDelete : model.softDelete;
2979
+ if (options.includingSoftDeleted && isEntitySoftDeleteEnabled) {
2980
+ const deletedAtProp = getEntityPropertyByCode(server, model, "deletedAt");
2981
+ if (deletedAtProp && !lodash.find(propertiesToSelect, (p) => p.code === "deletedAt")) {
2982
+ propertiesToSelect.push(deletedAtProp);
2983
+ }
2984
+ const deletedByProp = getEntityPropertyByCode(server, model, "deletedBy");
2985
+ if (deletedByProp && !lodash.find(propertiesToSelect, (p) => p.code === "deletedBy")) {
2986
+ propertiesToSelect.push(deletedByProp);
2987
+ }
2988
+ }
2960
2989
  const columnsToSelect = [];
2961
2990
  const relationPropertiesToSelect = [];
2962
2991
  lodash.forEach(propertiesToSelect, (property) => {
@@ -3174,7 +3203,7 @@ const UNDELETED_ENTITY_FILTER_OPTIONS = {
3174
3203
  field: "deletedAt",
3175
3204
  };
3176
3205
  function tryAddUndeletedEntityFilter(model, baseModel, filters) {
3177
- let isEntitySoftDeleteEnabled = baseModel ? (baseModel.softDelete || model.softDelete) : model.softDelete;
3206
+ let isEntitySoftDeleteEnabled = baseModel ? baseModel.softDelete || model.softDelete : model.softDelete;
3178
3207
  if (!isEntitySoftDeleteEnabled) {
3179
3208
  return filters;
3180
3209
  }
@@ -3426,6 +3455,7 @@ async function findManyRelationLinksViaLinkTable(options) {
3426
3455
  },
3427
3456
  ],
3428
3457
  keepNonPropertyFields: true,
3458
+ includingSoftDeleted: true,
3429
3459
  };
3430
3460
  if (selectRelationOptions) {
3431
3461
  if (typeof selectRelationOptions !== "boolean") {
@@ -3479,6 +3509,7 @@ async function findManyRelatedEntitiesViaIdPropertyCode(options) {
3479
3509
  ],
3480
3510
  extraColumnsToSelect: [relationProperty.selfIdColumnName],
3481
3511
  keepNonPropertyFields: true,
3512
+ includingSoftDeleted: true,
3482
3513
  };
3483
3514
  if (selectRelationOptions) {
3484
3515
  if (typeof selectRelationOptions !== "boolean") {
@@ -3522,6 +3553,7 @@ async function findOneRelatedEntitiesViaIdPropertyCode(options) {
3522
3553
  },
3523
3554
  ],
3524
3555
  keepNonPropertyFields: true,
3556
+ includingSoftDeleted: true,
3525
3557
  };
3526
3558
  if (selectRelationOptions) {
3527
3559
  if (typeof selectRelationOptions !== "boolean") {
@@ -4298,7 +4330,7 @@ async function deleteEntityById(server, dataAccessor, options, plugin) {
4298
4330
  if (!entity) {
4299
4331
  return;
4300
4332
  }
4301
- const isEntitySoftDeleteEnabled = model.base ? (baseModel.softDelete || model.softDelete) : model.softDelete;
4333
+ const isEntitySoftDeleteEnabled = model.base ? baseModel.softDelete || model.softDelete : model.softDelete;
4302
4334
  if (isEntitySoftDeleteEnabled) {
4303
4335
  if (entity.deletedAt) {
4304
4336
  return;
@@ -4423,6 +4455,7 @@ async function deleteEntityById(server, dataAccessor, options, plugin) {
4423
4455
  sender: plugin,
4424
4456
  routeContext,
4425
4457
  });
4458
+ return entity;
4426
4459
  }
4427
4460
  class EntityManager {
4428
4461
  #server;
@@ -4491,6 +4524,8 @@ class EntityManager {
4491
4524
  throw new Error(`Operation 'addRelations' is only supported on property of 'many' relation`);
4492
4525
  }
4493
4526
  const { queryBuilder } = server;
4527
+ const targetEntityManager = server.getEntityManager(relationProperty.targetSingularCode);
4528
+ const relationTargetEntities = [];
4494
4529
  if (relationProperty.linkTableName) {
4495
4530
  for (const relation of relations) {
4496
4531
  const command = `INSERT INTO ${queryBuilder.quoteTable({
@@ -4504,17 +4539,24 @@ class EntityManager {
4504
4539
  )`;
4505
4540
  const targetId = relation[relationProperty.targetIdColumnName] || relation.id;
4506
4541
  const params = [selfId, targetId];
4507
- await server.queryDatabaseObject(command, params, routeContext?.getDbTransactionClient());
4542
+ const result = await server.queryDatabaseObject(command, params, routeContext?.getDbTransactionClient());
4543
+ if (result?.length > 0) {
4544
+ const targetEntity = await targetEntityManager.findById({
4545
+ routeContext,
4546
+ id: targetId,
4547
+ });
4548
+ relationTargetEntities.push(targetEntity);
4549
+ }
4508
4550
  }
4509
4551
  }
4510
4552
  else {
4511
- const targetEntityManager = server.getEntityManager(relationProperty.targetSingularCode);
4512
4553
  for (const relation of relations) {
4513
4554
  relation[relationProperty.selfIdColumnName] = selfId;
4514
- await targetEntityManager.createEntity({
4555
+ const targetEntity = await targetEntityManager.createEntity({
4515
4556
  routeContext,
4516
4557
  entity: relation,
4517
4558
  });
4559
+ relationTargetEntities.push(targetEntity);
4518
4560
  }
4519
4561
  }
4520
4562
  await server.emitEvent({
@@ -4525,10 +4567,17 @@ class EntityManager {
4525
4567
  entity,
4526
4568
  property,
4527
4569
  relations,
4570
+ relationTargetEntities,
4528
4571
  },
4529
4572
  sender: plugin,
4530
4573
  routeContext: options.routeContext,
4531
4574
  });
4575
+ return {
4576
+ entity,
4577
+ property,
4578
+ relations,
4579
+ relationTargetEntities,
4580
+ };
4532
4581
  }
4533
4582
  async removeRelations(options, plugin) {
4534
4583
  const server = this.#server;
@@ -4549,12 +4598,21 @@ class EntityManager {
4549
4598
  throw new Error(`Operation 'removeRelations' is only supported on property of 'many' relation`);
4550
4599
  }
4551
4600
  const { queryBuilder } = server;
4601
+ const targetEntityManager = server.getEntityManager(relationProperty.targetSingularCode);
4602
+ const relationTargetEntities = [];
4552
4603
  if (relationProperty.linkTableName) {
4553
4604
  for (const relation of relations) {
4554
4605
  const command = `DELETE FROM ${queryBuilder.quoteTable({ schema: relationProperty.linkSchema, tableName: relationProperty.linkTableName })}
4555
4606
  WHERE ${queryBuilder.quoteObject(relationProperty.selfIdColumnName)}=$1 AND ${queryBuilder.quoteObject(relationProperty.targetIdColumnName)}=$2;`;
4556
4607
  const params = [id, relation.id];
4557
- await server.queryDatabaseObject(command, params, routeContext?.getDbTransactionClient());
4608
+ const result = await server.queryDatabaseObject(command, params, routeContext?.getDbTransactionClient());
4609
+ if (result?.length > 0) {
4610
+ const targetEntity = await targetEntityManager.findById({
4611
+ routeContext,
4612
+ id: relation.id,
4613
+ });
4614
+ relationTargetEntities.push(targetEntity);
4615
+ }
4558
4616
  }
4559
4617
  }
4560
4618
  await server.emitEvent({
@@ -4565,10 +4623,17 @@ class EntityManager {
4565
4623
  entity,
4566
4624
  property,
4567
4625
  relations,
4626
+ relationTargetEntities,
4568
4627
  },
4569
4628
  sender: plugin,
4570
4629
  routeContext: options.routeContext,
4571
4630
  });
4631
+ return {
4632
+ entity,
4633
+ property,
4634
+ relations,
4635
+ relationTargetEntities,
4636
+ };
4572
4637
  }
4573
4638
  }
4574
4639
 
@@ -5017,7 +5082,15 @@ class RapidServer {
5017
5082
  throw new Error("Unknown handler: " + actionCode);
5018
5083
  }
5019
5084
  await this.beforeRunActionHandler(handlerContext, action);
5020
- await handler(handlerContext, action.config);
5085
+ try {
5086
+ await handler(handlerContext, action.config);
5087
+ }
5088
+ catch (error) {
5089
+ throw error;
5090
+ }
5091
+ finally {
5092
+ await this.afterRunActionHandler(handlerContext, action);
5093
+ }
5021
5094
  }
5022
5095
  }
5023
5096
  async beforeRunRouteActions(handlerContext) {
@@ -5026,6 +5099,9 @@ class RapidServer {
5026
5099
  async beforeRunActionHandler(handlerContext, actionConfig) {
5027
5100
  await this.#pluginManager.beforeRunActionHandler(handlerContext, actionConfig);
5028
5101
  }
5102
+ async afterRunActionHandler(handlerContext, actionConfig, error) {
5103
+ await this.#pluginManager.afterRunActionHandler(handlerContext, actionConfig, error);
5104
+ }
5029
5105
  async beforeCreateEntity(model, options) {
5030
5106
  await this.#pluginManager.beforeCreateEntity(model, options);
5031
5107
  }
@@ -6449,13 +6525,15 @@ async function handler$o(plugin, ctx, options) {
6449
6525
  routeContext: routeContext,
6450
6526
  filters,
6451
6527
  });
6528
+ const outputs = [];
6452
6529
  for (const entity of entities) {
6453
- await entityManager.deleteById({
6530
+ const output = await entityManager.deleteById({
6454
6531
  routeContext,
6455
6532
  id: entity.id,
6456
6533
  }, plugin);
6534
+ outputs.push(output);
6457
6535
  }
6458
- return {};
6536
+ return outputs;
6459
6537
  });
6460
6538
  }
6461
6539
 
@@ -6469,11 +6547,11 @@ const code$n = "deleteCollectionEntityById";
6469
6547
  async function handler$n(plugin, ctx, options) {
6470
6548
  await runCollectionEntityActionHandler(ctx, options, code$n, true, true, async (entityManager, input) => {
6471
6549
  const { routerContext: routeContext } = ctx;
6472
- await entityManager.deleteById({
6550
+ const output = await entityManager.deleteById({
6473
6551
  id: input.id,
6474
6552
  routeContext,
6475
6553
  }, plugin);
6476
- return {};
6554
+ return output;
6477
6555
  });
6478
6556
  }
6479
6557
 
@@ -6488,8 +6566,8 @@ async function handler$m(plugin, ctx, options) {
6488
6566
  await runCollectionEntityActionHandler(ctx, options, code$m, true, true, async (entityManager, input) => {
6489
6567
  const { routerContext: routeContext } = ctx;
6490
6568
  input.routeContext = routeContext;
6491
- await entityManager.addRelations(input, plugin);
6492
- return {};
6569
+ const result = await entityManager.addRelations(input, plugin);
6570
+ return result;
6493
6571
  });
6494
6572
  }
6495
6573
 
@@ -6504,8 +6582,8 @@ async function handler$l(plugin, ctx, options) {
6504
6582
  await runCollectionEntityActionHandler(ctx, options, code$l, true, true, async (entityManager, input) => {
6505
6583
  const { routerContext: routeContext } = ctx;
6506
6584
  input.routeContext = routeContext;
6507
- await entityManager.removeRelations(input, plugin);
6508
- return {};
6585
+ const result = await entityManager.removeRelations(input, plugin);
6586
+ return result;
6509
6587
  });
6510
6588
  }
6511
6589
 
package/dist/server.d.ts CHANGED
@@ -60,6 +60,7 @@ export declare class RapidServer implements IRpdServer {
60
60
  runActionHandlers(handlerContext: ActionHandlerContext, actions: RpdRouteActionConfig[]): Promise<void>;
61
61
  beforeRunRouteActions(handlerContext: ActionHandlerContext): Promise<void>;
62
62
  beforeRunActionHandler(handlerContext: ActionHandlerContext, actionConfig: RpdRouteActionConfig): Promise<void>;
63
+ afterRunActionHandler(handlerContext: ActionHandlerContext, actionConfig: RpdRouteActionConfig, error?: Error): Promise<void>;
63
64
  beforeCreateEntity(model: RpdDataModel, options: CreateEntityOptions): Promise<void>;
64
65
  beforeUpdateEntity(model: RpdDataModel, options: UpdateEntityByIdOptions, currentEntity: any): Promise<void>;
65
66
  }
package/dist/types.d.ts CHANGED
@@ -147,6 +147,7 @@ export interface RpdEntityAddRelationsEventPayload {
147
147
  entity: any;
148
148
  property: string;
149
149
  relations: any[];
150
+ relationTargetEntities: any[];
150
151
  }
151
152
  export interface RpdEntityRemoveRelationsEventPayload {
152
153
  namespace: string;
@@ -155,6 +156,7 @@ export interface RpdEntityRemoveRelationsEventPayload {
155
156
  entity: any;
156
157
  property: string;
157
158
  relations: any[];
159
+ relationTargetEntities: any[];
158
160
  }
159
161
  export interface RpdEntityBeforeResponseEventPayload {
160
162
  namespace: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ruiapp/rapid-core",
3
- "version": "0.11.6",
3
+ "version": "0.11.8",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -171,6 +171,15 @@ class PluginManager {
171
171
  }
172
172
  }
173
173
 
174
+ /** 在执行 action handler 后调用。 */
175
+ async afterRunActionHandler(handlerContext: ActionHandlerContext, actionConfig: RpdRouteActionConfig, error?: Error) {
176
+ for (const plugin of this.#plugins) {
177
+ if (plugin.afterRunActionHandler) {
178
+ await plugin.afterRunActionHandler(this.#server, handlerContext, actionConfig, error);
179
+ }
180
+ }
181
+ }
182
+
174
183
  /** 在创建实体前调用。 */
175
184
  async beforeCreateEntity(model: RpdDataModel, options: CreateEntityOptions) {
176
185
  for (const plugin of this.#plugins) {
@@ -32,10 +32,17 @@ async function executeHandlerOfActions(server: IRpdServer, routeConfig: RpdRoute
32
32
  }
33
33
 
34
34
  await server.beforeRunActionHandler(handlerContext, actionConfig);
35
-
36
- const result = handler(handlerContext, actionConfig.config);
37
- if (result instanceof Promise) {
38
- await result;
35
+ let err: any;
36
+ try {
37
+ const result = handler(handlerContext, actionConfig.config);
38
+ if (result instanceof Promise) {
39
+ await result;
40
+ }
41
+ } catch (error) {
42
+ err = error;
43
+ throw error;
44
+ } finally {
45
+ await server.afterRunActionHandler(handlerContext, actionConfig, err);
39
46
  }
40
47
  }
41
48
  }
@@ -57,6 +57,7 @@ export interface IRpdServer {
57
57
  runActionHandlers(handlerContext: ActionHandlerContext, actions: RpdRouteActionConfig[]): Promise<void>;
58
58
  beforeRunRouteActions(handlerContext: ActionHandlerContext): Promise<void>;
59
59
  beforeRunActionHandler(handlerContext: ActionHandlerContext, actionConfig: RpdRouteActionConfig): Promise<void>;
60
+ afterRunActionHandler(handlerContext: ActionHandlerContext, actionConfig: RpdRouteActionConfig, error?: Error): Promise<void>;
60
61
  beforeCreateEntity(model: RpdDataModel, options: CreateEntityOptions): Promise<void>;
61
62
  beforeUpdateEntity(model: RpdDataModel, options: UpdateEntityByIdOptions, currentEntity: any): Promise<void>;
62
63
 
@@ -151,6 +152,8 @@ export interface RapidPlugin {
151
152
  beforeRunRouteActions?: (server: IRpdServer, handlerContext: ActionHandlerContext) => Promise<any>;
152
153
  /** 在执行 action hanlder 前调用。 */
153
154
  beforeRunActionHandler?: (server: IRpdServer, handlerContext: ActionHandlerContext, actionConfig: RpdRouteActionConfig) => Promise<any>;
155
+ /** 在执行 action handler 后调用。 */
156
+ afterRunActionHandler?: (server: IRpdServer, handlerContext: ActionHandlerContext, actionConfig: RpdRouteActionConfig, error?: Error) => Promise<any>;
154
157
  /** 在创建实体前调用。 */
155
158
  beforeCreateEntity?: (server: IRpdServer, model: RpdDataModel, options: CreateEntityOptions) => Promise<any>;
156
159
  /** 在更新实体前调用。 */
@@ -170,6 +170,18 @@ async function findEntities(server: IRpdServer, dataAccessor: IRpdDataAccessor,
170
170
  );
171
171
  }
172
172
 
173
+ const isEntitySoftDeleteEnabled = baseModel ? baseModel.softDelete || model.softDelete : model.softDelete;
174
+ if (options.includingSoftDeleted && isEntitySoftDeleteEnabled) {
175
+ const deletedAtProp = getEntityPropertyByCode(server, model, "deletedAt");
176
+ if (deletedAtProp && !find(propertiesToSelect, (p) => p.code === "deletedAt")) {
177
+ propertiesToSelect.push(deletedAtProp);
178
+ }
179
+ const deletedByProp = getEntityPropertyByCode(server, model, "deletedBy");
180
+ if (deletedByProp && !find(propertiesToSelect, (p) => p.code === "deletedBy")) {
181
+ propertiesToSelect.push(deletedByProp);
182
+ }
183
+ }
184
+
173
185
  const columnsToSelect: ColumnSelectOptions[] = [];
174
186
 
175
187
  const relationPropertiesToSelect: RpdDataModelProperty[] = [];
@@ -401,7 +413,7 @@ const UNDELETED_ENTITY_FILTER_OPTIONS: EntityFilterOptions = {
401
413
  };
402
414
 
403
415
  function tryAddUndeletedEntityFilter(model: RpdDataModel, baseModel: RpdDataModel, filters: EntityFilterOptions[] | undefined) {
404
- let isEntitySoftDeleteEnabled = baseModel ? (baseModel.softDelete || model.softDelete) : model.softDelete;
416
+ let isEntitySoftDeleteEnabled = baseModel ? baseModel.softDelete || model.softDelete : model.softDelete;
405
417
  if (!isEntitySoftDeleteEnabled) {
406
418
  return filters;
407
419
  }
@@ -678,6 +690,7 @@ async function findManyRelationLinksViaLinkTable(options: FindManyRelationEntiti
678
690
  },
679
691
  ],
680
692
  keepNonPropertyFields: true,
693
+ includingSoftDeleted: true,
681
694
  };
682
695
 
683
696
  if (selectRelationOptions) {
@@ -737,6 +750,7 @@ async function findManyRelatedEntitiesViaIdPropertyCode(options: FindManyRelatio
737
750
  ],
738
751
  extraColumnsToSelect: [relationProperty.selfIdColumnName],
739
752
  keepNonPropertyFields: true,
753
+ includingSoftDeleted: true,
740
754
  };
741
755
 
742
756
  if (selectRelationOptions) {
@@ -785,6 +799,7 @@ async function findOneRelatedEntitiesViaIdPropertyCode(options: FindOneRelationE
785
799
  },
786
800
  ],
787
801
  keepNonPropertyFields: true,
802
+ includingSoftDeleted: true,
788
803
  };
789
804
 
790
805
  if (selectRelationOptions) {
@@ -1630,7 +1645,7 @@ async function deleteEntityById(
1630
1645
  dataAccessor: IRpdDataAccessor,
1631
1646
  options: DeleteEntityByIdOptions | string | number,
1632
1647
  plugin?: RapidPlugin,
1633
- ): Promise<void> {
1648
+ ): Promise<any> {
1634
1649
  // options is id
1635
1650
  if (!isObject(options)) {
1636
1651
  options = {
@@ -1662,7 +1677,7 @@ async function deleteEntityById(
1662
1677
  return;
1663
1678
  }
1664
1679
 
1665
- const isEntitySoftDeleteEnabled = model.base ? (baseModel.softDelete || model.softDelete) : model.softDelete;
1680
+ const isEntitySoftDeleteEnabled = model.base ? baseModel.softDelete || model.softDelete : model.softDelete;
1666
1681
  if (isEntitySoftDeleteEnabled) {
1667
1682
  if (entity.deletedAt) {
1668
1683
  return;
@@ -1826,6 +1841,7 @@ async function deleteEntityById(
1826
1841
  sender: plugin,
1827
1842
  routeContext,
1828
1843
  });
1844
+ return entity;
1829
1845
  }
1830
1846
 
1831
1847
  export default class EntityManager<TEntity = any> {
@@ -1882,11 +1898,11 @@ export default class EntityManager<TEntity = any> {
1882
1898
  return await this.#dataAccessor.count(countRowOptions, routeContext?.getDbTransactionClient());
1883
1899
  }
1884
1900
 
1885
- async deleteById(options: DeleteEntityByIdOptions | string | number, plugin?: RapidPlugin): Promise<void> {
1901
+ async deleteById(options: DeleteEntityByIdOptions | string | number, plugin?: RapidPlugin): Promise<TEntity> {
1886
1902
  return await deleteEntityById(this.#server, this.#dataAccessor, options, plugin);
1887
1903
  }
1888
1904
 
1889
- async addRelations(options: AddEntityRelationsOptions, plugin?: RapidPlugin): Promise<void> {
1905
+ async addRelations(options: AddEntityRelationsOptions, plugin?: RapidPlugin): Promise<any> {
1890
1906
  const server = this.#server;
1891
1907
  const model = this.getModel();
1892
1908
  const { id: selfId, property, relations, routeContext } = options;
@@ -1908,6 +1924,8 @@ export default class EntityManager<TEntity = any> {
1908
1924
  }
1909
1925
 
1910
1926
  const { queryBuilder } = server;
1927
+ const targetEntityManager = server.getEntityManager(relationProperty.targetSingularCode);
1928
+ const relationTargetEntities = [];
1911
1929
  if (relationProperty.linkTableName) {
1912
1930
  for (const relation of relations) {
1913
1931
  const command = `INSERT INTO ${queryBuilder.quoteTable({
@@ -1922,16 +1940,23 @@ export default class EntityManager<TEntity = any> {
1922
1940
 
1923
1941
  const targetId = relation[relationProperty.targetIdColumnName!] || relation.id;
1924
1942
  const params = [selfId, targetId];
1925
- await server.queryDatabaseObject(command, params, routeContext?.getDbTransactionClient());
1943
+ const result = await server.queryDatabaseObject(command, params, routeContext?.getDbTransactionClient());
1944
+ if (result?.length > 0) {
1945
+ const targetEntity = await targetEntityManager.findById({
1946
+ routeContext,
1947
+ id: targetId,
1948
+ });
1949
+ relationTargetEntities.push(targetEntity);
1950
+ }
1926
1951
  }
1927
1952
  } else {
1928
- const targetEntityManager = server.getEntityManager(relationProperty.targetSingularCode);
1929
1953
  for (const relation of relations) {
1930
1954
  relation[relationProperty.selfIdColumnName!] = selfId;
1931
- await targetEntityManager.createEntity({
1955
+ const targetEntity = await targetEntityManager.createEntity({
1932
1956
  routeContext,
1933
1957
  entity: relation,
1934
1958
  });
1959
+ relationTargetEntities.push(targetEntity);
1935
1960
  }
1936
1961
  }
1937
1962
 
@@ -1943,13 +1968,21 @@ export default class EntityManager<TEntity = any> {
1943
1968
  entity,
1944
1969
  property,
1945
1970
  relations,
1971
+ relationTargetEntities,
1946
1972
  },
1947
1973
  sender: plugin,
1948
1974
  routeContext: options.routeContext,
1949
1975
  });
1976
+
1977
+ return {
1978
+ entity,
1979
+ property,
1980
+ relations,
1981
+ relationTargetEntities,
1982
+ };
1950
1983
  }
1951
1984
 
1952
- async removeRelations(options: RemoveEntityRelationsOptions, plugin?: RapidPlugin): Promise<void> {
1985
+ async removeRelations(options: RemoveEntityRelationsOptions, plugin?: RapidPlugin): Promise<any> {
1953
1986
  const server = this.#server;
1954
1987
  const model = this.getModel();
1955
1988
  const { id, property, relations, routeContext } = options;
@@ -1971,12 +2004,21 @@ export default class EntityManager<TEntity = any> {
1971
2004
  }
1972
2005
 
1973
2006
  const { queryBuilder } = server;
2007
+ const targetEntityManager = server.getEntityManager(relationProperty.targetSingularCode);
2008
+ const relationTargetEntities = [];
1974
2009
  if (relationProperty.linkTableName) {
1975
2010
  for (const relation of relations) {
1976
2011
  const command = `DELETE FROM ${queryBuilder.quoteTable({ schema: relationProperty.linkSchema, tableName: relationProperty.linkTableName })}
1977
2012
  WHERE ${queryBuilder.quoteObject(relationProperty.selfIdColumnName!)}=$1 AND ${queryBuilder.quoteObject(relationProperty.targetIdColumnName!)}=$2;`;
1978
2013
  const params = [id, relation.id];
1979
- await server.queryDatabaseObject(command, params, routeContext?.getDbTransactionClient());
2014
+ const result = await server.queryDatabaseObject(command, params, routeContext?.getDbTransactionClient());
2015
+ if (result?.length > 0) {
2016
+ const targetEntity = await targetEntityManager.findById({
2017
+ routeContext,
2018
+ id: relation.id,
2019
+ });
2020
+ relationTargetEntities.push(targetEntity);
2021
+ }
1980
2022
  }
1981
2023
  }
1982
2024
 
@@ -1988,9 +2030,17 @@ export default class EntityManager<TEntity = any> {
1988
2030
  entity,
1989
2031
  property,
1990
2032
  relations,
2033
+ relationTargetEntities,
1991
2034
  },
1992
2035
  sender: plugin,
1993
2036
  routeContext: options.routeContext,
1994
2037
  });
2038
+
2039
+ return {
2040
+ entity,
2041
+ property,
2042
+ relations,
2043
+ relationTargetEntities,
2044
+ };
1995
2045
  }
1996
2046
  }
@@ -9,7 +9,7 @@ export async function handler(plugin: RapidPlugin, ctx: ActionHandlerContext, op
9
9
  await runCollectionEntityActionHandler(ctx, options, code, true, true, async (entityManager, input: AddEntityRelationsOptions): Promise<any> => {
10
10
  const { routerContext: routeContext } = ctx;
11
11
  input.routeContext = routeContext;
12
- await entityManager.addRelations(input, plugin);
13
- return {};
12
+ const result = await entityManager.addRelations(input, plugin);
13
+ return result;
14
14
  });
15
15
  }
@@ -30,16 +30,18 @@ export async function handler(plugin: RapidPlugin, ctx: ActionHandlerContext, op
30
30
  routeContext: routeContext,
31
31
  filters,
32
32
  });
33
+ const outputs = [];
33
34
  for (const entity of entities) {
34
- await entityManager.deleteById(
35
+ const output = await entityManager.deleteById(
35
36
  {
36
37
  routeContext,
37
38
  id: entity.id,
38
39
  },
39
40
  plugin,
40
41
  );
42
+ outputs.push(output);
41
43
  }
42
- return {};
44
+ return outputs;
43
45
  },
44
46
  );
45
47
  }
@@ -8,13 +8,13 @@ export const code = "deleteCollectionEntityById";
8
8
  export async function handler(plugin: RapidPlugin, ctx: ActionHandlerContext, options: RunEntityActionHandlerOptions) {
9
9
  await runCollectionEntityActionHandler(ctx, options, code, true, true, async (entityManager, input: any): Promise<any> => {
10
10
  const { routerContext: routeContext } = ctx;
11
- await entityManager.deleteById(
11
+ const output = await entityManager.deleteById(
12
12
  {
13
13
  id: input.id,
14
14
  routeContext,
15
15
  },
16
16
  plugin,
17
17
  );
18
- return {};
18
+ return output;
19
19
  });
20
20
  }
@@ -9,7 +9,7 @@ export async function handler(plugin: RapidPlugin, ctx: ActionHandlerContext, op
9
9
  await runCollectionEntityActionHandler(ctx, options, code, true, true, async (entityManager, input: any): Promise<any> => {
10
10
  const { routerContext: routeContext } = ctx;
11
11
  input.routeContext = routeContext;
12
- await entityManager.removeRelations(input, plugin);
13
- return {};
12
+ const result = await entityManager.removeRelations(input, plugin);
13
+ return result;
14
14
  });
15
15
  }
package/src/server.ts CHANGED
@@ -494,9 +494,16 @@ export class RapidServer implements IRpdServer {
494
494
  if (!handler) {
495
495
  throw new Error("Unknown handler: " + actionCode);
496
496
  }
497
-
497
+ let err: any;
498
498
  await this.beforeRunActionHandler(handlerContext, action);
499
- await handler(handlerContext, action.config);
499
+ try {
500
+ await handler(handlerContext, action.config);
501
+ } catch (error) {
502
+ err = error;
503
+ throw error;
504
+ } finally {
505
+ await this.afterRunActionHandler(handlerContext, action);
506
+ }
500
507
  }
501
508
  }
502
509
 
@@ -508,6 +515,10 @@ export class RapidServer implements IRpdServer {
508
515
  await this.#pluginManager.beforeRunActionHandler(handlerContext, actionConfig);
509
516
  }
510
517
 
518
+ async afterRunActionHandler(handlerContext: ActionHandlerContext, actionConfig: RpdRouteActionConfig, error?: Error) {
519
+ await this.#pluginManager.afterRunActionHandler(handlerContext, actionConfig, error);
520
+ }
521
+
511
522
  async beforeCreateEntity(model: RpdDataModel, options: CreateEntityOptions) {
512
523
  await this.#pluginManager.beforeCreateEntity(model, options);
513
524
  }
package/src/types.ts CHANGED
@@ -172,6 +172,7 @@ export interface RpdEntityAddRelationsEventPayload {
172
172
  entity: any;
173
173
  property: string;
174
174
  relations: any[];
175
+ relationTargetEntities: any[];
175
176
  }
176
177
 
177
178
  export interface RpdEntityRemoveRelationsEventPayload {
@@ -181,6 +182,7 @@ export interface RpdEntityRemoveRelationsEventPayload {
181
182
  entity: any;
182
183
  property: string;
183
184
  relations: any[];
185
+ relationTargetEntities: any[];
184
186
  }
185
187
 
186
188
  export interface RpdEntityBeforeResponseEventPayload {