@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.
- package/dist/core/server.d.ts +2 -2
- package/dist/dataAccess/entityManager.d.ts +3 -3
- package/dist/index.js +213 -85
- package/dist/server.d.ts +2 -2
- package/dist/types.d.ts +35 -9
- package/package.json +1 -1
- package/src/core/server.ts +2 -2
- package/src/dataAccess/entityManager.ts +121 -65
- package/src/plugins/dataManage/actionHandlers/addEntityRelations.ts +3 -2
- package/src/plugins/dataManage/actionHandlers/countCollectionEntities.ts +3 -2
- package/src/plugins/dataManage/actionHandlers/createCollectionEntitiesBatch.ts +1 -0
- package/src/plugins/dataManage/actionHandlers/createCollectionEntity.ts +1 -0
- package/src/plugins/dataManage/actionHandlers/deleteCollectionEntityById.ts +4 -1
- package/src/plugins/dataManage/actionHandlers/findCollectionEntities.ts +1 -0
- 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 +38 -9
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,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,
|
|
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
|
-
|
|
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,
|
|
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(
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
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,
|
|
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,
|
|
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(
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
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,
|
|
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(
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
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,
|
|
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,
|
|
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(
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
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(
|
|
2749
|
-
|
|
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(
|
|
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
|
|
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(
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
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(
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
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(
|
|
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(
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
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(
|
|
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(
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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<
|
|
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>;
|