@ruiapp/rapid-core 0.5.2 → 0.5.3
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 +3 -3
- package/dist/dataAccess/entityManager.d.ts +2 -0
- package/dist/helpers/metaHelper.d.ts +2 -2
- package/dist/index.js +192 -82
- package/dist/server.d.ts +3 -3
- package/dist/types.d.ts +5 -0
- package/package.json +1 -1
- package/src/bootstrapApplicationConfig.ts +7 -0
- package/src/core/server.ts +3 -2
- package/src/dataAccess/entityManager.ts +214 -81
- package/src/helpers/metaHelper.ts +22 -7
- package/src/server.ts +5 -4
- package/src/types.ts +7 -0
package/dist/core/server.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CreateEntityOptions, EmitServerEventOptions, EntityWatcherType, GetDataAccessorOptions, GetModelOptions, IDatabaseAccessor, IDatabaseConfig, IQueryBuilder, IRpdDataAccessor, RapidServerConfig, RpdApplicationConfig, RpdDataModel, RpdDataModelProperty, RpdServerEventTypes, UpdateEntityByIdOptions } from "../types";
|
|
1
|
+
import { CreateEntityOptions, EmitServerEventOptions, EntityWatcherType, GetDataAccessorOptions, GetModelOptions, IDatabaseAccessor, IDatabaseClient, 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";
|
|
@@ -12,8 +12,8 @@ export interface IRpdServer {
|
|
|
12
12
|
registerFacilityFactory(factory: FacilityFactory): any;
|
|
13
13
|
getFacility<TFacility = any>(name: string, options?: any): Promise<TFacility>;
|
|
14
14
|
getDatabaseAccessor(): IDatabaseAccessor;
|
|
15
|
-
queryDatabaseObject: (sql: string, params?: unknown[] | Record<string, unknown
|
|
16
|
-
tryQueryDatabaseObject: (sql: string, params?: unknown[] | Record<string, unknown
|
|
15
|
+
queryDatabaseObject: (sql: string, params?: unknown[] | Record<string, unknown>, client?: IDatabaseClient) => Promise<any[]>;
|
|
16
|
+
tryQueryDatabaseObject: (sql: string, params?: unknown[] | Record<string, unknown>, client?: IDatabaseClient) => Promise<any[]>;
|
|
17
17
|
registerMiddleware(middleware: any): void;
|
|
18
18
|
registerActionHandler(plugin: RapidPlugin, options: IPluginActionHandler): void;
|
|
19
19
|
getActionHandlerByCode(code: string): ActionHandler | undefined;
|
|
@@ -3,6 +3,7 @@ import { IRpdServer, RapidPlugin } from "../core/server";
|
|
|
3
3
|
import { RouteContext } from "../core/routeContext";
|
|
4
4
|
export type FindOneRelationEntitiesOptions = {
|
|
5
5
|
server: IRpdServer;
|
|
6
|
+
routeContext?: RouteContext;
|
|
6
7
|
mainModel: RpdDataModel;
|
|
7
8
|
relationProperty: RpdDataModelProperty;
|
|
8
9
|
relationEntityIds: any[];
|
|
@@ -10,6 +11,7 @@ export type FindOneRelationEntitiesOptions = {
|
|
|
10
11
|
};
|
|
11
12
|
export type FindManyRelationEntitiesOptions = {
|
|
12
13
|
server: IRpdServer;
|
|
14
|
+
routeContext?: RouteContext;
|
|
13
15
|
mainModel: RpdDataModel;
|
|
14
16
|
relationProperty: RpdDataModelProperty;
|
|
15
17
|
mainEntityIds: any[];
|
|
@@ -3,8 +3,8 @@ import { RpdDataModel, RpdDataModelProperty } from "../types";
|
|
|
3
3
|
export declare function isRelationProperty(property: RpdDataModelProperty): boolean;
|
|
4
4
|
export declare function isOneRelationProperty(property: RpdDataModelProperty): boolean;
|
|
5
5
|
export declare function isManyRelationProperty(property: RpdDataModelProperty): boolean;
|
|
6
|
-
export declare function getEntityProperties(server: IRpdServer, model: RpdDataModel): RpdDataModelProperty[];
|
|
7
|
-
export declare function getEntityPropertiesIncludingBase(server: IRpdServer, model: RpdDataModel): RpdDataModelProperty[];
|
|
6
|
+
export declare function getEntityProperties(server: IRpdServer, model: RpdDataModel, predicate?: (item: RpdDataModelProperty) => boolean): RpdDataModelProperty[];
|
|
7
|
+
export declare function getEntityPropertiesIncludingBase(server: IRpdServer, model: RpdDataModel, predicate?: (item: RpdDataModelProperty) => boolean): RpdDataModelProperty[];
|
|
8
8
|
export declare function getEntityPropertyByCode(server: IRpdServer, model: RpdDataModel, propertyCode: string): RpdDataModelProperty | undefined;
|
|
9
9
|
export declare function getEntityProperty(server: IRpdServer, model: RpdDataModel, predicate: (item: RpdDataModelProperty) => boolean): RpdDataModelProperty | undefined;
|
|
10
10
|
export declare function getEntityOwnPropertyByCode(model: RpdDataModel, propertyCode: string): RpdDataModelProperty | undefined;
|
package/dist/index.js
CHANGED
|
@@ -1712,6 +1712,13 @@ var bootstrapApplicationConfig = {
|
|
|
1712
1712
|
type: "text",
|
|
1713
1713
|
required: false,
|
|
1714
1714
|
},
|
|
1715
|
+
{
|
|
1716
|
+
name: "entityDeletingReaction",
|
|
1717
|
+
code: "entityDeletingReaction",
|
|
1718
|
+
columnName: "entity_deleting_reaction",
|
|
1719
|
+
type: "text",
|
|
1720
|
+
required: false,
|
|
1721
|
+
},
|
|
1715
1722
|
{
|
|
1716
1723
|
name: "readonly",
|
|
1717
1724
|
code: "readonly",
|
|
@@ -2119,22 +2126,41 @@ function isOneRelationProperty(property) {
|
|
|
2119
2126
|
function isManyRelationProperty(property) {
|
|
2120
2127
|
return isRelationProperty(property) && property.relation === "many";
|
|
2121
2128
|
}
|
|
2122
|
-
function
|
|
2123
|
-
if (!
|
|
2129
|
+
function getEntityProperties(server, model, predicate) {
|
|
2130
|
+
if (!predicate) {
|
|
2124
2131
|
return model.properties;
|
|
2125
2132
|
}
|
|
2133
|
+
return lodash.filter(model.properties, predicate);
|
|
2134
|
+
}
|
|
2135
|
+
function getEntityPropertiesIncludingBase(server, model, predicate) {
|
|
2136
|
+
if (!model.base) {
|
|
2137
|
+
return getEntityProperties(server, model, predicate);
|
|
2138
|
+
}
|
|
2126
2139
|
const baseModel = server.getModel({
|
|
2127
2140
|
singularCode: model.base,
|
|
2128
2141
|
});
|
|
2129
2142
|
let baseProperties = [];
|
|
2130
2143
|
if (baseModel) {
|
|
2131
|
-
|
|
2144
|
+
if (predicate) {
|
|
2145
|
+
baseProperties = lodash.filter(baseModel.properties, predicate);
|
|
2146
|
+
}
|
|
2147
|
+
else {
|
|
2148
|
+
baseProperties = baseModel.properties;
|
|
2149
|
+
}
|
|
2150
|
+
baseProperties = baseProperties.map((property) => {
|
|
2132
2151
|
property = lodash.cloneDeep(property);
|
|
2133
2152
|
property.isBaseProperty = true;
|
|
2134
2153
|
return property;
|
|
2135
2154
|
});
|
|
2136
2155
|
}
|
|
2137
|
-
|
|
2156
|
+
let properties;
|
|
2157
|
+
if (predicate) {
|
|
2158
|
+
properties = lodash.filter(model.properties, predicate);
|
|
2159
|
+
}
|
|
2160
|
+
else {
|
|
2161
|
+
properties = model.properties;
|
|
2162
|
+
}
|
|
2163
|
+
return [...baseProperties, ...properties];
|
|
2138
2164
|
}
|
|
2139
2165
|
function getEntityPropertyByCode(server, model, propertyCode) {
|
|
2140
2166
|
return getEntityProperty(server, model, (e) => e.code === propertyCode);
|
|
@@ -2539,6 +2565,7 @@ async function findEntities(server, dataAccessor, options) {
|
|
|
2539
2565
|
if (isManyRelation) {
|
|
2540
2566
|
const relationLinks = await findManyRelationLinksViaLinkTable({
|
|
2541
2567
|
server,
|
|
2568
|
+
routeContext,
|
|
2542
2569
|
mainModel: relationModel,
|
|
2543
2570
|
relationProperty,
|
|
2544
2571
|
mainEntityIds: entityIds,
|
|
@@ -2556,6 +2583,7 @@ async function findEntities(server, dataAccessor, options) {
|
|
|
2556
2583
|
if (isManyRelation) {
|
|
2557
2584
|
relatedEntities = await findManyRelatedEntitiesViaIdPropertyCode({
|
|
2558
2585
|
server,
|
|
2586
|
+
routeContext,
|
|
2559
2587
|
mainModel: model,
|
|
2560
2588
|
relationProperty,
|
|
2561
2589
|
mainEntityIds: entityIds,
|
|
@@ -2566,6 +2594,7 @@ async function findEntities(server, dataAccessor, options) {
|
|
|
2566
2594
|
const targetEntityIds = lodash.uniq(lodash.reject(lodash.map(rows, (entity) => entity[relationProperty.targetIdColumnName]), isNullOrUndefined));
|
|
2567
2595
|
relatedEntities = await findOneRelatedEntitiesViaIdPropertyCode({
|
|
2568
2596
|
server,
|
|
2597
|
+
routeContext,
|
|
2569
2598
|
mainModel: model,
|
|
2570
2599
|
relationProperty,
|
|
2571
2600
|
relationEntityIds: targetEntityIds,
|
|
@@ -2782,7 +2811,7 @@ async function convertEntityFiltersToRowFilters(routeContext, server, model, bas
|
|
|
2782
2811
|
tableName: relationProperty.linkTableName,
|
|
2783
2812
|
})} WHERE ${server.queryBuilder.quoteObject(relationProperty.targetIdColumnName)} = ANY($1::int[])`;
|
|
2784
2813
|
const params = [targetEntityIds];
|
|
2785
|
-
const links = await server.queryDatabaseObject(command, params);
|
|
2814
|
+
const links = await server.queryDatabaseObject(command, params, routeContext?.getDbTransactionClient());
|
|
2786
2815
|
const selfEntityIds = links.map((link) => link[relationProperty.selfIdColumnName]);
|
|
2787
2816
|
replacedFilters.push({
|
|
2788
2817
|
field: {
|
|
@@ -2850,7 +2879,7 @@ async function convertEntityFiltersToRowFilters(routeContext, server, model, bas
|
|
|
2850
2879
|
return replacedFilters;
|
|
2851
2880
|
}
|
|
2852
2881
|
async function findManyRelationLinksViaLinkTable(options) {
|
|
2853
|
-
const { server, relationProperty, mainModel: relationModel, mainEntityIds, selectRelationOptions } = options;
|
|
2882
|
+
const { server, routeContext, relationProperty, mainModel: relationModel, mainEntityIds, selectRelationOptions } = options;
|
|
2854
2883
|
const command = `SELECT * FROM ${server.queryBuilder.quoteTable({
|
|
2855
2884
|
schema: relationProperty.linkSchema,
|
|
2856
2885
|
tableName: relationProperty.linkTableName,
|
|
@@ -2858,7 +2887,7 @@ async function findManyRelationLinksViaLinkTable(options) {
|
|
|
2858
2887
|
ORDER BY id
|
|
2859
2888
|
`;
|
|
2860
2889
|
const params = [mainEntityIds];
|
|
2861
|
-
const links = await server.queryDatabaseObject(command, params);
|
|
2890
|
+
const links = await server.queryDatabaseObject(command, params, routeContext?.getDbTransactionClient());
|
|
2862
2891
|
const targetEntityIds = links.map((link) => link[relationProperty.targetIdColumnName]);
|
|
2863
2892
|
const dataAccessor = server.getDataAccessor({
|
|
2864
2893
|
namespace: relationModel.namespace,
|
|
@@ -3160,7 +3189,7 @@ async function createEntity(server, dataAccessor, options, plugin) {
|
|
|
3160
3189
|
tableName: property.linkTableName,
|
|
3161
3190
|
})} (${server.queryBuilder.quoteObject(property.selfIdColumnName)}, ${property.targetIdColumnName}) VALUES ($1, $2) ON CONFLICT DO NOTHING;`;
|
|
3162
3191
|
const params = [newEntity.id, newTargetEntity.id];
|
|
3163
|
-
await server.queryDatabaseObject(command, params);
|
|
3192
|
+
await server.queryDatabaseObject(command, params, routeContext?.getDbTransactionClient());
|
|
3164
3193
|
}
|
|
3165
3194
|
newEntity[property.code].push(newTargetEntity);
|
|
3166
3195
|
}
|
|
@@ -3176,7 +3205,7 @@ async function createEntity(server, dataAccessor, options, plugin) {
|
|
|
3176
3205
|
tableName: property.linkTableName,
|
|
3177
3206
|
})} (${server.queryBuilder.quoteObject(property.selfIdColumnName)}, ${property.targetIdColumnName}) VALUES ($1, $2) ON CONFLICT DO NOTHING;`;
|
|
3178
3207
|
const params = [newEntity.id, relatedEntityId];
|
|
3179
|
-
await server.queryDatabaseObject(command, params);
|
|
3208
|
+
await server.queryDatabaseObject(command, params, routeContext?.getDbTransactionClient());
|
|
3180
3209
|
}
|
|
3181
3210
|
else {
|
|
3182
3211
|
await targetDataAccessor.updateById(targetEntity.id, { [property.selfIdColumnName]: newEntity.id }, routeContext?.getDbTransactionClient());
|
|
@@ -3198,7 +3227,7 @@ async function createEntity(server, dataAccessor, options, plugin) {
|
|
|
3198
3227
|
tableName: property.linkTableName,
|
|
3199
3228
|
})} (${server.queryBuilder.quoteObject(property.selfIdColumnName)}, ${property.targetIdColumnName}) VALUES ($1, $2) ON CONFLICT DO NOTHING;`;
|
|
3200
3229
|
const params = [newEntity.id, relatedEntityId];
|
|
3201
|
-
await server.queryDatabaseObject(command, params);
|
|
3230
|
+
await server.queryDatabaseObject(command, params, routeContext?.getDbTransactionClient());
|
|
3202
3231
|
}
|
|
3203
3232
|
else {
|
|
3204
3233
|
await targetDataAccessor.updateById(targetEntity.id, { [property.selfIdColumnName]: newEntity.id }, routeContext?.getDbTransactionClient());
|
|
@@ -3469,13 +3498,13 @@ async function updateEntityById(server, dataAccessor, options, plugin) {
|
|
|
3469
3498
|
const targetLinks = await server.queryDatabaseObject(`SELECT ${server.queryBuilder.quoteObject(property.targetIdColumnName)} FROM ${server.queryBuilder.quoteTable({
|
|
3470
3499
|
schema: property.linkSchema,
|
|
3471
3500
|
tableName: property.linkTableName,
|
|
3472
|
-
})} WHERE ${server.queryBuilder.quoteObject(property.selfIdColumnName)} = $1`, [id]);
|
|
3501
|
+
})} WHERE ${server.queryBuilder.quoteObject(property.selfIdColumnName)} = $1`, [id], routeContext?.getDbTransactionClient());
|
|
3473
3502
|
currentTargetIds = targetLinks.map((item) => item[property.targetIdColumnName]);
|
|
3474
3503
|
await server.queryDatabaseObject(`DELETE FROM ${server.queryBuilder.quoteTable({
|
|
3475
3504
|
schema: property.linkSchema,
|
|
3476
3505
|
tableName: property.linkTableName,
|
|
3477
3506
|
})} WHERE ${server.queryBuilder.quoteObject(property.selfIdColumnName)} = $1
|
|
3478
|
-
AND ${server.queryBuilder.quoteObject(property.targetIdColumnName)} <> ALL($2::int[])`, [id, targetIdsToKeep]);
|
|
3507
|
+
AND ${server.queryBuilder.quoteObject(property.targetIdColumnName)} <> ALL($2::int[])`, [id, targetIdsToKeep], routeContext?.getDbTransactionClient());
|
|
3479
3508
|
}
|
|
3480
3509
|
else {
|
|
3481
3510
|
const targetModel = server.getModel({
|
|
@@ -3484,7 +3513,7 @@ async function updateEntityById(server, dataAccessor, options, plugin) {
|
|
|
3484
3513
|
const targetRows = await server.queryDatabaseObject(`SELECT id FROM ${server.queryBuilder.quoteTable({
|
|
3485
3514
|
schema: targetModel.schema,
|
|
3486
3515
|
tableName: targetModel.tableName,
|
|
3487
|
-
})} WHERE ${server.queryBuilder.quoteObject(property.selfIdColumnName)} = $1`, [id]);
|
|
3516
|
+
})} WHERE ${server.queryBuilder.quoteObject(property.selfIdColumnName)} = $1`, [id], routeContext?.getDbTransactionClient());
|
|
3488
3517
|
currentTargetIds = targetRows.map((item) => item.id);
|
|
3489
3518
|
}
|
|
3490
3519
|
for (const relatedEntityToBeSaved of relatedEntitiesToBeSaved) {
|
|
@@ -3507,7 +3536,7 @@ async function updateEntityById(server, dataAccessor, options, plugin) {
|
|
|
3507
3536
|
tableName: property.linkTableName,
|
|
3508
3537
|
})} (${server.queryBuilder.quoteObject(property.selfIdColumnName)}, ${property.targetIdColumnName}) VALUES ($1, $2) ON CONFLICT DO NOTHING;`;
|
|
3509
3538
|
const params = [id, newTargetEntity.id];
|
|
3510
|
-
await server.queryDatabaseObject(command, params);
|
|
3539
|
+
await server.queryDatabaseObject(command, params, routeContext?.getDbTransactionClient());
|
|
3511
3540
|
}
|
|
3512
3541
|
relatedEntities.push(newTargetEntity);
|
|
3513
3542
|
}
|
|
@@ -3548,7 +3577,7 @@ async function updateEntityById(server, dataAccessor, options, plugin) {
|
|
|
3548
3577
|
tableName: property.linkTableName,
|
|
3549
3578
|
})} (${server.queryBuilder.quoteObject(property.selfIdColumnName)}, ${property.targetIdColumnName}) VALUES ($1, $2) ON CONFLICT DO NOTHING;`;
|
|
3550
3579
|
const params = [id, relatedEntityId];
|
|
3551
|
-
await server.queryDatabaseObject(command, params);
|
|
3580
|
+
await server.queryDatabaseObject(command, params, routeContext?.getDbTransactionClient());
|
|
3552
3581
|
}
|
|
3553
3582
|
else {
|
|
3554
3583
|
await targetDataAccessor.updateById(targetEntity.id, { [property.selfIdColumnName]: id }, routeContext?.getDbTransactionClient());
|
|
@@ -3572,7 +3601,7 @@ async function updateEntityById(server, dataAccessor, options, plugin) {
|
|
|
3572
3601
|
tableName: property.linkTableName,
|
|
3573
3602
|
})} (${server.queryBuilder.quoteObject(property.selfIdColumnName)}, ${property.targetIdColumnName}) VALUES ($1, $2) ON CONFLICT DO NOTHING;`;
|
|
3574
3603
|
const params = [id, relatedEntityId];
|
|
3575
|
-
await server.queryDatabaseObject(command, params);
|
|
3604
|
+
await server.queryDatabaseObject(command, params, routeContext?.getDbTransactionClient());
|
|
3576
3605
|
}
|
|
3577
3606
|
else {
|
|
3578
3607
|
await targetDataAccessor.updateById(targetEntity.id, { [property.selfIdColumnName]: id }, routeContext?.getDbTransactionClient());
|
|
@@ -3654,6 +3683,146 @@ function getEntityDuplicatedErrorMessage(server, model, indexConfig) {
|
|
|
3654
3683
|
});
|
|
3655
3684
|
return `已存在 ${propertyNames.join(", ")} 相同的记录。`;
|
|
3656
3685
|
}
|
|
3686
|
+
async function deleteEntityById(server, dataAccessor, options, plugin) {
|
|
3687
|
+
// options is id
|
|
3688
|
+
if (!lodash.isObject(options)) {
|
|
3689
|
+
options = {
|
|
3690
|
+
id: options,
|
|
3691
|
+
};
|
|
3692
|
+
}
|
|
3693
|
+
const model = dataAccessor.getModel();
|
|
3694
|
+
if (model.derivedTypePropertyCode) {
|
|
3695
|
+
// TODO: should be allowed.
|
|
3696
|
+
throw newEntityOperationError("Delete base entity directly is not allowed.");
|
|
3697
|
+
}
|
|
3698
|
+
const { id, routeContext } = options;
|
|
3699
|
+
const entity = await findById(server, dataAccessor, {
|
|
3700
|
+
id,
|
|
3701
|
+
keepNonPropertyFields: true,
|
|
3702
|
+
routeContext,
|
|
3703
|
+
});
|
|
3704
|
+
if (!entity) {
|
|
3705
|
+
return;
|
|
3706
|
+
}
|
|
3707
|
+
if (model.softDelete) {
|
|
3708
|
+
if (entity.deletedAt) {
|
|
3709
|
+
return;
|
|
3710
|
+
}
|
|
3711
|
+
}
|
|
3712
|
+
await server.emitEvent({
|
|
3713
|
+
eventName: "entity.beforeDelete",
|
|
3714
|
+
payload: {
|
|
3715
|
+
namespace: model.namespace,
|
|
3716
|
+
modelSingularCode: model.singularCode,
|
|
3717
|
+
before: entity,
|
|
3718
|
+
},
|
|
3719
|
+
sender: plugin,
|
|
3720
|
+
routeContext,
|
|
3721
|
+
});
|
|
3722
|
+
if (model.softDelete) {
|
|
3723
|
+
const currentUserId = routeContext?.state?.userId;
|
|
3724
|
+
await dataAccessor.updateById(id, {
|
|
3725
|
+
deleted_at: getNowStringWithTimezone(),
|
|
3726
|
+
deleter_id: currentUserId,
|
|
3727
|
+
}, routeContext?.getDbTransactionClient());
|
|
3728
|
+
}
|
|
3729
|
+
else {
|
|
3730
|
+
const relationPropertiesWithDeletingReaction = getEntityPropertiesIncludingBase(server, model, (property) => {
|
|
3731
|
+
return isRelationProperty(property) && property.entityDeletingReaction && property.entityDeletingReaction !== "doNothing";
|
|
3732
|
+
});
|
|
3733
|
+
for (const relationProperty of relationPropertiesWithDeletingReaction) {
|
|
3734
|
+
const relationDataAccessor = server.getDataAccessor({
|
|
3735
|
+
singularCode: relationProperty.targetSingularCode,
|
|
3736
|
+
});
|
|
3737
|
+
if (relationProperty.entityDeletingReaction === "cascadingDelete") {
|
|
3738
|
+
if (relationProperty.relation === "one") {
|
|
3739
|
+
const relatedEntityId = entity[relationProperty.targetIdColumnName];
|
|
3740
|
+
if (relatedEntityId) {
|
|
3741
|
+
await deleteEntityById(server, relationDataAccessor, {
|
|
3742
|
+
routeContext,
|
|
3743
|
+
id: relatedEntityId,
|
|
3744
|
+
}, plugin);
|
|
3745
|
+
}
|
|
3746
|
+
}
|
|
3747
|
+
else if (relationProperty.relation === "many") {
|
|
3748
|
+
if (relationProperty.linkTableName) {
|
|
3749
|
+
const targetLinks = await server.queryDatabaseObject(`SELECT ${server.queryBuilder.quoteObject(relationProperty.targetIdColumnName)} FROM ${server.queryBuilder.quoteTable({
|
|
3750
|
+
schema: relationProperty.linkSchema,
|
|
3751
|
+
tableName: relationProperty.linkTableName,
|
|
3752
|
+
})} WHERE ${server.queryBuilder.quoteObject(relationProperty.selfIdColumnName)} = $1`, [id], routeContext?.getDbTransactionClient());
|
|
3753
|
+
const targetEntityIds = targetLinks.map((item) => item[relationProperty.targetIdColumnName]);
|
|
3754
|
+
await server.queryDatabaseObject(`DELETE FROM ${server.queryBuilder.quoteTable({
|
|
3755
|
+
schema: relationProperty.linkSchema,
|
|
3756
|
+
tableName: relationProperty.linkTableName,
|
|
3757
|
+
})} WHERE ${server.queryBuilder.quoteObject(relationProperty.selfIdColumnName)} = $1`, [id], routeContext?.getDbTransactionClient());
|
|
3758
|
+
for (const targetEntityId of targetEntityIds) {
|
|
3759
|
+
await deleteEntityById(server, relationDataAccessor, {
|
|
3760
|
+
routeContext,
|
|
3761
|
+
id: targetEntityId,
|
|
3762
|
+
}, plugin);
|
|
3763
|
+
}
|
|
3764
|
+
}
|
|
3765
|
+
else {
|
|
3766
|
+
const targetModel = server.getModel({
|
|
3767
|
+
singularCode: relationProperty.targetSingularCode,
|
|
3768
|
+
});
|
|
3769
|
+
const targetRows = await server.queryDatabaseObject(`SELECT id FROM ${server.queryBuilder.quoteTable({
|
|
3770
|
+
schema: targetModel.schema,
|
|
3771
|
+
tableName: targetModel.tableName,
|
|
3772
|
+
})} WHERE ${server.queryBuilder.quoteObject(relationProperty.selfIdColumnName)} = $1`, [id], routeContext?.getDbTransactionClient());
|
|
3773
|
+
const targetEntityIds = targetRows.map((item) => item.id);
|
|
3774
|
+
for (const targetEntityId of targetEntityIds) {
|
|
3775
|
+
await deleteEntityById(server, relationDataAccessor, {
|
|
3776
|
+
routeContext,
|
|
3777
|
+
id: targetEntityId,
|
|
3778
|
+
}, plugin);
|
|
3779
|
+
}
|
|
3780
|
+
}
|
|
3781
|
+
}
|
|
3782
|
+
}
|
|
3783
|
+
else if (relationProperty.entityDeletingReaction === "unlink") {
|
|
3784
|
+
if (relationProperty.relation === "one") ;
|
|
3785
|
+
else if (relationProperty.relation === "many") {
|
|
3786
|
+
if (relationProperty.linkTableName) {
|
|
3787
|
+
await server.queryDatabaseObject(`DELETE FROM ${server.queryBuilder.quoteTable({
|
|
3788
|
+
schema: relationProperty.linkSchema,
|
|
3789
|
+
tableName: relationProperty.linkTableName,
|
|
3790
|
+
})}
|
|
3791
|
+
WHERE ${server.queryBuilder.quoteObject(relationProperty.selfIdColumnName)} = $1`, [id], routeContext?.getDbTransactionClient());
|
|
3792
|
+
}
|
|
3793
|
+
else {
|
|
3794
|
+
const relationModel = server.getModel({
|
|
3795
|
+
singularCode: relationProperty.targetSingularCode,
|
|
3796
|
+
});
|
|
3797
|
+
await server.queryDatabaseObject(`UPDATE ${server.queryBuilder.quoteTable({
|
|
3798
|
+
schema: relationModel.schema,
|
|
3799
|
+
tableName: relationModel.tableName,
|
|
3800
|
+
})}
|
|
3801
|
+
SET ${server.queryBuilder.quoteObject(relationProperty.selfIdColumnName)} = null
|
|
3802
|
+
WHERE ${server.queryBuilder.quoteObject(relationProperty.selfIdColumnName)} = $1`, [id], routeContext?.getDbTransactionClient());
|
|
3803
|
+
}
|
|
3804
|
+
}
|
|
3805
|
+
}
|
|
3806
|
+
}
|
|
3807
|
+
await dataAccessor.deleteById(id, routeContext?.getDbTransactionClient());
|
|
3808
|
+
if (model.base) {
|
|
3809
|
+
const baseDataAccessor = server.getDataAccessor({
|
|
3810
|
+
singularCode: model.base,
|
|
3811
|
+
});
|
|
3812
|
+
await baseDataAccessor.deleteById(id, routeContext?.getDbTransactionClient());
|
|
3813
|
+
}
|
|
3814
|
+
}
|
|
3815
|
+
await server.emitEvent({
|
|
3816
|
+
eventName: "entity.delete",
|
|
3817
|
+
payload: {
|
|
3818
|
+
namespace: model.namespace,
|
|
3819
|
+
modelSingularCode: model.singularCode,
|
|
3820
|
+
before: entity,
|
|
3821
|
+
},
|
|
3822
|
+
sender: plugin,
|
|
3823
|
+
routeContext,
|
|
3824
|
+
});
|
|
3825
|
+
}
|
|
3657
3826
|
class EntityManager {
|
|
3658
3827
|
#server;
|
|
3659
3828
|
#dataAccessor;
|
|
@@ -3700,66 +3869,7 @@ class EntityManager {
|
|
|
3700
3869
|
return await this.#dataAccessor.count(countRowOptions, routeContext?.getDbTransactionClient());
|
|
3701
3870
|
}
|
|
3702
3871
|
async deleteById(options, plugin) {
|
|
3703
|
-
|
|
3704
|
-
if (!lodash.isObject(options)) {
|
|
3705
|
-
options = {
|
|
3706
|
-
id: options,
|
|
3707
|
-
};
|
|
3708
|
-
}
|
|
3709
|
-
const model = this.getModel();
|
|
3710
|
-
if (model.derivedTypePropertyCode) {
|
|
3711
|
-
throw newEntityOperationError("Delete base entity directly is not allowed.");
|
|
3712
|
-
}
|
|
3713
|
-
const { id, routeContext } = options;
|
|
3714
|
-
const entity = await this.findById({
|
|
3715
|
-
id,
|
|
3716
|
-
keepNonPropertyFields: true,
|
|
3717
|
-
routeContext,
|
|
3718
|
-
});
|
|
3719
|
-
if (!entity) {
|
|
3720
|
-
return;
|
|
3721
|
-
}
|
|
3722
|
-
await this.#server.emitEvent({
|
|
3723
|
-
eventName: "entity.beforeDelete",
|
|
3724
|
-
payload: {
|
|
3725
|
-
namespace: model.namespace,
|
|
3726
|
-
modelSingularCode: model.singularCode,
|
|
3727
|
-
before: entity,
|
|
3728
|
-
},
|
|
3729
|
-
sender: plugin,
|
|
3730
|
-
routeContext,
|
|
3731
|
-
});
|
|
3732
|
-
if (model.softDelete) {
|
|
3733
|
-
let dataAccessor = model.base
|
|
3734
|
-
? this.#server.getDataAccessor({
|
|
3735
|
-
singularCode: model.base,
|
|
3736
|
-
})
|
|
3737
|
-
: this.#dataAccessor;
|
|
3738
|
-
const currentUserId = routeContext?.state?.userId;
|
|
3739
|
-
await dataAccessor.updateById(id, {
|
|
3740
|
-
deleted_at: getNowStringWithTimezone(),
|
|
3741
|
-
deleter_id: currentUserId,
|
|
3742
|
-
}, routeContext?.getDbTransactionClient());
|
|
3743
|
-
}
|
|
3744
|
-
else {
|
|
3745
|
-
await this.#dataAccessor.deleteById(id, routeContext?.getDbTransactionClient());
|
|
3746
|
-
if (model.base) {
|
|
3747
|
-
const baseDataAccessor = this.#server.getDataAccessor({
|
|
3748
|
-
singularCode: model.base,
|
|
3749
|
-
});
|
|
3750
|
-
await baseDataAccessor.deleteById(id, routeContext?.getDbTransactionClient());
|
|
3751
|
-
}
|
|
3752
|
-
}
|
|
3753
|
-
await this.#server.emitEvent({
|
|
3754
|
-
eventName: "entity.delete",
|
|
3755
|
-
payload: {
|
|
3756
|
-
namespace: model.namespace,
|
|
3757
|
-
modelSingularCode: model.singularCode,
|
|
3758
|
-
before: entity,
|
|
3759
|
-
},
|
|
3760
|
-
sender: plugin,
|
|
3761
|
-
routeContext,
|
|
3762
|
-
});
|
|
3872
|
+
return await deleteEntityById(this.#server, this.#dataAccessor, options, plugin);
|
|
3763
3873
|
}
|
|
3764
3874
|
async addRelations(options, plugin) {
|
|
3765
3875
|
const server = this.#server;
|
|
@@ -3792,7 +3902,7 @@ class EntityManager {
|
|
|
3792
3902
|
WHERE ${queryBuilder.quoteObject(relationProperty.selfIdColumnName)}=$1 AND ${queryBuilder.quoteObject(relationProperty.targetIdColumnName)}=$2
|
|
3793
3903
|
)`;
|
|
3794
3904
|
const params = [id, relation.id];
|
|
3795
|
-
await server.queryDatabaseObject(command, params);
|
|
3905
|
+
await server.queryDatabaseObject(command, params, routeContext?.getDbTransactionClient());
|
|
3796
3906
|
}
|
|
3797
3907
|
}
|
|
3798
3908
|
await server.emitEvent({
|
|
@@ -3832,7 +3942,7 @@ class EntityManager {
|
|
|
3832
3942
|
const command = `DELETE FROM ${queryBuilder.quoteTable({ schema: relationProperty.linkSchema, tableName: relationProperty.linkTableName })}
|
|
3833
3943
|
WHERE ${queryBuilder.quoteObject(relationProperty.selfIdColumnName)}=$1 AND ${queryBuilder.quoteObject(relationProperty.targetIdColumnName)}=$2;`;
|
|
3834
3944
|
const params = [id, relation.id];
|
|
3835
|
-
await server.queryDatabaseObject(command, params);
|
|
3945
|
+
await server.queryDatabaseObject(command, params, routeContext?.getDbTransactionClient());
|
|
3836
3946
|
}
|
|
3837
3947
|
}
|
|
3838
3948
|
await server.emitEvent({
|
|
@@ -4139,18 +4249,18 @@ class RapidServer {
|
|
|
4139
4249
|
}
|
|
4140
4250
|
return await factory.createFacility(this, options);
|
|
4141
4251
|
}
|
|
4142
|
-
async queryDatabaseObject(sql, params) {
|
|
4252
|
+
async queryDatabaseObject(sql, params, client) {
|
|
4143
4253
|
try {
|
|
4144
|
-
return await this.#databaseAccessor.queryDatabaseObject(sql, params);
|
|
4254
|
+
return await this.#databaseAccessor.queryDatabaseObject(sql, params, client);
|
|
4145
4255
|
}
|
|
4146
4256
|
catch (err) {
|
|
4147
4257
|
this.#logger.error("Failed to query database object.", { errorMessage: err.message, sql, params });
|
|
4148
4258
|
throw err;
|
|
4149
4259
|
}
|
|
4150
4260
|
}
|
|
4151
|
-
async tryQueryDatabaseObject(sql, params) {
|
|
4261
|
+
async tryQueryDatabaseObject(sql, params, client) {
|
|
4152
4262
|
try {
|
|
4153
|
-
return await this.queryDatabaseObject(sql, params);
|
|
4263
|
+
return await this.queryDatabaseObject(sql, params, client);
|
|
4154
4264
|
}
|
|
4155
4265
|
catch (err) {
|
|
4156
4266
|
this.#logger.error("Failed to query database object.", { errorMessage: err.message, sql, params });
|
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, EmitServerEventOptions } from "./types";
|
|
1
|
+
import { GetDataAccessorOptions, GetModelOptions, IDatabaseAccessor, IDatabaseConfig, IQueryBuilder, IRpdDataAccessor, RpdApplicationConfig, RpdDataModel, RpdServerEventTypes, RapidServerConfig, RpdDataModelProperty, CreateEntityOptions, UpdateEntityByIdOptions, EntityWatcherType, EmitServerEventOptions, IDatabaseClient } 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";
|
|
@@ -41,8 +41,8 @@ export declare class RapidServer implements IRpdServer {
|
|
|
41
41
|
configureApplication(): Promise<void>;
|
|
42
42
|
registerFacilityFactory(factory: FacilityFactory): void;
|
|
43
43
|
getFacility<TFacility = any>(name: string, options?: any, nullIfUnknownFacility?: boolean): Promise<TFacility>;
|
|
44
|
-
queryDatabaseObject(sql: string, params?: unknown[] | Record<string, unknown
|
|
45
|
-
tryQueryDatabaseObject(sql: string, params?: unknown[] | Record<string, unknown
|
|
44
|
+
queryDatabaseObject(sql: string, params?: unknown[] | Record<string, unknown>, client?: IDatabaseClient): Promise<any[]>;
|
|
45
|
+
tryQueryDatabaseObject(sql: string, params?: unknown[] | Record<string, unknown>, client?: IDatabaseClient): Promise<any[]>;
|
|
46
46
|
get middlewares(): any[];
|
|
47
47
|
handleRequest(request: Request, next: Next): Promise<Response>;
|
|
48
48
|
beforeRunRouteActions(handlerContext: ActionHandlerContext): Promise<void>;
|
package/dist/types.d.ts
CHANGED
|
@@ -282,12 +282,17 @@ export interface RpdDataModelProperty {
|
|
|
282
282
|
* 当设置了 linkTableName 时,可以设置关联关系表所在的 Schema。
|
|
283
283
|
*/
|
|
284
284
|
linkSchema?: string;
|
|
285
|
+
/**
|
|
286
|
+
* 当删除实体时,针对关系属性的联动处理。
|
|
287
|
+
*/
|
|
288
|
+
entityDeletingReaction?: RpdEntityDeleteRelationPropertyReaction;
|
|
285
289
|
/**
|
|
286
290
|
* 当设置为`true`时,仅允许在创建时设置此属性的值,不允许更新。
|
|
287
291
|
*/
|
|
288
292
|
readonly?: boolean;
|
|
289
293
|
}
|
|
290
294
|
export type RpdDataPropertyTypes = "integer" | "long" | "float" | "double" | "decimal" | "text" | "boolean" | "date" | "time" | "datetime" | "json" | "relation" | "relation[]" | "option" | "option[]" | "file" | "file[]" | "image" | "image[]";
|
|
295
|
+
export type RpdEntityDeleteRelationPropertyReaction = "doNothing" | "unlink" | "cascadingDelete";
|
|
291
296
|
/**
|
|
292
297
|
* 数据字典
|
|
293
298
|
*/
|
package/package.json
CHANGED
|
@@ -237,6 +237,13 @@ export default {
|
|
|
237
237
|
type: "text",
|
|
238
238
|
required: false,
|
|
239
239
|
},
|
|
240
|
+
{
|
|
241
|
+
name: "entityDeletingReaction",
|
|
242
|
+
code: "entityDeletingReaction",
|
|
243
|
+
columnName: "entity_deleting_reaction",
|
|
244
|
+
type: "text",
|
|
245
|
+
required: false,
|
|
246
|
+
},
|
|
240
247
|
{
|
|
241
248
|
name: "readonly",
|
|
242
249
|
code: "readonly",
|
package/src/core/server.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
GetDataAccessorOptions,
|
|
6
6
|
GetModelOptions,
|
|
7
7
|
IDatabaseAccessor,
|
|
8
|
+
IDatabaseClient,
|
|
8
9
|
IDatabaseConfig,
|
|
9
10
|
IQueryBuilder,
|
|
10
11
|
IRpdDataAccessor,
|
|
@@ -32,8 +33,8 @@ export interface IRpdServer {
|
|
|
32
33
|
getFacility<TFacility = any>(name: string, options?: any): Promise<TFacility>;
|
|
33
34
|
|
|
34
35
|
getDatabaseAccessor(): IDatabaseAccessor;
|
|
35
|
-
queryDatabaseObject: (sql: string, params?: unknown[] | Record<string, unknown
|
|
36
|
-
tryQueryDatabaseObject: (sql: string, params?: unknown[] | Record<string, unknown
|
|
36
|
+
queryDatabaseObject: (sql: string, params?: unknown[] | Record<string, unknown>, client?: IDatabaseClient) => Promise<any[]>;
|
|
37
|
+
tryQueryDatabaseObject: (sql: string, params?: unknown[] | Record<string, unknown>, client?: IDatabaseClient) => Promise<any[]>;
|
|
37
38
|
registerMiddleware(middleware: any): void;
|
|
38
39
|
registerActionHandler(plugin: RapidPlugin, options: IPluginActionHandler): void;
|
|
39
40
|
getActionHandlerByCode(code: string): ActionHandler | undefined;
|
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
uniq,
|
|
46
46
|
} from "lodash";
|
|
47
47
|
import {
|
|
48
|
+
getEntityProperties,
|
|
48
49
|
getEntityPropertiesIncludingBase,
|
|
49
50
|
getEntityProperty,
|
|
50
51
|
getEntityPropertyByCode,
|
|
@@ -60,6 +61,7 @@ import { RouteContext } from "~/core/routeContext";
|
|
|
60
61
|
|
|
61
62
|
export type FindOneRelationEntitiesOptions = {
|
|
62
63
|
server: IRpdServer;
|
|
64
|
+
routeContext?: RouteContext;
|
|
63
65
|
mainModel: RpdDataModel;
|
|
64
66
|
relationProperty: RpdDataModelProperty;
|
|
65
67
|
relationEntityIds: any[];
|
|
@@ -68,6 +70,7 @@ export type FindOneRelationEntitiesOptions = {
|
|
|
68
70
|
|
|
69
71
|
export type FindManyRelationEntitiesOptions = {
|
|
70
72
|
server: IRpdServer;
|
|
73
|
+
routeContext?: RouteContext;
|
|
71
74
|
mainModel: RpdDataModel;
|
|
72
75
|
relationProperty: RpdDataModelProperty;
|
|
73
76
|
mainEntityIds: any[];
|
|
@@ -269,6 +272,7 @@ async function findEntities(server: IRpdServer, dataAccessor: IRpdDataAccessor,
|
|
|
269
272
|
if (isManyRelation) {
|
|
270
273
|
const relationLinks = await findManyRelationLinksViaLinkTable({
|
|
271
274
|
server,
|
|
275
|
+
routeContext,
|
|
272
276
|
mainModel: relationModel,
|
|
273
277
|
relationProperty,
|
|
274
278
|
mainEntityIds: entityIds,
|
|
@@ -286,6 +290,7 @@ async function findEntities(server: IRpdServer, dataAccessor: IRpdDataAccessor,
|
|
|
286
290
|
if (isManyRelation) {
|
|
287
291
|
relatedEntities = await findManyRelatedEntitiesViaIdPropertyCode({
|
|
288
292
|
server,
|
|
293
|
+
routeContext,
|
|
289
294
|
mainModel: model,
|
|
290
295
|
relationProperty,
|
|
291
296
|
mainEntityIds: entityIds,
|
|
@@ -300,6 +305,7 @@ async function findEntities(server: IRpdServer, dataAccessor: IRpdDataAccessor,
|
|
|
300
305
|
);
|
|
301
306
|
relatedEntities = await findOneRelatedEntitiesViaIdPropertyCode({
|
|
302
307
|
server,
|
|
308
|
+
routeContext,
|
|
303
309
|
mainModel: model,
|
|
304
310
|
relationProperty,
|
|
305
311
|
relationEntityIds: targetEntityIds,
|
|
@@ -546,7 +552,7 @@ async function convertEntityFiltersToRowFilters(
|
|
|
546
552
|
tableName: relationProperty.linkTableName!,
|
|
547
553
|
})} WHERE ${server.queryBuilder.quoteObject(relationProperty.targetIdColumnName!)} = ANY($1::int[])`;
|
|
548
554
|
const params = [targetEntityIds];
|
|
549
|
-
const links = await server.queryDatabaseObject(command, params);
|
|
555
|
+
const links = await server.queryDatabaseObject(command, params, routeContext?.getDbTransactionClient());
|
|
550
556
|
const selfEntityIds = links.map((link) => link[relationProperty.selfIdColumnName!]);
|
|
551
557
|
replacedFilters.push({
|
|
552
558
|
field: {
|
|
@@ -614,7 +620,7 @@ async function convertEntityFiltersToRowFilters(
|
|
|
614
620
|
}
|
|
615
621
|
|
|
616
622
|
async function findManyRelationLinksViaLinkTable(options: FindManyRelationEntitiesOptions) {
|
|
617
|
-
const { server, relationProperty, mainModel: relationModel, mainEntityIds, selectRelationOptions } = options;
|
|
623
|
+
const { server, routeContext, relationProperty, mainModel: relationModel, mainEntityIds, selectRelationOptions } = options;
|
|
618
624
|
const command = `SELECT * FROM ${server.queryBuilder.quoteTable({
|
|
619
625
|
schema: relationProperty.linkSchema,
|
|
620
626
|
tableName: relationProperty.linkTableName!,
|
|
@@ -622,7 +628,7 @@ async function findManyRelationLinksViaLinkTable(options: FindManyRelationEntiti
|
|
|
622
628
|
ORDER BY id
|
|
623
629
|
`;
|
|
624
630
|
const params = [mainEntityIds];
|
|
625
|
-
const links = await server.queryDatabaseObject(command, params);
|
|
631
|
+
const links = await server.queryDatabaseObject(command, params, routeContext?.getDbTransactionClient());
|
|
626
632
|
const targetEntityIds = links.map((link) => link[relationProperty.targetIdColumnName!]);
|
|
627
633
|
|
|
628
634
|
const dataAccessor = server.getDataAccessor({
|
|
@@ -960,7 +966,7 @@ async function createEntity(server: IRpdServer, dataAccessor: IRpdDataAccessor,
|
|
|
960
966
|
tableName: property.linkTableName,
|
|
961
967
|
})} (${server.queryBuilder.quoteObject(property.selfIdColumnName!)}, ${property.targetIdColumnName}) VALUES ($1, $2) ON CONFLICT DO NOTHING;`;
|
|
962
968
|
const params = [newEntity.id, newTargetEntity.id];
|
|
963
|
-
await server.queryDatabaseObject(command, params);
|
|
969
|
+
await server.queryDatabaseObject(command, params, routeContext?.getDbTransactionClient());
|
|
964
970
|
}
|
|
965
971
|
|
|
966
972
|
newEntity[property.code].push(newTargetEntity);
|
|
@@ -977,7 +983,7 @@ async function createEntity(server: IRpdServer, dataAccessor: IRpdDataAccessor,
|
|
|
977
983
|
tableName: property.linkTableName,
|
|
978
984
|
})} (${server.queryBuilder.quoteObject(property.selfIdColumnName!)}, ${property.targetIdColumnName}) VALUES ($1, $2) ON CONFLICT DO NOTHING;`;
|
|
979
985
|
const params = [newEntity.id, relatedEntityId];
|
|
980
|
-
await server.queryDatabaseObject(command, params);
|
|
986
|
+
await server.queryDatabaseObject(command, params, routeContext?.getDbTransactionClient());
|
|
981
987
|
} else {
|
|
982
988
|
await targetDataAccessor.updateById(targetEntity.id, { [property.selfIdColumnName!]: newEntity.id }, routeContext?.getDbTransactionClient());
|
|
983
989
|
targetEntity[property.selfIdColumnName!] = newEntity.id;
|
|
@@ -998,7 +1004,7 @@ async function createEntity(server: IRpdServer, dataAccessor: IRpdDataAccessor,
|
|
|
998
1004
|
tableName: property.linkTableName,
|
|
999
1005
|
})} (${server.queryBuilder.quoteObject(property.selfIdColumnName!)}, ${property.targetIdColumnName}) VALUES ($1, $2) ON CONFLICT DO NOTHING;`;
|
|
1000
1006
|
const params = [newEntity.id, relatedEntityId];
|
|
1001
|
-
await server.queryDatabaseObject(command, params);
|
|
1007
|
+
await server.queryDatabaseObject(command, params, routeContext?.getDbTransactionClient());
|
|
1002
1008
|
} else {
|
|
1003
1009
|
await targetDataAccessor.updateById(targetEntity.id, { [property.selfIdColumnName!]: newEntity.id }, routeContext?.getDbTransactionClient());
|
|
1004
1010
|
targetEntity[property.selfIdColumnName!] = newEntity.id;
|
|
@@ -1298,6 +1304,7 @@ async function updateEntityById(server: IRpdServer, dataAccessor: IRpdDataAccess
|
|
|
1298
1304
|
tableName: property.linkTableName,
|
|
1299
1305
|
})} WHERE ${server.queryBuilder.quoteObject(property.selfIdColumnName!)} = $1`,
|
|
1300
1306
|
[id],
|
|
1307
|
+
routeContext?.getDbTransactionClient(),
|
|
1301
1308
|
);
|
|
1302
1309
|
currentTargetIds = targetLinks.map((item) => item[property.targetIdColumnName]);
|
|
1303
1310
|
|
|
@@ -1308,6 +1315,7 @@ async function updateEntityById(server: IRpdServer, dataAccessor: IRpdDataAccess
|
|
|
1308
1315
|
})} WHERE ${server.queryBuilder.quoteObject(property.selfIdColumnName!)} = $1
|
|
1309
1316
|
AND ${server.queryBuilder.quoteObject(property.targetIdColumnName!)} <> ALL($2::int[])`,
|
|
1310
1317
|
[id, targetIdsToKeep],
|
|
1318
|
+
routeContext?.getDbTransactionClient(),
|
|
1311
1319
|
);
|
|
1312
1320
|
} else {
|
|
1313
1321
|
const targetModel = server.getModel({
|
|
@@ -1319,6 +1327,7 @@ async function updateEntityById(server: IRpdServer, dataAccessor: IRpdDataAccess
|
|
|
1319
1327
|
tableName: targetModel.tableName,
|
|
1320
1328
|
})} WHERE ${server.queryBuilder.quoteObject(property.selfIdColumnName!)} = $1`,
|
|
1321
1329
|
[id],
|
|
1330
|
+
routeContext?.getDbTransactionClient(),
|
|
1322
1331
|
);
|
|
1323
1332
|
currentTargetIds = targetRows.map((item) => item.id);
|
|
1324
1333
|
}
|
|
@@ -1344,7 +1353,7 @@ async function updateEntityById(server: IRpdServer, dataAccessor: IRpdDataAccess
|
|
|
1344
1353
|
tableName: property.linkTableName,
|
|
1345
1354
|
})} (${server.queryBuilder.quoteObject(property.selfIdColumnName!)}, ${property.targetIdColumnName}) VALUES ($1, $2) ON CONFLICT DO NOTHING;`;
|
|
1346
1355
|
const params = [id, newTargetEntity.id];
|
|
1347
|
-
await server.queryDatabaseObject(command, params);
|
|
1356
|
+
await server.queryDatabaseObject(command, params, routeContext?.getDbTransactionClient());
|
|
1348
1357
|
}
|
|
1349
1358
|
|
|
1350
1359
|
relatedEntities.push(newTargetEntity);
|
|
@@ -1386,7 +1395,7 @@ async function updateEntityById(server: IRpdServer, dataAccessor: IRpdDataAccess
|
|
|
1386
1395
|
tableName: property.linkTableName,
|
|
1387
1396
|
})} (${server.queryBuilder.quoteObject(property.selfIdColumnName!)}, ${property.targetIdColumnName}) VALUES ($1, $2) ON CONFLICT DO NOTHING;`;
|
|
1388
1397
|
const params = [id, relatedEntityId];
|
|
1389
|
-
await server.queryDatabaseObject(command, params);
|
|
1398
|
+
await server.queryDatabaseObject(command, params, routeContext?.getDbTransactionClient());
|
|
1390
1399
|
} else {
|
|
1391
1400
|
await targetDataAccessor.updateById(targetEntity.id, { [property.selfIdColumnName!]: id }, routeContext?.getDbTransactionClient());
|
|
1392
1401
|
targetEntity[property.selfIdColumnName!] = id;
|
|
@@ -1409,7 +1418,7 @@ async function updateEntityById(server: IRpdServer, dataAccessor: IRpdDataAccess
|
|
|
1409
1418
|
tableName: property.linkTableName,
|
|
1410
1419
|
})} (${server.queryBuilder.quoteObject(property.selfIdColumnName!)}, ${property.targetIdColumnName}) VALUES ($1, $2) ON CONFLICT DO NOTHING;`;
|
|
1411
1420
|
const params = [id, relatedEntityId];
|
|
1412
|
-
await server.queryDatabaseObject(command, params);
|
|
1421
|
+
await server.queryDatabaseObject(command, params, routeContext?.getDbTransactionClient());
|
|
1413
1422
|
} else {
|
|
1414
1423
|
await targetDataAccessor.updateById(targetEntity.id, { [property.selfIdColumnName!]: id }, routeContext?.getDbTransactionClient());
|
|
1415
1424
|
targetEntity[property.selfIdColumnName!] = id;
|
|
@@ -1508,6 +1517,199 @@ function getEntityDuplicatedErrorMessage(server: IRpdServer, model: RpdDataModel
|
|
|
1508
1517
|
return `已存在 ${propertyNames.join(", ")} 相同的记录。`;
|
|
1509
1518
|
}
|
|
1510
1519
|
|
|
1520
|
+
async function deleteEntityById(
|
|
1521
|
+
server: IRpdServer,
|
|
1522
|
+
dataAccessor: IRpdDataAccessor,
|
|
1523
|
+
options: DeleteEntityByIdOptions | string | number,
|
|
1524
|
+
plugin?: RapidPlugin,
|
|
1525
|
+
): Promise<void> {
|
|
1526
|
+
// options is id
|
|
1527
|
+
if (!isObject(options)) {
|
|
1528
|
+
options = {
|
|
1529
|
+
id: options,
|
|
1530
|
+
};
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
const model = dataAccessor.getModel();
|
|
1534
|
+
if (model.derivedTypePropertyCode) {
|
|
1535
|
+
// TODO: should be allowed.
|
|
1536
|
+
throw newEntityOperationError("Delete base entity directly is not allowed.");
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
const { id, routeContext } = options;
|
|
1540
|
+
|
|
1541
|
+
const entity = await findById(server, dataAccessor, {
|
|
1542
|
+
id,
|
|
1543
|
+
keepNonPropertyFields: true,
|
|
1544
|
+
routeContext,
|
|
1545
|
+
});
|
|
1546
|
+
|
|
1547
|
+
if (!entity) {
|
|
1548
|
+
return;
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
if (model.softDelete) {
|
|
1552
|
+
if (entity.deletedAt) {
|
|
1553
|
+
return;
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1557
|
+
await server.emitEvent({
|
|
1558
|
+
eventName: "entity.beforeDelete",
|
|
1559
|
+
payload: {
|
|
1560
|
+
namespace: model.namespace,
|
|
1561
|
+
modelSingularCode: model.singularCode,
|
|
1562
|
+
before: entity,
|
|
1563
|
+
},
|
|
1564
|
+
sender: plugin,
|
|
1565
|
+
routeContext,
|
|
1566
|
+
});
|
|
1567
|
+
|
|
1568
|
+
if (model.softDelete) {
|
|
1569
|
+
const currentUserId = routeContext?.state?.userId;
|
|
1570
|
+
await dataAccessor.updateById(
|
|
1571
|
+
id,
|
|
1572
|
+
{
|
|
1573
|
+
deleted_at: getNowStringWithTimezone(),
|
|
1574
|
+
deleter_id: currentUserId,
|
|
1575
|
+
},
|
|
1576
|
+
routeContext?.getDbTransactionClient(),
|
|
1577
|
+
);
|
|
1578
|
+
} else {
|
|
1579
|
+
const relationPropertiesWithDeletingReaction = getEntityPropertiesIncludingBase(server, model, (property) => {
|
|
1580
|
+
return isRelationProperty(property) && property.entityDeletingReaction && property.entityDeletingReaction !== "doNothing";
|
|
1581
|
+
});
|
|
1582
|
+
|
|
1583
|
+
for (const relationProperty of relationPropertiesWithDeletingReaction) {
|
|
1584
|
+
const relationDataAccessor = server.getDataAccessor({
|
|
1585
|
+
singularCode: relationProperty.targetSingularCode,
|
|
1586
|
+
});
|
|
1587
|
+
if (relationProperty.entityDeletingReaction === "cascadingDelete") {
|
|
1588
|
+
if (relationProperty.relation === "one") {
|
|
1589
|
+
const relatedEntityId = entity[relationProperty.targetIdColumnName];
|
|
1590
|
+
if (relatedEntityId) {
|
|
1591
|
+
await deleteEntityById(
|
|
1592
|
+
server,
|
|
1593
|
+
relationDataAccessor,
|
|
1594
|
+
{
|
|
1595
|
+
routeContext,
|
|
1596
|
+
id: relatedEntityId,
|
|
1597
|
+
},
|
|
1598
|
+
plugin,
|
|
1599
|
+
);
|
|
1600
|
+
}
|
|
1601
|
+
} else if (relationProperty.relation === "many") {
|
|
1602
|
+
if (relationProperty.linkTableName) {
|
|
1603
|
+
const targetLinks = await server.queryDatabaseObject(
|
|
1604
|
+
`SELECT ${server.queryBuilder.quoteObject(relationProperty.targetIdColumnName)} FROM ${server.queryBuilder.quoteTable({
|
|
1605
|
+
schema: relationProperty.linkSchema,
|
|
1606
|
+
tableName: relationProperty.linkTableName,
|
|
1607
|
+
})} WHERE ${server.queryBuilder.quoteObject(relationProperty.selfIdColumnName!)} = $1`,
|
|
1608
|
+
[id],
|
|
1609
|
+
routeContext?.getDbTransactionClient(),
|
|
1610
|
+
);
|
|
1611
|
+
const targetEntityIds = targetLinks.map((item) => item[relationProperty.targetIdColumnName]);
|
|
1612
|
+
|
|
1613
|
+
await server.queryDatabaseObject(
|
|
1614
|
+
`DELETE FROM ${server.queryBuilder.quoteTable({
|
|
1615
|
+
schema: relationProperty.linkSchema,
|
|
1616
|
+
tableName: relationProperty.linkTableName,
|
|
1617
|
+
})} WHERE ${server.queryBuilder.quoteObject(relationProperty.selfIdColumnName!)} = $1`,
|
|
1618
|
+
[id],
|
|
1619
|
+
routeContext?.getDbTransactionClient(),
|
|
1620
|
+
);
|
|
1621
|
+
|
|
1622
|
+
for (const targetEntityId of targetEntityIds) {
|
|
1623
|
+
await deleteEntityById(
|
|
1624
|
+
server,
|
|
1625
|
+
relationDataAccessor,
|
|
1626
|
+
{
|
|
1627
|
+
routeContext,
|
|
1628
|
+
id: targetEntityId,
|
|
1629
|
+
},
|
|
1630
|
+
plugin,
|
|
1631
|
+
);
|
|
1632
|
+
}
|
|
1633
|
+
} else {
|
|
1634
|
+
const targetModel = server.getModel({
|
|
1635
|
+
singularCode: relationProperty.targetSingularCode,
|
|
1636
|
+
});
|
|
1637
|
+
const targetRows = await server.queryDatabaseObject(
|
|
1638
|
+
`SELECT id FROM ${server.queryBuilder.quoteTable({
|
|
1639
|
+
schema: targetModel.schema,
|
|
1640
|
+
tableName: targetModel.tableName,
|
|
1641
|
+
})} WHERE ${server.queryBuilder.quoteObject(relationProperty.selfIdColumnName!)} = $1`,
|
|
1642
|
+
[id],
|
|
1643
|
+
routeContext?.getDbTransactionClient(),
|
|
1644
|
+
);
|
|
1645
|
+
const targetEntityIds = targetRows.map((item) => item.id);
|
|
1646
|
+
for (const targetEntityId of targetEntityIds) {
|
|
1647
|
+
await deleteEntityById(
|
|
1648
|
+
server,
|
|
1649
|
+
relationDataAccessor,
|
|
1650
|
+
{
|
|
1651
|
+
routeContext,
|
|
1652
|
+
id: targetEntityId,
|
|
1653
|
+
},
|
|
1654
|
+
plugin,
|
|
1655
|
+
);
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1659
|
+
} else if (relationProperty.entityDeletingReaction === "unlink") {
|
|
1660
|
+
if (relationProperty.relation === "one") {
|
|
1661
|
+
// do nothing, entity will be deleted later.
|
|
1662
|
+
} else if (relationProperty.relation === "many") {
|
|
1663
|
+
if (relationProperty.linkTableName) {
|
|
1664
|
+
await server.queryDatabaseObject(
|
|
1665
|
+
`DELETE FROM ${server.queryBuilder.quoteTable({
|
|
1666
|
+
schema: relationProperty.linkSchema,
|
|
1667
|
+
tableName: relationProperty.linkTableName,
|
|
1668
|
+
})}
|
|
1669
|
+
WHERE ${server.queryBuilder.quoteObject(relationProperty.selfIdColumnName!)} = $1`,
|
|
1670
|
+
[id],
|
|
1671
|
+
routeContext?.getDbTransactionClient(),
|
|
1672
|
+
);
|
|
1673
|
+
} else {
|
|
1674
|
+
const relationModel = server.getModel({
|
|
1675
|
+
singularCode: relationProperty.targetSingularCode,
|
|
1676
|
+
});
|
|
1677
|
+
await server.queryDatabaseObject(
|
|
1678
|
+
`UPDATE ${server.queryBuilder.quoteTable({
|
|
1679
|
+
schema: relationModel.schema,
|
|
1680
|
+
tableName: relationModel.tableName,
|
|
1681
|
+
})}
|
|
1682
|
+
SET ${server.queryBuilder.quoteObject(relationProperty.selfIdColumnName!)} = null
|
|
1683
|
+
WHERE ${server.queryBuilder.quoteObject(relationProperty.selfIdColumnName!)} = $1`,
|
|
1684
|
+
[id],
|
|
1685
|
+
routeContext?.getDbTransactionClient(),
|
|
1686
|
+
);
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
|
|
1692
|
+
await dataAccessor.deleteById(id, routeContext?.getDbTransactionClient());
|
|
1693
|
+
if (model.base) {
|
|
1694
|
+
const baseDataAccessor = server.getDataAccessor({
|
|
1695
|
+
singularCode: model.base,
|
|
1696
|
+
});
|
|
1697
|
+
await baseDataAccessor.deleteById(id, routeContext?.getDbTransactionClient());
|
|
1698
|
+
}
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
await server.emitEvent({
|
|
1702
|
+
eventName: "entity.delete",
|
|
1703
|
+
payload: {
|
|
1704
|
+
namespace: model.namespace,
|
|
1705
|
+
modelSingularCode: model.singularCode,
|
|
1706
|
+
before: entity,
|
|
1707
|
+
},
|
|
1708
|
+
sender: plugin,
|
|
1709
|
+
routeContext,
|
|
1710
|
+
});
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1511
1713
|
export default class EntityManager<TEntity = any> {
|
|
1512
1714
|
#server: IRpdServer;
|
|
1513
1715
|
#dataAccessor: IRpdDataAccessor;
|
|
@@ -1563,76 +1765,7 @@ export default class EntityManager<TEntity = any> {
|
|
|
1563
1765
|
}
|
|
1564
1766
|
|
|
1565
1767
|
async deleteById(options: DeleteEntityByIdOptions | string | number, plugin?: RapidPlugin): Promise<void> {
|
|
1566
|
-
|
|
1567
|
-
if (!isObject(options)) {
|
|
1568
|
-
options = {
|
|
1569
|
-
id: options,
|
|
1570
|
-
};
|
|
1571
|
-
}
|
|
1572
|
-
|
|
1573
|
-
const model = this.getModel();
|
|
1574
|
-
if (model.derivedTypePropertyCode) {
|
|
1575
|
-
throw newEntityOperationError("Delete base entity directly is not allowed.");
|
|
1576
|
-
}
|
|
1577
|
-
|
|
1578
|
-
const { id, routeContext } = options;
|
|
1579
|
-
|
|
1580
|
-
const entity = await this.findById({
|
|
1581
|
-
id,
|
|
1582
|
-
keepNonPropertyFields: true,
|
|
1583
|
-
routeContext,
|
|
1584
|
-
});
|
|
1585
|
-
|
|
1586
|
-
if (!entity) {
|
|
1587
|
-
return;
|
|
1588
|
-
}
|
|
1589
|
-
|
|
1590
|
-
await this.#server.emitEvent({
|
|
1591
|
-
eventName: "entity.beforeDelete",
|
|
1592
|
-
payload: {
|
|
1593
|
-
namespace: model.namespace,
|
|
1594
|
-
modelSingularCode: model.singularCode,
|
|
1595
|
-
before: entity,
|
|
1596
|
-
},
|
|
1597
|
-
sender: plugin,
|
|
1598
|
-
routeContext,
|
|
1599
|
-
});
|
|
1600
|
-
|
|
1601
|
-
if (model.softDelete) {
|
|
1602
|
-
let dataAccessor = model.base
|
|
1603
|
-
? this.#server.getDataAccessor({
|
|
1604
|
-
singularCode: model.base,
|
|
1605
|
-
})
|
|
1606
|
-
: this.#dataAccessor;
|
|
1607
|
-
const currentUserId = routeContext?.state?.userId;
|
|
1608
|
-
await dataAccessor.updateById(
|
|
1609
|
-
id,
|
|
1610
|
-
{
|
|
1611
|
-
deleted_at: getNowStringWithTimezone(),
|
|
1612
|
-
deleter_id: currentUserId,
|
|
1613
|
-
},
|
|
1614
|
-
routeContext?.getDbTransactionClient(),
|
|
1615
|
-
);
|
|
1616
|
-
} else {
|
|
1617
|
-
await this.#dataAccessor.deleteById(id, routeContext?.getDbTransactionClient());
|
|
1618
|
-
if (model.base) {
|
|
1619
|
-
const baseDataAccessor = this.#server.getDataAccessor({
|
|
1620
|
-
singularCode: model.base,
|
|
1621
|
-
});
|
|
1622
|
-
await baseDataAccessor.deleteById(id, routeContext?.getDbTransactionClient());
|
|
1623
|
-
}
|
|
1624
|
-
}
|
|
1625
|
-
|
|
1626
|
-
await this.#server.emitEvent({
|
|
1627
|
-
eventName: "entity.delete",
|
|
1628
|
-
payload: {
|
|
1629
|
-
namespace: model.namespace,
|
|
1630
|
-
modelSingularCode: model.singularCode,
|
|
1631
|
-
before: entity,
|
|
1632
|
-
},
|
|
1633
|
-
sender: plugin,
|
|
1634
|
-
routeContext,
|
|
1635
|
-
});
|
|
1768
|
+
return await deleteEntityById(this.#server, this.#dataAccessor, options, plugin);
|
|
1636
1769
|
}
|
|
1637
1770
|
|
|
1638
1771
|
async addRelations(options: AddEntityRelationsOptions, plugin?: RapidPlugin): Promise<void> {
|
|
@@ -1669,7 +1802,7 @@ export default class EntityManager<TEntity = any> {
|
|
|
1669
1802
|
WHERE ${queryBuilder.quoteObject(relationProperty.selfIdColumnName!)}=$1 AND ${queryBuilder.quoteObject(relationProperty.targetIdColumnName!)}=$2
|
|
1670
1803
|
)`;
|
|
1671
1804
|
const params = [id, relation.id];
|
|
1672
|
-
await server.queryDatabaseObject(command, params);
|
|
1805
|
+
await server.queryDatabaseObject(command, params, routeContext?.getDbTransactionClient());
|
|
1673
1806
|
}
|
|
1674
1807
|
}
|
|
1675
1808
|
|
|
@@ -1714,7 +1847,7 @@ export default class EntityManager<TEntity = any> {
|
|
|
1714
1847
|
const command = `DELETE FROM ${queryBuilder.quoteTable({ schema: relationProperty.linkSchema, tableName: relationProperty.linkTableName })}
|
|
1715
1848
|
WHERE ${queryBuilder.quoteObject(relationProperty.selfIdColumnName!)}=$1 AND ${queryBuilder.quoteObject(relationProperty.targetIdColumnName!)}=$2;`;
|
|
1716
1849
|
const params = [id, relation.id];
|
|
1717
|
-
await server.queryDatabaseObject(command, params);
|
|
1850
|
+
await server.queryDatabaseObject(command, params, routeContext?.getDbTransactionClient());
|
|
1718
1851
|
}
|
|
1719
1852
|
}
|
|
1720
1853
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { cloneDeep } from "lodash";
|
|
1
|
+
import { cloneDeep, filter, find } from "lodash";
|
|
2
2
|
import { IRpdServer } from "~/core/server";
|
|
3
3
|
import { RpdDataModel, RpdDataModelProperty } from "~/types";
|
|
4
4
|
|
|
@@ -14,13 +14,17 @@ export function isManyRelationProperty(property: RpdDataModelProperty) {
|
|
|
14
14
|
return isRelationProperty(property) && property.relation === "many";
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
export function getEntityProperties(server: IRpdServer, model: RpdDataModel) {
|
|
18
|
-
|
|
17
|
+
export function getEntityProperties(server: IRpdServer, model: RpdDataModel, predicate?: (item: RpdDataModelProperty) => boolean) {
|
|
18
|
+
if (!predicate) {
|
|
19
|
+
return model.properties;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return filter(model.properties, predicate);
|
|
19
23
|
}
|
|
20
24
|
|
|
21
|
-
export function getEntityPropertiesIncludingBase(server: IRpdServer, model: RpdDataModel) {
|
|
25
|
+
export function getEntityPropertiesIncludingBase(server: IRpdServer, model: RpdDataModel, predicate?: (item: RpdDataModelProperty) => boolean) {
|
|
22
26
|
if (!model.base) {
|
|
23
|
-
return model
|
|
27
|
+
return getEntityProperties(server, model, predicate);
|
|
24
28
|
}
|
|
25
29
|
|
|
26
30
|
const baseModel = server.getModel({
|
|
@@ -28,14 +32,25 @@ export function getEntityPropertiesIncludingBase(server: IRpdServer, model: RpdD
|
|
|
28
32
|
});
|
|
29
33
|
let baseProperties: RpdDataModelProperty[] = [];
|
|
30
34
|
if (baseModel) {
|
|
31
|
-
|
|
35
|
+
if (predicate) {
|
|
36
|
+
baseProperties = filter(baseModel.properties, predicate);
|
|
37
|
+
} else {
|
|
38
|
+
baseProperties = baseModel.properties;
|
|
39
|
+
}
|
|
40
|
+
baseProperties = baseProperties.map((property) => {
|
|
32
41
|
property = cloneDeep(property);
|
|
33
42
|
property.isBaseProperty = true;
|
|
34
43
|
return property;
|
|
35
44
|
});
|
|
36
45
|
}
|
|
37
46
|
|
|
38
|
-
|
|
47
|
+
let properties: RpdDataModelProperty[];
|
|
48
|
+
if (predicate) {
|
|
49
|
+
properties = filter(model.properties, predicate);
|
|
50
|
+
} else {
|
|
51
|
+
properties = model.properties;
|
|
52
|
+
}
|
|
53
|
+
return [...baseProperties, ...properties];
|
|
39
54
|
}
|
|
40
55
|
|
|
41
56
|
export function getEntityPropertyByCode(server: IRpdServer, model: RpdDataModel, propertyCode: string): RpdDataModelProperty | undefined {
|
package/src/server.ts
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
EntityWatcherType,
|
|
18
18
|
RpdEntityCreateEventPayload,
|
|
19
19
|
EmitServerEventOptions,
|
|
20
|
+
IDatabaseClient,
|
|
20
21
|
} from "./types";
|
|
21
22
|
|
|
22
23
|
import QueryBuilder from "./queryBuilder/queryBuilder";
|
|
@@ -373,18 +374,18 @@ export class RapidServer implements IRpdServer {
|
|
|
373
374
|
return await factory.createFacility(this, options);
|
|
374
375
|
}
|
|
375
376
|
|
|
376
|
-
async queryDatabaseObject(sql: string, params?: unknown[] | Record<string, unknown
|
|
377
|
+
async queryDatabaseObject(sql: string, params?: unknown[] | Record<string, unknown>, client?: IDatabaseClient): Promise<any[]> {
|
|
377
378
|
try {
|
|
378
|
-
return await this.#databaseAccessor.queryDatabaseObject(sql, params);
|
|
379
|
+
return await this.#databaseAccessor.queryDatabaseObject(sql, params, client);
|
|
379
380
|
} catch (err) {
|
|
380
381
|
this.#logger.error("Failed to query database object.", { errorMessage: err.message, sql, params });
|
|
381
382
|
throw err;
|
|
382
383
|
}
|
|
383
384
|
}
|
|
384
385
|
|
|
385
|
-
async tryQueryDatabaseObject(sql: string, params?: unknown[] | Record<string, unknown
|
|
386
|
+
async tryQueryDatabaseObject(sql: string, params?: unknown[] | Record<string, unknown>, client?: IDatabaseClient): Promise<any[]> {
|
|
386
387
|
try {
|
|
387
|
-
return await this.queryDatabaseObject(sql, params);
|
|
388
|
+
return await this.queryDatabaseObject(sql, params, client);
|
|
388
389
|
} catch (err) {
|
|
389
390
|
this.#logger.error("Failed to query database object.", { errorMessage: err.message, sql, params });
|
|
390
391
|
}
|
package/src/types.ts
CHANGED
|
@@ -314,6 +314,11 @@ export interface RpdDataModelProperty {
|
|
|
314
314
|
*/
|
|
315
315
|
linkSchema?: string;
|
|
316
316
|
|
|
317
|
+
/**
|
|
318
|
+
* 当删除实体时,针对关系属性的联动处理。
|
|
319
|
+
*/
|
|
320
|
+
entityDeletingReaction?: RpdEntityDeleteRelationPropertyReaction;
|
|
321
|
+
|
|
317
322
|
/**
|
|
318
323
|
* 当设置为`true`时,仅允许在创建时设置此属性的值,不允许更新。
|
|
319
324
|
*/
|
|
@@ -341,6 +346,8 @@ export type RpdDataPropertyTypes =
|
|
|
341
346
|
| "image"
|
|
342
347
|
| "image[]";
|
|
343
348
|
|
|
349
|
+
export type RpdEntityDeleteRelationPropertyReaction = "doNothing" | "unlink" | "cascadingDelete";
|
|
350
|
+
|
|
344
351
|
/**
|
|
345
352
|
* 数据字典
|
|
346
353
|
*/
|