@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.
@@ -9,7 +9,7 @@ export const code = "findCollectionEntities";
9
9
  export async function handler(plugin: RapidPlugin, ctx: ActionHandlerContext, options: RunEntityActionHandlerOptions) {
10
10
  await runCollectionEntityActionHandler(ctx, options, code, async (entityManager, input: FindEntityOptions) => {
11
11
  input.filters = removeFiltersWithNullValue(input.filters);
12
- input.routerContext = ctx.routerContext;
12
+ input.routeContext = ctx.routerContext;
13
13
  const entities = await entityManager.findEntities(input);
14
14
  const result: {
15
15
  list: any;
@@ -10,7 +10,10 @@ export async function handler(plugin: RapidPlugin, ctx: ActionHandlerContext, op
10
10
  const { id } = input;
11
11
 
12
12
  const entityManager = server.getEntityManager(options.singularCode);
13
- const entity = await entityManager.findById(id);
13
+ const entity = await entityManager.findById({
14
+ id,
15
+ routeContext: ctx.routerContext,
16
+ });
14
17
  if (!entity) {
15
18
  throw new Error(`${options.namespace}.${options.singularCode} with id "${id}" was not found.`);
16
19
  }
@@ -1,4 +1,4 @@
1
- import { RunEntityActionHandlerOptions } from "~/types";
1
+ import { RemoveEntityRelationsOptions, RunEntityActionHandlerOptions } from "~/types";
2
2
  import { mergeInput } from "~/helpers/inputHelper";
3
3
  import { ActionHandlerContext } from "~/core/actionHandler";
4
4
  import { RapidPlugin } from "~/core/server";
@@ -9,8 +9,9 @@ export async function handler(plugin: RapidPlugin, ctx: ActionHandlerContext, op
9
9
  const { logger, server, input } = ctx;
10
10
  const { defaultInput, fixedInput } = options;
11
11
 
12
- const mergedInput = mergeInput(defaultInput, input, fixedInput);
12
+ const mergedInput: RemoveEntityRelationsOptions = mergeInput(defaultInput, input, fixedInput);
13
13
  logger.debug(`Running ${code} handler...`, { defaultInput, fixedInput, mergedInput });
14
+ mergedInput.routeContext = ctx.routerContext;
14
15
 
15
16
  const entityManager = server.getEntityManager(options.singularCode);
16
17
  await entityManager.removeRelations(mergedInput, plugin);
@@ -1,4 +1,4 @@
1
- import { RunEntityActionHandlerOptions } from "~/types";
1
+ import { RunEntityActionHandlerOptions, UpdateEntityByIdOptions } from "~/types";
2
2
  import { mergeInput } from "~/helpers/inputHelper";
3
3
  import { ActionHandlerContext } from "~/core/actionHandler";
4
4
  import { RapidPlugin } from "~/core/server";
@@ -22,7 +22,14 @@ export async function handler(plugin: RapidPlugin, ctx: ActionHandlerContext, op
22
22
  delete mergedInput.$stateProperties;
23
23
  }
24
24
 
25
+ const updateEntityByIdOptions: UpdateEntityByIdOptions = {
26
+ id: mergedInput.id,
27
+ entityToSave: mergedInput,
28
+ operation,
29
+ stateProperties,
30
+ routeContext: ctx.routerContext,
31
+ };
25
32
  const entityManager = server.getEntityManager(options.singularCode);
26
- const output = await entityManager.updateEntityById({ id: mergedInput.id, entityToSave: mergedInput, operation, stateProperties }, plugin);
33
+ const output = await entityManager.updateEntityById(updateEntityByIdOptions, plugin);
27
34
  ctx.output = output;
28
35
  }
@@ -161,6 +161,13 @@ type ColumnInformation = {
161
161
  numeric_scale: number;
162
162
  };
163
163
 
164
+ type ConstraintInformation = {
165
+ table_schema: string;
166
+ table_name: string;
167
+ constraint_type: string;
168
+ constraint_name: string;
169
+ };
170
+
164
171
  async function syncDatabaseSchema(server: IRpdServer, applicationConfig: RpdApplicationConfig) {
165
172
  const logger = server.getLogger();
166
173
  logger.info("Synchronizing database schema...");
@@ -187,7 +194,7 @@ async function syncDatabaseSchema(server: IRpdServer, applicationConfig: RpdAppl
187
194
  logger.debug(`Checking data columns for '${model.namespace}.${model.singularCode}'...`);
188
195
 
189
196
  for (const property of model.properties) {
190
- let columnDDL;
197
+ let columnDDL = "";
191
198
  if (isRelationProperty(property)) {
192
199
  if (property.relation === "one") {
193
200
  const targetModel = applicationConfig.models.find((item) => item.singularCode === property.targetSingularCode);
@@ -222,6 +229,12 @@ async function syncDatabaseSchema(server: IRpdServer, applicationConfig: RpdAppl
222
229
  selfIdColumnName: property.selfIdColumnName!,
223
230
  });
224
231
  }
232
+
233
+ const contraintName = `${property.linkTableName}_pk`;
234
+ columnDDL += `ALTER TABLE ${queryBuilder.quoteTable(({
235
+ schema: property.linkSchema,
236
+ tableName: property.linkTableName,
237
+ }))} ADD CONSTRAINT ${queryBuilder.quoteObject(contraintName)} PRIMARY KEY (id);`;
225
238
  } else {
226
239
  const targetModel = applicationConfig.models.find((item) => item.singularCode === property.targetSingularCode);
227
240
  if (!targetModel) {
@@ -307,6 +320,24 @@ async function syncDatabaseSchema(server: IRpdServer, applicationConfig: RpdAppl
307
320
  }
308
321
  }
309
322
  }
323
+
324
+ const sqlQueryConstraints = `SELECT table_schema, table_name, constraint_type, constraint_name FROM information_schema.table_constraints WHERE constraint_type = 'PRIMARY KEY';`;
325
+ const constraintsInDb: ConstraintInformation[] = await server.queryDatabaseObject(sqlQueryConstraints);
326
+ for (const model of applicationConfig.models) {
327
+ const expectedTableSchema = model.schema || server.databaseConfig.dbDefaultSchema;
328
+ const expectedTableName = model.tableName;
329
+ const expectedContraintName = `${expectedTableName}_pk`;
330
+ logger.debug(`Checking pk for '${expectedTableSchema}.${expectedTableName}'...`);
331
+ const constraintInDb = find(constraintsInDb, {
332
+ table_schema: expectedTableSchema,
333
+ table_name: expectedTableName,
334
+ constraint_type: "PRIMARY KEY",
335
+ constraint_name: expectedContraintName,
336
+ });
337
+ if (!constraintInDb) {
338
+ await server.queryDatabaseObject(`ALTER TABLE ${queryBuilder.quoteTable(model)} ADD CONSTRAINT ${queryBuilder.quoteObject(expectedContraintName)} PRIMARY KEY (id);`, []);
339
+ }
340
+ }
310
341
  }
311
342
 
312
343
  function generateCreateColumnDDL(
@@ -358,7 +389,7 @@ function generateLinkTableDDL(
358
389
  })} (`;
359
390
  columnDDL += `id serial not null,`;
360
391
  columnDDL += `${queryBuilder.quoteObject(options.selfIdColumnName)} integer not null,`;
361
- columnDDL += `${queryBuilder.quoteObject(options.targetIdColumnName)} integer not null)`;
392
+ columnDDL += `${queryBuilder.quoteObject(options.targetIdColumnName)} integer not null);`;
362
393
 
363
394
  return columnDDL;
364
395
  }
package/src/server.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import DataAccessor from "./dataAccess/dataAccessor";
2
- import { GetDataAccessorOptions, GetModelOptions, IDatabaseAccessor, IDatabaseConfig, IQueryBuilder, IRpdDataAccessor, RpdApplicationConfig, RpdDataModel, RpdServerEventTypes, RapidServerConfig, RpdDataModelProperty, CreateEntityOptions, UpdateEntityByIdOptions, EntityWatchHandlerContext, EntityWatcherType, RpdEntityCreateEventPayload } from "./types";
2
+ import { GetDataAccessorOptions, GetModelOptions, IDatabaseAccessor, IDatabaseConfig, IQueryBuilder, IRpdDataAccessor, RpdApplicationConfig, RpdDataModel, RpdServerEventTypes, RapidServerConfig, RpdDataModelProperty, CreateEntityOptions, UpdateEntityByIdOptions, EntityWatchHandlerContext, EntityWatcherType, RpdEntityCreateEventPayload, EmitServerEventOptions } from "./types";
3
3
 
4
4
  import QueryBuilder from "./queryBuilder/queryBuilder";
5
5
  import PluginManager from "./core/pluginManager";
@@ -237,9 +237,10 @@ export class RapidServer implements IRpdServer {
237
237
  this.#entityWatchers.push(entityWatcher);
238
238
  }
239
239
 
240
- async emitEvent<K extends keyof RpdServerEventTypes>(eventName: K, payload: RpdServerEventTypes[K][1], sender?: RapidPlugin) {
240
+ async emitEvent<TEventName extends keyof RpdServerEventTypes>(event: EmitServerEventOptions<TEventName>) {
241
+ const { eventName, payload, sender, routeContext: routerContext } = event;
241
242
  this.#logger.debug(`Emitting '${eventName}' event.`, { eventName, payload });
242
- await this.#eventManager.emit<K>(eventName, sender, payload as any);
243
+ await this.#eventManager.emit<TEventName>(eventName, sender, payload as any, routerContext);
243
244
 
244
245
  // TODO: should move this logic into metaManager
245
246
  // if (
@@ -392,11 +393,12 @@ export class RapidServer implements IRpdServer {
392
393
  await this.#pluginManager.beforeUpdateEntity(model, options, currentEntity);
393
394
  }
394
395
 
395
- async #handleEntityEvent(eventName: keyof RpdServerEventTypes, sender: RapidPlugin, payload: RpdEntityCreateEventPayload) {
396
+ async #handleEntityEvent(eventName: keyof RpdServerEventTypes, sender: RapidPlugin, payload: RpdEntityCreateEventPayload, routerContext?: RouteContext) {
396
397
  const { modelSingularCode, baseModelSingularCode } = payload;
397
398
  const entityWatchHandlerContext: EntityWatchHandlerContext<typeof eventName> = {
398
399
  server: this,
399
400
  payload,
401
+ routerContext,
400
402
  };
401
403
 
402
404
  let emitter: EventManager<Record<string, [EntityWatchHandlerContext<any>]>>;
package/src/types.ts CHANGED
@@ -68,19 +68,18 @@ export interface GetModelOptions {
68
68
  }
69
69
 
70
70
  export type RpdServerEventTypes = {
71
- "entity.beforeCreate": [RapidPlugin, RpdEntityBeforeCreateEventPayload];
72
- "entity.create": [RapidPlugin, RpdEntityCreateEventPayload];
73
- "entity.beforeUpdate": [RapidPlugin, RpdEntityBeforeUpdateEventPayload];
74
- "entity.update": [RapidPlugin, RpdEntityUpdateEventPayload];
75
- "entity.beforeDelete": [RapidPlugin, RpdEntityBeforeDeleteEventPayload];
76
- "entity.delete": [RapidPlugin, RpdEntityDeleteEventPayload];
77
- "entity.addRelations": [RapidPlugin, RpdEntityAddRelationsEventPayload];
78
- "entity.removeRelations": [RapidPlugin, RpdEntityRemoveRelationsEventPayload];
79
- "entity.beforeResponse": [RapidPlugin, RpdEntityBeforeResponseEventPayload];
71
+ "entity.beforeCreate": [RapidPlugin, RpdEntityBeforeCreateEventPayload, RouteContext?];
72
+ "entity.create": [RapidPlugin, RpdEntityCreateEventPayload, RouteContext?];
73
+ "entity.beforeUpdate": [RapidPlugin, RpdEntityBeforeUpdateEventPayload, RouteContext?];
74
+ "entity.update": [RapidPlugin, RpdEntityUpdateEventPayload, RouteContext?];
75
+ "entity.beforeDelete": [RapidPlugin, RpdEntityBeforeDeleteEventPayload, RouteContext?];
76
+ "entity.delete": [RapidPlugin, RpdEntityDeleteEventPayload, RouteContext?];
77
+ "entity.addRelations": [RapidPlugin, RpdEntityAddRelationsEventPayload, RouteContext?];
78
+ "entity.removeRelations": [RapidPlugin, RpdEntityRemoveRelationsEventPayload, RouteContext?];
79
+ "entity.beforeResponse": [RapidPlugin, RpdEntityBeforeResponseEventPayload, RouteContext?];
80
80
  };
81
81
 
82
82
  export interface RpdEntityBeforeCreateEventPayload {
83
- routerContext?: RouteContext;
84
83
  namespace: string;
85
84
  modelSingularCode: string;
86
85
  baseModelSingularCode?: string;
@@ -88,7 +87,6 @@ export interface RpdEntityBeforeCreateEventPayload {
88
87
  }
89
88
 
90
89
  export interface RpdEntityCreateEventPayload {
91
- routerContext?: RouteContext;
92
90
  namespace: string;
93
91
  modelSingularCode: string;
94
92
  baseModelSingularCode?: string;
@@ -96,7 +94,6 @@ export interface RpdEntityCreateEventPayload {
96
94
  }
97
95
 
98
96
  export interface RpdEntityBeforeUpdateEventPayload {
99
- routerContext?: RouteContext;
100
97
  namespace: string;
101
98
  modelSingularCode: string;
102
99
  baseModelSingularCode?: string;
@@ -105,7 +102,6 @@ export interface RpdEntityBeforeUpdateEventPayload {
105
102
  }
106
103
 
107
104
  export interface RpdEntityUpdateEventPayload {
108
- routerContext?: RouteContext;
109
105
  namespace: string;
110
106
  modelSingularCode: string;
111
107
  baseModelSingularCode?: string;
@@ -115,7 +111,6 @@ export interface RpdEntityUpdateEventPayload {
115
111
  }
116
112
 
117
113
  export interface RpdEntityBeforeDeleteEventPayload {
118
- routerContext?: RouteContext;
119
114
  namespace: string;
120
115
  modelSingularCode: string;
121
116
  baseModelSingularCode?: string;
@@ -123,7 +118,6 @@ export interface RpdEntityBeforeDeleteEventPayload {
123
118
  }
124
119
 
125
120
  export interface RpdEntityDeleteEventPayload {
126
- routerContext?: RouteContext;
127
121
  namespace: string;
128
122
  modelSingularCode: string;
129
123
  baseModelSingularCode?: string;
@@ -131,7 +125,6 @@ export interface RpdEntityDeleteEventPayload {
131
125
  }
132
126
 
133
127
  export interface RpdEntityAddRelationsEventPayload {
134
- routerContext?: RouteContext;
135
128
  namespace: string;
136
129
  modelSingularCode: string;
137
130
  baseModelSingularCode?: string;
@@ -141,7 +134,6 @@ export interface RpdEntityAddRelationsEventPayload {
141
134
  }
142
135
 
143
136
  export interface RpdEntityRemoveRelationsEventPayload {
144
- routerContext?: RouteContext;
145
137
  namespace: string;
146
138
  modelSingularCode: string;
147
139
  baseModelSingularCode?: string;
@@ -151,13 +143,19 @@ export interface RpdEntityRemoveRelationsEventPayload {
151
143
  }
152
144
 
153
145
  export interface RpdEntityBeforeResponseEventPayload {
154
- routerContext?: RouteContext;
155
146
  namespace: string;
156
147
  modelSingularCode: string;
157
148
  baseModelSingularCode?: string;
158
149
  entities: any[];
159
150
  }
160
151
 
152
+ export type EmitServerEventOptions<TEventName extends keyof RpdServerEventTypes> = {
153
+ eventName: TEventName;
154
+ payload: RpdServerEventTypes[TEventName][1];
155
+ sender?: RapidPlugin;
156
+ routeContext?: RouteContext;
157
+ }
158
+
161
159
  export interface QuoteTableOptions {
162
160
  schema?: string;
163
161
  tableName: string;
@@ -399,7 +397,7 @@ export type EntityFilterOptions = FindEntityRelationalFilterOptions | FindEntity
399
397
  export type EntityNonRelationPropertyFilterOptions = FindEntityRelationalFilterOptions | FindEntitySetFilterOptions | FindEntityUnaryFilterOptions;
400
398
 
401
399
  export interface FindEntityOptions {
402
- routerContext?: RouteContext;
400
+ routeContext?: RouteContext;
403
401
  filters?: EntityFilterOptions[];
404
402
  orderBy?: FindEntityOrderByOptions[];
405
403
  pagination?: FindEntityPaginationOptions;
@@ -407,6 +405,13 @@ export interface FindEntityOptions {
407
405
  keepNonPropertyFields?: boolean;
408
406
  }
409
407
 
408
+ export interface FindEntityByIdOptions {
409
+ routeContext?: RouteContext;
410
+ id: any;
411
+ properties?: string[];
412
+ keepNonPropertyFields?: boolean;
413
+ }
414
+
410
415
  export interface FindEntityRelationalFilterOptions {
411
416
  field: string;
412
417
  operator: EntityFilterRelationalOperators;
@@ -448,6 +453,7 @@ export interface FindEntityOrderByOptions {
448
453
  }
449
454
 
450
455
  export interface CountEntityOptions {
456
+ routeContext?: RouteContext;
451
457
  filters?: EntityFilterOptions[];
452
458
  }
453
459
 
@@ -455,19 +461,24 @@ export interface CountEntityResult {
455
461
  count: number;
456
462
  }
457
463
 
464
+ export interface DeleteEntityByIdOptions {
465
+ routeContext?: RouteContext;
466
+ id: any;
467
+ }
468
+
458
469
  export interface CreateEntityOptions {
459
- routerContext?: RouteContext;
470
+ routeContext?: RouteContext;
460
471
  entity: any;
461
472
  }
462
473
 
463
474
  export interface UpdateEntityOptions {
464
- routerContext?: RouteContext;
475
+ routeContext?: RouteContext;
465
476
  filters?: EntityFilterOptions[];
466
477
  entity: any;
467
478
  }
468
479
 
469
480
  export interface UpdateEntityByIdOptions {
470
- routerContext?: RouteContext;
481
+ routeContext?: RouteContext;
471
482
  id: any;
472
483
  entityToSave: any;
473
484
  operation?: any;
@@ -475,19 +486,19 @@ export interface UpdateEntityByIdOptions {
475
486
  }
476
487
 
477
488
  export interface DeleteEntityOptions {
478
- routerContext?: RouteContext;
489
+ routeContext?: RouteContext;
479
490
  filters?: EntityFilterOptions[];
480
491
  }
481
492
 
482
493
  export interface AddEntityRelationsOptions {
483
- routerContext?: RouteContext;
494
+ routeContext?: RouteContext;
484
495
  id: number;
485
496
  property: string;
486
497
  relations: { id?: number; [k: string]: any }[];
487
498
  }
488
499
 
489
500
  export interface RemoveEntityRelationsOptions {
490
- routerContext?: RouteContext;
501
+ routeContext?: RouteContext;
491
502
  id: number;
492
503
  property: string;
493
504
  relations: { id?: number; [k: string]: any }[];
@@ -507,6 +518,7 @@ export type EntityWatchHandler<TEventName extends keyof RpdServerEventTypes> = (
507
518
  export type EntityWatchHandlerContext<TEventName extends keyof RpdServerEventTypes> = {
508
519
  server: IRpdServer;
509
520
  payload: RpdServerEventTypes[TEventName][1];
521
+ routerContext?: RouteContext;
510
522
  };
511
523
 
512
524
  export interface EntityWatchPluginInitOptions {