@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.
- package/dist/core/server.d.ts +2 -2
- package/dist/dataAccess/entityManager.d.ts +3 -3
- package/dist/index.js +213 -92
- package/dist/server.d.ts +2 -2
- package/dist/types.d.ts +34 -25
- package/package.json +1 -1
- package/src/core/server.ts +2 -2
- package/src/dataAccess/entityManager.ts +121 -68
- package/src/plugins/dataManage/actionHandlers/addEntityRelations.ts +1 -1
- package/src/plugins/dataManage/actionHandlers/countCollectionEntities.ts +3 -2
- package/src/plugins/dataManage/actionHandlers/createCollectionEntitiesBatch.ts +1 -1
- package/src/plugins/dataManage/actionHandlers/createCollectionEntity.ts +1 -1
- package/src/plugins/dataManage/actionHandlers/deleteCollectionEntityById.ts +4 -1
- package/src/plugins/dataManage/actionHandlers/findCollectionEntities.ts +1 -1
- package/src/plugins/dataManage/actionHandlers/findCollectionEntityById.ts +4 -1
- package/src/plugins/dataManage/actionHandlers/removeEntityRelations.ts +3 -2
- package/src/plugins/dataManage/actionHandlers/updateCollectionEntityById.ts +9 -2
- package/src/plugins/metaManage/MetaManagePlugin.ts +33 -2
- package/src/server.ts +6 -4
- package/src/types.ts +37 -25
package/dist/core/server.d.ts
CHANGED
|
@@ -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<
|
|
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(
|
|
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(
|
|
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,
|
|
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,
|
|
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
|
-
}),
|
|
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(
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
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,
|
|
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(
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
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,
|
|
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,
|
|
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(
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
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,
|
|
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(
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
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,
|
|
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,
|
|
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(
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
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(
|
|
2752
|
-
|
|
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(
|
|
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
|
|
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(
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
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(
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
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(
|
|
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(
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
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(
|
|
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(
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
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(
|
|
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.
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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.
|
|
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<
|
|
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>;
|