@ruiapp/rapid-core 0.1.54 → 0.1.55

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.
@@ -1,4 +1,4 @@
1
- import { CreateEntityOptions, EntityWatcherType, GetDataAccessorOptions, GetModelOptions, IDatabaseConfig, IQueryBuilder, IRpdDataAccessor, RapidServerConfig, RpdApplicationConfig, RpdDataModel, RpdDataModelProperty, RpdServerEventTypes, UpdateEntityByIdOptions } from "../types";
1
+ import { CreateEntityOptions, EmitServerEventOptions, EntityWatcherType, GetDataAccessorOptions, GetModelOptions, IDatabaseConfig, IQueryBuilder, IRpdDataAccessor, RapidServerConfig, RpdApplicationConfig, RpdDataModel, RpdDataModelProperty, RpdServerEventTypes, UpdateEntityByIdOptions } from "../types";
2
2
  import { IPluginActionHandler, ActionHandler, ActionHandlerContext } from "./actionHandler";
3
3
  import { Next, RouteContext } from "./routeContext";
4
4
  import EntityManager from "../dataAccess/entityManager";
@@ -26,7 +26,7 @@ export interface IRpdServer {
26
26
  getModel(options: GetModelOptions): RpdDataModel | undefined;
27
27
  registerEventHandler<K extends keyof RpdServerEventTypes>(eventName: K, listener: (...args: RpdServerEventTypes[K]) => void): any;
28
28
  registerEntityWatcher(entityWatcher: EntityWatcherType): any;
29
- emitEvent<K extends keyof RpdServerEventTypes>(eventName: K, payload: RpdServerEventTypes[K][1], sender?: RapidPlugin): void;
29
+ emitEvent<TEventName extends keyof RpdServerEventTypes>(event: EmitServerEventOptions<TEventName>): void;
30
30
  handleRequest(request: Request, next: Next): Promise<Response>;
31
31
  beforeRunRouteActions(handlerContext: ActionHandlerContext): Promise<void>;
32
32
  beforeCreateEntity(model: RpdDataModel, options: CreateEntityOptions): Promise<void>;
@@ -1,4 +1,4 @@
1
- import { AddEntityRelationsOptions, CountEntityOptions, CountEntityResult, CreateEntityOptions, FindEntityOptions, IRpdDataAccessor, RemoveEntityRelationsOptions, RpdDataModel, UpdateEntityByIdOptions } from "../types";
1
+ import { AddEntityRelationsOptions, CountEntityOptions, CountEntityResult, CreateEntityOptions, DeleteEntityByIdOptions, FindEntityByIdOptions, FindEntityOptions, IRpdDataAccessor, RemoveEntityRelationsOptions, RpdDataModel, UpdateEntityByIdOptions } from "../types";
2
2
  import { IRpdServer, RapidPlugin } from "../core/server";
3
3
  export default class EntityManager<TEntity = any> {
4
4
  #private;
@@ -6,11 +6,11 @@ export default class EntityManager<TEntity = any> {
6
6
  getModel(): RpdDataModel;
7
7
  findEntities(options: FindEntityOptions): Promise<TEntity[]>;
8
8
  findEntity(options: FindEntityOptions): Promise<TEntity | null>;
9
- findById(id: any, keepNonPropertyFields?: boolean): Promise<TEntity | null>;
9
+ findById(options: FindEntityByIdOptions): Promise<TEntity | null>;
10
10
  createEntity(options: CreateEntityOptions, plugin?: RapidPlugin): Promise<TEntity>;
11
11
  updateEntityById(options: UpdateEntityByIdOptions, plugin?: RapidPlugin): Promise<TEntity>;
12
12
  count(options: CountEntityOptions): Promise<CountEntityResult>;
13
- deleteById(id: any, plugin?: RapidPlugin): Promise<void>;
13
+ deleteById(options: DeleteEntityByIdOptions, plugin?: RapidPlugin): Promise<void>;
14
14
  addRelations(options: AddEntityRelationsOptions, plugin?: RapidPlugin): Promise<void>;
15
15
  removeRelations(options: RemoveEntityRelationsOptions, plugin?: RapidPlugin): Promise<void>;
16
16
  }
package/dist/index.js CHANGED
@@ -2079,7 +2079,7 @@ async function findEntities(server, dataAccessor, options) {
2079
2079
  lodash.forEach(rows, (row) => {
2080
2080
  row[relationProperty.code] = lodash.filter(relationLinks, (link) => {
2081
2081
  return link[relationProperty.selfIdColumnName] == row["id"];
2082
- }).map((link) => mapDbRowToEntity(server, targetModel, link.targetEntity, false));
2082
+ }).map((link) => mapDbRowToEntity(server, targetModel, link.targetEntity, options.keepNonPropertyFields));
2083
2083
  });
2084
2084
  }
2085
2085
  }
@@ -2099,33 +2099,38 @@ async function findEntities(server, dataAccessor, options) {
2099
2099
  if (isManyRelation) {
2100
2100
  row[relationProperty.code] = lodash.filter(relatedEntities, (relatedEntity) => {
2101
2101
  return relatedEntity[relationProperty.selfIdColumnName] == row.id;
2102
- }).map((item) => mapDbRowToEntity(server, targetModel, item, false));
2102
+ }).map((item) => mapDbRowToEntity(server, targetModel, item, options.keepNonPropertyFields));
2103
2103
  }
2104
2104
  else {
2105
2105
  row[relationProperty.code] = mapDbRowToEntity(server, targetModel, lodash.find(relatedEntities, (relatedEntity) => {
2106
2106
  // TODO: id property code should be configurable.
2107
2107
  return relatedEntity["id"] == row[relationProperty.targetIdColumnName];
2108
- }), false);
2108
+ }), options.keepNonPropertyFields);
2109
2109
  }
2110
2110
  });
2111
2111
  }
2112
2112
  }
2113
2113
  }
2114
2114
  const entities = rows.map((item) => mapDbRowToEntity(server, model, item, options.keepNonPropertyFields));
2115
- await server.emitEvent("entity.beforeResponse", {
2116
- routerContext: options.routerContext,
2117
- namespace: model.namespace,
2118
- modelSingularCode: model.singularCode,
2119
- baseModelSingularCode: model.base,
2120
- entities,
2121
- }, null);
2115
+ await server.emitEvent({
2116
+ eventName: "entity.beforeResponse",
2117
+ payload: {
2118
+ namespace: model.namespace,
2119
+ modelSingularCode: model.singularCode,
2120
+ baseModelSingularCode: model.base,
2121
+ entities,
2122
+ },
2123
+ sender: null,
2124
+ routeContext: options.routeContext,
2125
+ });
2122
2126
  return entities;
2123
2127
  }
2124
2128
  async function findEntity(server, dataAccessor, options) {
2125
2129
  const entities = await findEntities(server, dataAccessor, options);
2126
2130
  return lodash.first(entities);
2127
2131
  }
2128
- async function findById(server, dataAccessor, id, keepNonPropertyFields = false) {
2132
+ async function findById(server, dataAccessor, options) {
2133
+ const { id, properties, keepNonPropertyFields, routeContext } = options;
2129
2134
  return await findEntity(server, dataAccessor, {
2130
2135
  filters: [
2131
2136
  {
@@ -2134,7 +2139,9 @@ async function findById(server, dataAccessor, id, keepNonPropertyFields = false)
2134
2139
  value: id,
2135
2140
  },
2136
2141
  ],
2142
+ properties,
2137
2143
  keepNonPropertyFields,
2144
+ routeContext,
2138
2145
  });
2139
2146
  }
2140
2147
  async function convertEntityFiltersToRowFilters(server, model, baseModel, filters) {
@@ -2405,15 +2412,19 @@ async function createEntity(server, dataAccessor, options, plugin) {
2405
2412
  if (model.derivedTypePropertyCode) {
2406
2413
  throw newEntityOperationError("Create base entity directly is not allowed.");
2407
2414
  }
2408
- const { entity } = options;
2415
+ const { entity, routeContext } = options;
2409
2416
  await server.beforeCreateEntity(model, options);
2410
- await server.emitEvent("entity.beforeCreate", {
2411
- routerContext: options.routerContext,
2412
- namespace: model.namespace,
2413
- modelSingularCode: model.singularCode,
2414
- baseModelSingularCode: model.base,
2415
- before: entity,
2416
- }, plugin);
2417
+ await server.emitEvent({
2418
+ eventName: "entity.beforeCreate",
2419
+ payload: {
2420
+ namespace: model.namespace,
2421
+ modelSingularCode: model.singularCode,
2422
+ baseModelSingularCode: model.base,
2423
+ before: entity,
2424
+ },
2425
+ sender: plugin,
2426
+ routeContext,
2427
+ });
2417
2428
  const oneRelationPropertiesToCreate = [];
2418
2429
  const manyRelationPropertiesToCreate = [];
2419
2430
  lodash.keys(entity).forEach((propertyCode) => {
@@ -2451,7 +2462,10 @@ async function createEntity(server, dataAccessor, options, plugin) {
2451
2462
  targetRow[property.targetIdColumnName] = newTargetEntity["id"];
2452
2463
  }
2453
2464
  else {
2454
- const targetEntity = await findById(server, targetDataAccessor, targetEntityId);
2465
+ const targetEntity = await findById(server, targetDataAccessor, {
2466
+ id: targetEntityId,
2467
+ routeContext,
2468
+ });
2455
2469
  if (!targetEntity) {
2456
2470
  throw newEntityOperationError(`Create ${model.singularCode} entity failed. Property '${property.code}' was invalid. Related ${property.targetSingularCode} entity with id '${targetEntityId}' was not found.`);
2457
2471
  }
@@ -2462,7 +2476,10 @@ async function createEntity(server, dataAccessor, options, plugin) {
2462
2476
  else {
2463
2477
  // fieldValue is id;
2464
2478
  const targetEntityId = fieldValue;
2465
- const targetEntity = await findById(server, targetDataAccessor, targetEntityId);
2479
+ const targetEntity = await findById(server, targetDataAccessor, {
2480
+ id: targetEntityId,
2481
+ routeContext,
2482
+ });
2466
2483
  if (!targetEntity) {
2467
2484
  throw newEntityOperationError(`Create ${model.singularCode} entity failed. Property '${property.code}' was invalid. Related ${property.targetSingularCode} entity with id '${targetEntityId}' was not found.`);
2468
2485
  }
@@ -2548,22 +2565,29 @@ async function createEntity(server, dataAccessor, options, plugin) {
2548
2565
  }
2549
2566
  }
2550
2567
  }
2551
- await server.emitEvent("entity.create", {
2552
- routerContext: options.routerContext,
2553
- namespace: model.namespace,
2554
- modelSingularCode: model.singularCode,
2555
- baseModelSingularCode: model.base,
2556
- after: newEntity,
2557
- }, plugin);
2568
+ await server.emitEvent({
2569
+ eventName: "entity.create",
2570
+ payload: {
2571
+ namespace: model.namespace,
2572
+ modelSingularCode: model.singularCode,
2573
+ baseModelSingularCode: model.base,
2574
+ after: newEntity,
2575
+ },
2576
+ sender: plugin,
2577
+ routeContext,
2578
+ });
2558
2579
  return newEntity;
2559
2580
  }
2560
2581
  async function updateEntityById(server, dataAccessor, options, plugin) {
2561
2582
  const model = dataAccessor.getModel();
2562
- const { id, entityToSave } = options;
2583
+ const { id, entityToSave, routeContext } = options;
2563
2584
  if (!id) {
2564
2585
  throw new Error("Id is required when updating an entity.");
2565
2586
  }
2566
- const entity = await findById(server, dataAccessor, id);
2587
+ const entity = await findById(server, dataAccessor, {
2588
+ id,
2589
+ routeContext,
2590
+ });
2567
2591
  if (!entity) {
2568
2592
  throw new Error(`${model.namespace}.${model.singularCode} with id "${id}" was not found.`);
2569
2593
  }
@@ -2573,12 +2597,17 @@ async function updateEntityById(server, dataAccessor, options, plugin) {
2573
2597
  }
2574
2598
  options.entityToSave = changes || {};
2575
2599
  await server.beforeUpdateEntity(model, options, entity);
2576
- await server.emitEvent("entity.beforeUpdate", {
2577
- namespace: model.namespace,
2578
- modelSingularCode: model.singularCode,
2579
- before: entity,
2580
- changes: options.entityToSave,
2581
- }, plugin);
2600
+ await server.emitEvent({
2601
+ eventName: "entity.beforeUpdate",
2602
+ payload: {
2603
+ namespace: model.namespace,
2604
+ modelSingularCode: model.singularCode,
2605
+ before: entity,
2606
+ changes: options.entityToSave,
2607
+ },
2608
+ sender: plugin,
2609
+ routeContext: options.routeContext,
2610
+ });
2582
2611
  changes = getEntityPartChanges(entity, options.entityToSave);
2583
2612
  const oneRelationPropertiesToUpdate = [];
2584
2613
  const manyRelationPropertiesToUpdate = [];
@@ -2616,7 +2645,10 @@ async function updateEntityById(server, dataAccessor, options, plugin) {
2616
2645
  targetRow[property.targetIdColumnName] = newTargetEntity["id"];
2617
2646
  }
2618
2647
  else {
2619
- const targetEntity = await findById(server, targetDataAccessor, targetEntityId);
2648
+ const targetEntity = await findById(server, targetDataAccessor, {
2649
+ id: targetEntityId,
2650
+ routeContext,
2651
+ });
2620
2652
  if (!targetEntity) {
2621
2653
  throw newEntityOperationError(`Create ${model.singularCode} entity failed. Property '${property.code}' was invalid. Related ${property.targetSingularCode} entity with id '${targetEntityId}' was not found.`);
2622
2654
  }
@@ -2627,7 +2659,10 @@ async function updateEntityById(server, dataAccessor, options, plugin) {
2627
2659
  else {
2628
2660
  // fieldValue is id;
2629
2661
  const targetEntityId = fieldValue;
2630
- const targetEntity = await findById(server, targetDataAccessor, targetEntityId);
2662
+ const targetEntity = await findById(server, targetDataAccessor, {
2663
+ id: targetEntityId,
2664
+ routeContext,
2665
+ });
2631
2666
  if (!targetEntity) {
2632
2667
  throw newEntityOperationError(`Create ${model.singularCode} entity failed. Property '${property.code}' was invalid. Related ${property.targetSingularCode} entity with id '${targetEntityId}' was not found.`);
2633
2668
  }
@@ -2721,15 +2756,20 @@ async function updateEntityById(server, dataAccessor, options, plugin) {
2721
2756
  }
2722
2757
  updatedEntity[property.code] = relatedEntities;
2723
2758
  }
2724
- await server.emitEvent("entity.update", {
2725
- namespace: model.namespace,
2726
- modelSingularCode: model.singularCode,
2727
- // TODO: should not emit event on base model if it's not effected.
2728
- baseModelSingularCode: model.base,
2729
- before: entity,
2730
- after: updatedEntity,
2731
- changes: changes,
2732
- }, plugin);
2759
+ await server.emitEvent({
2760
+ eventName: "entity.update",
2761
+ payload: {
2762
+ namespace: model.namespace,
2763
+ modelSingularCode: model.singularCode,
2764
+ // TODO: should not emit event on base model if it's not effected.
2765
+ baseModelSingularCode: model.base,
2766
+ before: entity,
2767
+ after: updatedEntity,
2768
+ changes: changes,
2769
+ },
2770
+ sender: plugin,
2771
+ routeContext: options.routeContext,
2772
+ });
2733
2773
  return updatedEntity;
2734
2774
  }
2735
2775
  class EntityManager {
@@ -2748,8 +2788,14 @@ class EntityManager {
2748
2788
  async findEntity(options) {
2749
2789
  return await findEntity(this.#server, this.#dataAccessor, options);
2750
2790
  }
2751
- async findById(id, keepNonPropertyFields = false) {
2752
- return await findById(this.#server, this.#dataAccessor, id, keepNonPropertyFields);
2791
+ async findById(options) {
2792
+ // options is id
2793
+ if (!lodash.isObject(options)) {
2794
+ options = {
2795
+ id: options,
2796
+ };
2797
+ }
2798
+ return await findById(this.#server, this.#dataAccessor, options);
2753
2799
  }
2754
2800
  async createEntity(options, plugin) {
2755
2801
  return await createEntity(this.#server, this.#dataAccessor, options, plugin);
@@ -2770,20 +2816,36 @@ class EntityManager {
2770
2816
  };
2771
2817
  return await this.#dataAccessor.count(countRowOptions);
2772
2818
  }
2773
- async deleteById(id, plugin) {
2819
+ async deleteById(options, plugin) {
2820
+ // options is id
2821
+ if (!lodash.isObject(options)) {
2822
+ options = {
2823
+ id: options,
2824
+ };
2825
+ }
2774
2826
  const model = this.getModel();
2775
2827
  if (model.derivedTypePropertyCode) {
2776
2828
  throw newEntityOperationError("Delete base entity directly is not allowed.");
2777
2829
  }
2778
- const entity = await this.findById(id, true);
2830
+ const { id, routeContext } = options;
2831
+ const entity = await this.findById({
2832
+ id,
2833
+ keepNonPropertyFields: true,
2834
+ routeContext,
2835
+ });
2779
2836
  if (!entity) {
2780
2837
  return;
2781
2838
  }
2782
- await this.#server.emitEvent("entity.beforeDelete", {
2783
- namespace: model.namespace,
2784
- modelSingularCode: model.singularCode,
2785
- before: entity,
2786
- }, plugin);
2839
+ await this.#server.emitEvent({
2840
+ eventName: "entity.beforeDelete",
2841
+ payload: {
2842
+ namespace: model.namespace,
2843
+ modelSingularCode: model.singularCode,
2844
+ before: entity,
2845
+ },
2846
+ sender: plugin,
2847
+ routeContext,
2848
+ });
2787
2849
  await this.#dataAccessor.deleteById(id);
2788
2850
  if (model.base) {
2789
2851
  const baseDataAccessor = this.#server.getDataAccessor({
@@ -2791,18 +2853,25 @@ class EntityManager {
2791
2853
  });
2792
2854
  await baseDataAccessor.deleteById(id);
2793
2855
  }
2794
- await this.#server.emitEvent("entity.delete", {
2795
- namespace: model.namespace,
2796
- modelSingularCode: model.singularCode,
2797
- baseModelSingularCode: model.base,
2798
- before: entity,
2799
- }, plugin);
2856
+ await this.#server.emitEvent({
2857
+ eventName: "entity.delete",
2858
+ payload: {
2859
+ namespace: model.namespace,
2860
+ modelSingularCode: model.singularCode,
2861
+ before: entity,
2862
+ },
2863
+ sender: plugin,
2864
+ routeContext,
2865
+ });
2800
2866
  }
2801
2867
  async addRelations(options, plugin) {
2802
2868
  const server = this.#server;
2803
2869
  const model = this.getModel();
2804
- const { id, property, relations } = options;
2805
- const entity = await this.findById(id);
2870
+ const { id, property, relations, routeContext } = options;
2871
+ const entity = await this.findById({
2872
+ id,
2873
+ routeContext,
2874
+ });
2806
2875
  if (!entity) {
2807
2876
  throw new Error(`${model.namespace}.${model.singularCode} with id "${id}" was not found.`);
2808
2877
  }
@@ -2826,19 +2895,27 @@ class EntityManager {
2826
2895
  await server.queryDatabaseObject(command, params);
2827
2896
  }
2828
2897
  }
2829
- await server.emitEvent("entity.addRelations", {
2830
- namespace: model.namespace,
2831
- modelSingularCode: model.singularCode,
2832
- entity,
2833
- property,
2834
- relations,
2835
- }, plugin);
2898
+ await server.emitEvent({
2899
+ eventName: "entity.addRelations",
2900
+ payload: {
2901
+ namespace: model.namespace,
2902
+ modelSingularCode: model.singularCode,
2903
+ entity,
2904
+ property,
2905
+ relations,
2906
+ },
2907
+ sender: plugin,
2908
+ routeContext: options.routeContext,
2909
+ });
2836
2910
  }
2837
2911
  async removeRelations(options, plugin) {
2838
2912
  const server = this.#server;
2839
2913
  const model = this.getModel();
2840
- const { id, property, relations } = options;
2841
- const entity = await this.findById(id);
2914
+ const { id, property, relations, routeContext } = options;
2915
+ const entity = await this.findById({
2916
+ id,
2917
+ routeContext,
2918
+ });
2842
2919
  if (!entity) {
2843
2920
  throw new Error(`${model.namespace}.${model.singularCode} with id "${id}" was not found.`);
2844
2921
  }
@@ -2858,13 +2935,18 @@ class EntityManager {
2858
2935
  await server.queryDatabaseObject(command, params);
2859
2936
  }
2860
2937
  }
2861
- await server.emitEvent("entity.removeRelations", {
2862
- namespace: model.namespace,
2863
- modelSingularCode: model.singularCode,
2864
- entity,
2865
- property,
2866
- relations,
2867
- }, plugin);
2938
+ await server.emitEvent({
2939
+ eventName: "entity.removeRelations",
2940
+ payload: {
2941
+ namespace: model.namespace,
2942
+ modelSingularCode: model.singularCode,
2943
+ entity,
2944
+ property,
2945
+ relations,
2946
+ },
2947
+ sender: plugin,
2948
+ routeContext: options.routeContext,
2949
+ });
2868
2950
  }
2869
2951
  }
2870
2952
 
@@ -3050,9 +3132,10 @@ class RapidServer {
3050
3132
  registerEntityWatcher(entityWatcher) {
3051
3133
  this.#entityWatchers.push(entityWatcher);
3052
3134
  }
3053
- async emitEvent(eventName, payload, sender) {
3135
+ async emitEvent(event) {
3136
+ const { eventName, payload, sender, routeContext: routerContext } = event;
3054
3137
  this.#logger.debug(`Emitting '${eventName}' event.`, { eventName, payload });
3055
- await this.#eventManager.emit(eventName, sender, payload);
3138
+ await this.#eventManager.emit(eventName, sender, payload, routerContext);
3056
3139
  // TODO: should move this logic into metaManager
3057
3140
  // if (
3058
3141
  // (eventName === "entity.create" || eventName === "entity.update" ||
@@ -3187,11 +3270,12 @@ class RapidServer {
3187
3270
  async beforeUpdateEntity(model, options, currentEntity) {
3188
3271
  await this.#pluginManager.beforeUpdateEntity(model, options, currentEntity);
3189
3272
  }
3190
- async #handleEntityEvent(eventName, sender, payload) {
3273
+ async #handleEntityEvent(eventName, sender, payload, routerContext) {
3191
3274
  const { modelSingularCode, baseModelSingularCode } = payload;
3192
3275
  const entityWatchHandlerContext = {
3193
3276
  server: this,
3194
3277
  payload,
3278
+ routerContext,
3195
3279
  };
3196
3280
  let emitter;
3197
3281
  if (eventName === "entity.beforeCreate") {
@@ -3531,7 +3615,7 @@ async function syncDatabaseSchema(server, applicationConfig) {
3531
3615
  for (const model of applicationConfig.models) {
3532
3616
  logger.debug(`Checking data columns for '${model.namespace}.${model.singularCode}'...`);
3533
3617
  for (const property of model.properties) {
3534
- let columnDDL;
3618
+ let columnDDL = "";
3535
3619
  if (isRelationProperty(property)) {
3536
3620
  if (property.relation === "one") {
3537
3621
  const targetModel = applicationConfig.models.find((item) => item.singularCode === property.targetSingularCode);
@@ -3565,6 +3649,11 @@ async function syncDatabaseSchema(server, applicationConfig) {
3565
3649
  selfIdColumnName: property.selfIdColumnName,
3566
3650
  });
3567
3651
  }
3652
+ const contraintName = `${property.linkTableName}_pk`;
3653
+ columnDDL += `ALTER TABLE ${queryBuilder.quoteTable(({
3654
+ schema: property.linkSchema,
3655
+ tableName: property.linkTableName,
3656
+ }))} ADD CONSTRAINT ${queryBuilder.quoteObject(contraintName)} PRIMARY KEY (id);`;
3568
3657
  }
3569
3658
  else {
3570
3659
  const targetModel = applicationConfig.models.find((item) => item.singularCode === property.targetSingularCode);
@@ -3650,6 +3739,23 @@ async function syncDatabaseSchema(server, applicationConfig) {
3650
3739
  }
3651
3740
  }
3652
3741
  }
3742
+ const sqlQueryConstraints = `SELECT table_schema, table_name, constraint_type, constraint_name FROM information_schema.table_constraints WHERE constraint_type = 'PRIMARY KEY';`;
3743
+ const constraintsInDb = await server.queryDatabaseObject(sqlQueryConstraints);
3744
+ for (const model of applicationConfig.models) {
3745
+ const expectedTableSchema = model.schema || server.databaseConfig.dbDefaultSchema;
3746
+ const expectedTableName = model.tableName;
3747
+ const expectedContraintName = `${expectedTableName}_pk`;
3748
+ logger.debug(`Checking pk for '${expectedTableSchema}.${expectedTableName}'...`);
3749
+ const constraintInDb = lodash.find(constraintsInDb, {
3750
+ table_schema: expectedTableSchema,
3751
+ table_name: expectedTableName,
3752
+ constraint_type: "PRIMARY KEY",
3753
+ constraint_name: expectedContraintName,
3754
+ });
3755
+ if (!constraintInDb) {
3756
+ await server.queryDatabaseObject(`ALTER TABLE ${queryBuilder.quoteTable(model)} ADD CONSTRAINT ${queryBuilder.quoteObject(expectedContraintName)} PRIMARY KEY (id);`, []);
3757
+ }
3758
+ }
3653
3759
  }
3654
3760
  function generateCreateColumnDDL(queryBuilder, options) {
3655
3761
  let columnDDL = `ALTER TABLE ${queryBuilder.quoteTable(options)} ADD`;
@@ -3679,7 +3785,7 @@ function generateLinkTableDDL(queryBuilder, options) {
3679
3785
  })} (`;
3680
3786
  columnDDL += `id serial not null,`;
3681
3787
  columnDDL += `${queryBuilder.quoteObject(options.selfIdColumnName)} integer not null,`;
3682
- columnDDL += `${queryBuilder.quoteObject(options.targetIdColumnName)} integer not null)`;
3788
+ columnDDL += `${queryBuilder.quoteObject(options.targetIdColumnName)} integer not null);`;
3683
3789
  return columnDDL;
3684
3790
  }
3685
3791
  const pgPropertyTypeColumnMap = {
@@ -3762,7 +3868,7 @@ const code$m = "findCollectionEntities";
3762
3868
  async function handler$m(plugin, ctx, options) {
3763
3869
  await runCollectionEntityActionHandler(ctx, options, code$m, async (entityManager, input) => {
3764
3870
  input.filters = removeFiltersWithNullValue(input.filters);
3765
- input.routerContext = ctx.routerContext;
3871
+ input.routeContext = ctx.routerContext;
3766
3872
  const entities = await entityManager.findEntities(input);
3767
3873
  const result = { list: entities };
3768
3874
  if (input.pagination && !input.pagination.withoutTotal) {
@@ -3786,7 +3892,10 @@ async function handler$l(plugin, ctx, options) {
3786
3892
  logger.debug(`Running ${code$l} handler...`, { input });
3787
3893
  const { id } = input;
3788
3894
  const entityManager = server.getEntityManager(options.singularCode);
3789
- const entity = await entityManager.findById(id);
3895
+ const entity = await entityManager.findById({
3896
+ id,
3897
+ routeContext: ctx.routerContext,
3898
+ });
3790
3899
  if (!entity) {
3791
3900
  throw new Error(`${options.namespace}.${options.singularCode} with id "${id}" was not found.`);
3792
3901
  }
@@ -3803,6 +3912,7 @@ const code$k = "countCollectionEntities";
3803
3912
  async function handler$k(plugin, ctx, options) {
3804
3913
  await runCollectionEntityActionHandler(ctx, options, code$k, (entityManager, input) => {
3805
3914
  input.filters = removeFiltersWithNullValue(input.filters);
3915
+ input.routeContext = ctx.routerContext;
3806
3916
  return entityManager.count(input);
3807
3917
  });
3808
3918
  }
@@ -3826,7 +3936,7 @@ async function handler$j(plugin, ctx, options) {
3826
3936
  const entityManager = server.getEntityManager(options.singularCode);
3827
3937
  const output = await entityManager.createEntity({
3828
3938
  entity: input,
3829
- routerContext: ctx.routerContext,
3939
+ routeContext: ctx.routerContext,
3830
3940
  }, plugin);
3831
3941
  ctx.output = output;
3832
3942
  }
@@ -3856,7 +3966,7 @@ async function handler$i(plugin, ctx, options) {
3856
3966
  const entityManager = server.getEntityManager(options.singularCode);
3857
3967
  const newEntity = await entityManager.createEntity({
3858
3968
  entity: mergedEntity,
3859
- routerContext: ctx.routerContext,
3969
+ routeContext: ctx.routerContext,
3860
3970
  }, plugin);
3861
3971
  output.push(newEntity);
3862
3972
  }
@@ -3883,8 +3993,15 @@ async function handler$h(plugin, ctx, options) {
3883
3993
  if (stateProperties) {
3884
3994
  delete mergedInput.$stateProperties;
3885
3995
  }
3996
+ const updateEntityByIdOptions = {
3997
+ id: mergedInput.id,
3998
+ entityToSave: mergedInput,
3999
+ operation,
4000
+ stateProperties,
4001
+ routeContext: ctx.routerContext,
4002
+ };
3886
4003
  const entityManager = server.getEntityManager(options.singularCode);
3887
- const output = await entityManager.updateEntityById({ id: mergedInput.id, entityToSave: mergedInput, operation, stateProperties }, plugin);
4004
+ const output = await entityManager.updateEntityById(updateEntityByIdOptions, plugin);
3888
4005
  ctx.output = output;
3889
4006
  }
3890
4007
 
@@ -3899,7 +4016,10 @@ async function handler$g(plugin, ctx, options) {
3899
4016
  const { logger, server, input } = ctx;
3900
4017
  logger.debug(`Running ${code$g} handler...`);
3901
4018
  const entityManager = server.getEntityManager(options.singularCode);
3902
- await entityManager.deleteById(input.id, plugin);
4019
+ await entityManager.deleteById({
4020
+ id: input.id,
4021
+ routeContext: ctx.routerContext,
4022
+ }, plugin);
3903
4023
  ctx.status = 200;
3904
4024
  ctx.output = {};
3905
4025
  }
@@ -3917,7 +4037,7 @@ async function handler$f(plugin, ctx, options) {
3917
4037
  const mergedInput = mergeInput(defaultInput, input, fixedInput);
3918
4038
  logger.debug(`Running ${code$f} handler...`, { defaultInput, fixedInput, mergedInput });
3919
4039
  const entityManager = server.getEntityManager(options.singularCode);
3920
- mergedInput.routerContext = ctx.routerContext;
4040
+ mergedInput.routeContext = ctx.routerContext;
3921
4041
  await entityManager.addRelations(mergedInput, plugin);
3922
4042
  ctx.output = {};
3923
4043
  }
@@ -3934,6 +4054,7 @@ async function handler$e(plugin, ctx, options) {
3934
4054
  const { defaultInput, fixedInput } = options;
3935
4055
  const mergedInput = mergeInput(defaultInput, input, fixedInput);
3936
4056
  logger.debug(`Running ${code$e} handler...`, { defaultInput, fixedInput, mergedInput });
4057
+ mergedInput.routeContext = ctx.routerContext;
3937
4058
  const entityManager = server.getEntityManager(options.singularCode);
3938
4059
  await entityManager.removeRelations(mergedInput, plugin);
3939
4060
  ctx.output = {};
package/dist/server.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { GetDataAccessorOptions, GetModelOptions, IDatabaseAccessor, IDatabaseConfig, IQueryBuilder, IRpdDataAccessor, RpdApplicationConfig, RpdDataModel, RpdServerEventTypes, RapidServerConfig, RpdDataModelProperty, CreateEntityOptions, UpdateEntityByIdOptions, EntityWatcherType } from "./types";
1
+ import { GetDataAccessorOptions, GetModelOptions, IDatabaseAccessor, IDatabaseConfig, IQueryBuilder, IRpdDataAccessor, RpdApplicationConfig, RpdDataModel, RpdServerEventTypes, RapidServerConfig, RpdDataModelProperty, CreateEntityOptions, UpdateEntityByIdOptions, EntityWatcherType, EmitServerEventOptions } from "./types";
2
2
  import { ActionHandler, ActionHandlerContext, IPluginActionHandler } from "./core/actionHandler";
3
3
  import { IRpdServer, RapidPlugin } from "./core/server";
4
4
  import { Next } from "./core/routeContext";
@@ -33,7 +33,7 @@ export declare class RapidServer implements IRpdServer {
33
33
  getEntityManager<TEntity = any>(singularCode: string): EntityManager<TEntity>;
34
34
  registerEventHandler<K extends keyof RpdServerEventTypes>(eventName: K, listener: (...args: RpdServerEventTypes[K]) => void): void;
35
35
  registerEntityWatcher(entityWatcher: EntityWatcherType): void;
36
- emitEvent<K extends keyof RpdServerEventTypes>(eventName: K, payload: RpdServerEventTypes[K][1], sender?: RapidPlugin): Promise<void>;
36
+ emitEvent<TEventName extends keyof RpdServerEventTypes>(event: EmitServerEventOptions<TEventName>): Promise<void>;
37
37
  registerService(name: string, service: any): void;
38
38
  getService<TService>(name: string): TService;
39
39
  start(): Promise<void>;