@ruiapp/rapid-core 0.1.53 → 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,32 +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
- namespace: model.namespace,
2117
- modelSingularCode: model.singularCode,
2118
- baseModelSingularCode: model.base,
2119
- entities,
2120
- }, 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
+ });
2121
2126
  return entities;
2122
2127
  }
2123
2128
  async function findEntity(server, dataAccessor, options) {
2124
2129
  const entities = await findEntities(server, dataAccessor, options);
2125
2130
  return lodash.first(entities);
2126
2131
  }
2127
- async function findById(server, dataAccessor, id, keepNonPropertyFields = false) {
2132
+ async function findById(server, dataAccessor, options) {
2133
+ const { id, properties, keepNonPropertyFields, routeContext } = options;
2128
2134
  return await findEntity(server, dataAccessor, {
2129
2135
  filters: [
2130
2136
  {
@@ -2133,7 +2139,9 @@ async function findById(server, dataAccessor, id, keepNonPropertyFields = false)
2133
2139
  value: id,
2134
2140
  },
2135
2141
  ],
2142
+ properties,
2136
2143
  keepNonPropertyFields,
2144
+ routeContext,
2137
2145
  });
2138
2146
  }
2139
2147
  async function convertEntityFiltersToRowFilters(server, model, baseModel, filters) {
@@ -2404,14 +2412,19 @@ async function createEntity(server, dataAccessor, options, plugin) {
2404
2412
  if (model.derivedTypePropertyCode) {
2405
2413
  throw newEntityOperationError("Create base entity directly is not allowed.");
2406
2414
  }
2407
- const { entity } = options;
2415
+ const { entity, routeContext } = options;
2408
2416
  await server.beforeCreateEntity(model, options);
2409
- await server.emitEvent("entity.beforeCreate", {
2410
- namespace: model.namespace,
2411
- modelSingularCode: model.singularCode,
2412
- baseModelSingularCode: model.base,
2413
- before: entity,
2414
- }, 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
+ });
2415
2428
  const oneRelationPropertiesToCreate = [];
2416
2429
  const manyRelationPropertiesToCreate = [];
2417
2430
  lodash.keys(entity).forEach((propertyCode) => {
@@ -2449,7 +2462,10 @@ async function createEntity(server, dataAccessor, options, plugin) {
2449
2462
  targetRow[property.targetIdColumnName] = newTargetEntity["id"];
2450
2463
  }
2451
2464
  else {
2452
- const targetEntity = await findById(server, targetDataAccessor, targetEntityId);
2465
+ const targetEntity = await findById(server, targetDataAccessor, {
2466
+ id: targetEntityId,
2467
+ routeContext,
2468
+ });
2453
2469
  if (!targetEntity) {
2454
2470
  throw newEntityOperationError(`Create ${model.singularCode} entity failed. Property '${property.code}' was invalid. Related ${property.targetSingularCode} entity with id '${targetEntityId}' was not found.`);
2455
2471
  }
@@ -2460,7 +2476,10 @@ async function createEntity(server, dataAccessor, options, plugin) {
2460
2476
  else {
2461
2477
  // fieldValue is id;
2462
2478
  const targetEntityId = fieldValue;
2463
- const targetEntity = await findById(server, targetDataAccessor, targetEntityId);
2479
+ const targetEntity = await findById(server, targetDataAccessor, {
2480
+ id: targetEntityId,
2481
+ routeContext,
2482
+ });
2464
2483
  if (!targetEntity) {
2465
2484
  throw newEntityOperationError(`Create ${model.singularCode} entity failed. Property '${property.code}' was invalid. Related ${property.targetSingularCode} entity with id '${targetEntityId}' was not found.`);
2466
2485
  }
@@ -2546,21 +2565,29 @@ async function createEntity(server, dataAccessor, options, plugin) {
2546
2565
  }
2547
2566
  }
2548
2567
  }
2549
- await server.emitEvent("entity.create", {
2550
- namespace: model.namespace,
2551
- modelSingularCode: model.singularCode,
2552
- baseModelSingularCode: model.base,
2553
- after: newEntity,
2554
- }, 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
+ });
2555
2579
  return newEntity;
2556
2580
  }
2557
2581
  async function updateEntityById(server, dataAccessor, options, plugin) {
2558
2582
  const model = dataAccessor.getModel();
2559
- const { id, entityToSave } = options;
2583
+ const { id, entityToSave, routeContext } = options;
2560
2584
  if (!id) {
2561
2585
  throw new Error("Id is required when updating an entity.");
2562
2586
  }
2563
- const entity = await findById(server, dataAccessor, id);
2587
+ const entity = await findById(server, dataAccessor, {
2588
+ id,
2589
+ routeContext,
2590
+ });
2564
2591
  if (!entity) {
2565
2592
  throw new Error(`${model.namespace}.${model.singularCode} with id "${id}" was not found.`);
2566
2593
  }
@@ -2570,12 +2597,17 @@ async function updateEntityById(server, dataAccessor, options, plugin) {
2570
2597
  }
2571
2598
  options.entityToSave = changes || {};
2572
2599
  await server.beforeUpdateEntity(model, options, entity);
2573
- await server.emitEvent("entity.beforeUpdate", {
2574
- namespace: model.namespace,
2575
- modelSingularCode: model.singularCode,
2576
- before: entity,
2577
- changes: options.entityToSave,
2578
- }, 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
+ });
2579
2611
  changes = getEntityPartChanges(entity, options.entityToSave);
2580
2612
  const oneRelationPropertiesToUpdate = [];
2581
2613
  const manyRelationPropertiesToUpdate = [];
@@ -2613,7 +2645,10 @@ async function updateEntityById(server, dataAccessor, options, plugin) {
2613
2645
  targetRow[property.targetIdColumnName] = newTargetEntity["id"];
2614
2646
  }
2615
2647
  else {
2616
- const targetEntity = await findById(server, targetDataAccessor, targetEntityId);
2648
+ const targetEntity = await findById(server, targetDataAccessor, {
2649
+ id: targetEntityId,
2650
+ routeContext,
2651
+ });
2617
2652
  if (!targetEntity) {
2618
2653
  throw newEntityOperationError(`Create ${model.singularCode} entity failed. Property '${property.code}' was invalid. Related ${property.targetSingularCode} entity with id '${targetEntityId}' was not found.`);
2619
2654
  }
@@ -2624,7 +2659,10 @@ async function updateEntityById(server, dataAccessor, options, plugin) {
2624
2659
  else {
2625
2660
  // fieldValue is id;
2626
2661
  const targetEntityId = fieldValue;
2627
- const targetEntity = await findById(server, targetDataAccessor, targetEntityId);
2662
+ const targetEntity = await findById(server, targetDataAccessor, {
2663
+ id: targetEntityId,
2664
+ routeContext,
2665
+ });
2628
2666
  if (!targetEntity) {
2629
2667
  throw newEntityOperationError(`Create ${model.singularCode} entity failed. Property '${property.code}' was invalid. Related ${property.targetSingularCode} entity with id '${targetEntityId}' was not found.`);
2630
2668
  }
@@ -2718,15 +2756,20 @@ async function updateEntityById(server, dataAccessor, options, plugin) {
2718
2756
  }
2719
2757
  updatedEntity[property.code] = relatedEntities;
2720
2758
  }
2721
- await server.emitEvent("entity.update", {
2722
- namespace: model.namespace,
2723
- modelSingularCode: model.singularCode,
2724
- // TODO: should not emit event on base model if it's not effected.
2725
- baseModelSingularCode: model.base,
2726
- before: entity,
2727
- after: updatedEntity,
2728
- changes: changes,
2729
- }, 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
+ });
2730
2773
  return updatedEntity;
2731
2774
  }
2732
2775
  class EntityManager {
@@ -2745,8 +2788,14 @@ class EntityManager {
2745
2788
  async findEntity(options) {
2746
2789
  return await findEntity(this.#server, this.#dataAccessor, options);
2747
2790
  }
2748
- async findById(id, keepNonPropertyFields = false) {
2749
- 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);
2750
2799
  }
2751
2800
  async createEntity(options, plugin) {
2752
2801
  return await createEntity(this.#server, this.#dataAccessor, options, plugin);
@@ -2767,20 +2816,36 @@ class EntityManager {
2767
2816
  };
2768
2817
  return await this.#dataAccessor.count(countRowOptions);
2769
2818
  }
2770
- 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
+ }
2771
2826
  const model = this.getModel();
2772
2827
  if (model.derivedTypePropertyCode) {
2773
2828
  throw newEntityOperationError("Delete base entity directly is not allowed.");
2774
2829
  }
2775
- 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
+ });
2776
2836
  if (!entity) {
2777
2837
  return;
2778
2838
  }
2779
- await this.#server.emitEvent("entity.beforeDelete", {
2780
- namespace: model.namespace,
2781
- modelSingularCode: model.singularCode,
2782
- before: entity,
2783
- }, 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
+ });
2784
2849
  await this.#dataAccessor.deleteById(id);
2785
2850
  if (model.base) {
2786
2851
  const baseDataAccessor = this.#server.getDataAccessor({
@@ -2788,18 +2853,25 @@ class EntityManager {
2788
2853
  });
2789
2854
  await baseDataAccessor.deleteById(id);
2790
2855
  }
2791
- await this.#server.emitEvent("entity.delete", {
2792
- namespace: model.namespace,
2793
- modelSingularCode: model.singularCode,
2794
- baseModelSingularCode: model.base,
2795
- before: entity,
2796
- }, 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
+ });
2797
2866
  }
2798
2867
  async addRelations(options, plugin) {
2799
2868
  const server = this.#server;
2800
2869
  const model = this.getModel();
2801
- const { id, property, relations } = options;
2802
- const entity = await this.findById(id);
2870
+ const { id, property, relations, routeContext } = options;
2871
+ const entity = await this.findById({
2872
+ id,
2873
+ routeContext,
2874
+ });
2803
2875
  if (!entity) {
2804
2876
  throw new Error(`${model.namespace}.${model.singularCode} with id "${id}" was not found.`);
2805
2877
  }
@@ -2823,19 +2895,27 @@ class EntityManager {
2823
2895
  await server.queryDatabaseObject(command, params);
2824
2896
  }
2825
2897
  }
2826
- await server.emitEvent("entity.addRelations", {
2827
- namespace: model.namespace,
2828
- modelSingularCode: model.singularCode,
2829
- entity,
2830
- property,
2831
- relations,
2832
- }, 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
+ });
2833
2910
  }
2834
2911
  async removeRelations(options, plugin) {
2835
2912
  const server = this.#server;
2836
2913
  const model = this.getModel();
2837
- const { id, property, relations } = options;
2838
- const entity = await this.findById(id);
2914
+ const { id, property, relations, routeContext } = options;
2915
+ const entity = await this.findById({
2916
+ id,
2917
+ routeContext,
2918
+ });
2839
2919
  if (!entity) {
2840
2920
  throw new Error(`${model.namespace}.${model.singularCode} with id "${id}" was not found.`);
2841
2921
  }
@@ -2855,13 +2935,18 @@ class EntityManager {
2855
2935
  await server.queryDatabaseObject(command, params);
2856
2936
  }
2857
2937
  }
2858
- await server.emitEvent("entity.removeRelations", {
2859
- namespace: model.namespace,
2860
- modelSingularCode: model.singularCode,
2861
- entity,
2862
- property,
2863
- relations,
2864
- }, 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
+ });
2865
2950
  }
2866
2951
  }
2867
2952
 
@@ -3047,9 +3132,10 @@ class RapidServer {
3047
3132
  registerEntityWatcher(entityWatcher) {
3048
3133
  this.#entityWatchers.push(entityWatcher);
3049
3134
  }
3050
- async emitEvent(eventName, payload, sender) {
3135
+ async emitEvent(event) {
3136
+ const { eventName, payload, sender, routeContext: routerContext } = event;
3051
3137
  this.#logger.debug(`Emitting '${eventName}' event.`, { eventName, payload });
3052
- await this.#eventManager.emit(eventName, sender, payload);
3138
+ await this.#eventManager.emit(eventName, sender, payload, routerContext);
3053
3139
  // TODO: should move this logic into metaManager
3054
3140
  // if (
3055
3141
  // (eventName === "entity.create" || eventName === "entity.update" ||
@@ -3184,11 +3270,12 @@ class RapidServer {
3184
3270
  async beforeUpdateEntity(model, options, currentEntity) {
3185
3271
  await this.#pluginManager.beforeUpdateEntity(model, options, currentEntity);
3186
3272
  }
3187
- async #handleEntityEvent(eventName, sender, payload) {
3273
+ async #handleEntityEvent(eventName, sender, payload, routerContext) {
3188
3274
  const { modelSingularCode, baseModelSingularCode } = payload;
3189
3275
  const entityWatchHandlerContext = {
3190
3276
  server: this,
3191
3277
  payload,
3278
+ routerContext,
3192
3279
  };
3193
3280
  let emitter;
3194
3281
  if (eventName === "entity.beforeCreate") {
@@ -3528,7 +3615,7 @@ async function syncDatabaseSchema(server, applicationConfig) {
3528
3615
  for (const model of applicationConfig.models) {
3529
3616
  logger.debug(`Checking data columns for '${model.namespace}.${model.singularCode}'...`);
3530
3617
  for (const property of model.properties) {
3531
- let columnDDL;
3618
+ let columnDDL = "";
3532
3619
  if (isRelationProperty(property)) {
3533
3620
  if (property.relation === "one") {
3534
3621
  const targetModel = applicationConfig.models.find((item) => item.singularCode === property.targetSingularCode);
@@ -3562,6 +3649,11 @@ async function syncDatabaseSchema(server, applicationConfig) {
3562
3649
  selfIdColumnName: property.selfIdColumnName,
3563
3650
  });
3564
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);`;
3565
3657
  }
3566
3658
  else {
3567
3659
  const targetModel = applicationConfig.models.find((item) => item.singularCode === property.targetSingularCode);
@@ -3647,6 +3739,23 @@ async function syncDatabaseSchema(server, applicationConfig) {
3647
3739
  }
3648
3740
  }
3649
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
+ }
3650
3759
  }
3651
3760
  function generateCreateColumnDDL(queryBuilder, options) {
3652
3761
  let columnDDL = `ALTER TABLE ${queryBuilder.quoteTable(options)} ADD`;
@@ -3676,7 +3785,7 @@ function generateLinkTableDDL(queryBuilder, options) {
3676
3785
  })} (`;
3677
3786
  columnDDL += `id serial not null,`;
3678
3787
  columnDDL += `${queryBuilder.quoteObject(options.selfIdColumnName)} integer not null,`;
3679
- columnDDL += `${queryBuilder.quoteObject(options.targetIdColumnName)} integer not null)`;
3788
+ columnDDL += `${queryBuilder.quoteObject(options.targetIdColumnName)} integer not null);`;
3680
3789
  return columnDDL;
3681
3790
  }
3682
3791
  const pgPropertyTypeColumnMap = {
@@ -3759,6 +3868,7 @@ const code$m = "findCollectionEntities";
3759
3868
  async function handler$m(plugin, ctx, options) {
3760
3869
  await runCollectionEntityActionHandler(ctx, options, code$m, async (entityManager, input) => {
3761
3870
  input.filters = removeFiltersWithNullValue(input.filters);
3871
+ input.routeContext = ctx.routerContext;
3762
3872
  const entities = await entityManager.findEntities(input);
3763
3873
  const result = { list: entities };
3764
3874
  if (input.pagination && !input.pagination.withoutTotal) {
@@ -3782,7 +3892,10 @@ async function handler$l(plugin, ctx, options) {
3782
3892
  logger.debug(`Running ${code$l} handler...`, { input });
3783
3893
  const { id } = input;
3784
3894
  const entityManager = server.getEntityManager(options.singularCode);
3785
- const entity = await entityManager.findById(id);
3895
+ const entity = await entityManager.findById({
3896
+ id,
3897
+ routeContext: ctx.routerContext,
3898
+ });
3786
3899
  if (!entity) {
3787
3900
  throw new Error(`${options.namespace}.${options.singularCode} with id "${id}" was not found.`);
3788
3901
  }
@@ -3799,6 +3912,7 @@ const code$k = "countCollectionEntities";
3799
3912
  async function handler$k(plugin, ctx, options) {
3800
3913
  await runCollectionEntityActionHandler(ctx, options, code$k, (entityManager, input) => {
3801
3914
  input.filters = removeFiltersWithNullValue(input.filters);
3915
+ input.routeContext = ctx.routerContext;
3802
3916
  return entityManager.count(input);
3803
3917
  });
3804
3918
  }
@@ -3822,6 +3936,7 @@ async function handler$j(plugin, ctx, options) {
3822
3936
  const entityManager = server.getEntityManager(options.singularCode);
3823
3937
  const output = await entityManager.createEntity({
3824
3938
  entity: input,
3939
+ routeContext: ctx.routerContext,
3825
3940
  }, plugin);
3826
3941
  ctx.output = output;
3827
3942
  }
@@ -3851,6 +3966,7 @@ async function handler$i(plugin, ctx, options) {
3851
3966
  const entityManager = server.getEntityManager(options.singularCode);
3852
3967
  const newEntity = await entityManager.createEntity({
3853
3968
  entity: mergedEntity,
3969
+ routeContext: ctx.routerContext,
3854
3970
  }, plugin);
3855
3971
  output.push(newEntity);
3856
3972
  }
@@ -3877,8 +3993,15 @@ async function handler$h(plugin, ctx, options) {
3877
3993
  if (stateProperties) {
3878
3994
  delete mergedInput.$stateProperties;
3879
3995
  }
3996
+ const updateEntityByIdOptions = {
3997
+ id: mergedInput.id,
3998
+ entityToSave: mergedInput,
3999
+ operation,
4000
+ stateProperties,
4001
+ routeContext: ctx.routerContext,
4002
+ };
3880
4003
  const entityManager = server.getEntityManager(options.singularCode);
3881
- const output = await entityManager.updateEntityById({ id: mergedInput.id, entityToSave: mergedInput, operation, stateProperties }, plugin);
4004
+ const output = await entityManager.updateEntityById(updateEntityByIdOptions, plugin);
3882
4005
  ctx.output = output;
3883
4006
  }
3884
4007
 
@@ -3893,7 +4016,10 @@ async function handler$g(plugin, ctx, options) {
3893
4016
  const { logger, server, input } = ctx;
3894
4017
  logger.debug(`Running ${code$g} handler...`);
3895
4018
  const entityManager = server.getEntityManager(options.singularCode);
3896
- await entityManager.deleteById(input.id, plugin);
4019
+ await entityManager.deleteById({
4020
+ id: input.id,
4021
+ routeContext: ctx.routerContext,
4022
+ }, plugin);
3897
4023
  ctx.status = 200;
3898
4024
  ctx.output = {};
3899
4025
  }
@@ -3911,6 +4037,7 @@ async function handler$f(plugin, ctx, options) {
3911
4037
  const mergedInput = mergeInput(defaultInput, input, fixedInput);
3912
4038
  logger.debug(`Running ${code$f} handler...`, { defaultInput, fixedInput, mergedInput });
3913
4039
  const entityManager = server.getEntityManager(options.singularCode);
4040
+ mergedInput.routeContext = ctx.routerContext;
3914
4041
  await entityManager.addRelations(mergedInput, plugin);
3915
4042
  ctx.output = {};
3916
4043
  }
@@ -3927,6 +4054,7 @@ async function handler$e(plugin, ctx, options) {
3927
4054
  const { defaultInput, fixedInput } = options;
3928
4055
  const mergedInput = mergeInput(defaultInput, input, fixedInput);
3929
4056
  logger.debug(`Running ${code$e} handler...`, { defaultInput, fixedInput, mergedInput });
4057
+ mergedInput.routeContext = ctx.routerContext;
3930
4058
  const entityManager = server.getEntityManager(options.singularCode);
3931
4059
  await entityManager.removeRelations(mergedInput, plugin);
3932
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>;