删除资源类、关系节点

main
expressgy 9 months ago
parent d7541847f5
commit e53abe6e22
  1. 10
      src/cache/index.js
  2. 17
      src/common/tools/binarySearch.js
  3. 1
      src/common/tools/binarySearchMore.js
  4. 23
      src/routes/graphResource2/atomModel/index.js
  5. 3
      src/routes/graphResource2/baseDict/index.js
  6. 10
      src/routes/graphResource2/resourceClass/index.dto.js
  7. 341
      src/routes/graphResource2/resourceClass/index.js
  8. 13
      test/压力/getClassTreeForAtomMOdel.js

10
src/cache/index.js vendored

@ -382,7 +382,11 @@ async function makeResourceCache(sequelize) {
// region 获取资源类关系表
const classRelationList =
await sequelize.models.ResourceClassRelation.findAll(
sequelizeFindAllType,
{...sequelizeFindAllType,where: {
isDelete: {
[Op.is]: null,
},
},},
);
// @ classRelationIdList - String - 描述:获取资源类关系ID列表
const classRelationIdList = [];
@ -394,7 +398,7 @@ async function makeResourceCache(sequelize) {
const classRelationItem = classRelationList[i];
const classRelationItemId = classRelationItem.resourceClassRelationId;
const targetId = classRelationItem.resourceClassRelationTarget;
classRelationIdList.push(classRelationItem);
classRelationIdList.push(classRelationItemId);
classRelationObject[classRelationItemId] = classRelationItem;
if (classRelationObjectForTargetClass[targetId] === undefined) {
classRelationObjectForTargetClass[targetId] = [classRelationItem];
@ -686,7 +690,7 @@ async function makeResourceCache(sequelize) {
};
// @ 构建类关系
for (let i = 0; i < classRelationIdList.length; i++) {
const nodeId = classRelationIdList[i].resourceClassRelationId;
const nodeId = classRelationList[i].resourceClassRelationId;
const classNode = classNodeObject[nodeId];
const fatherId = classNodeObject[nodeId].fatherId;
classNodeObject[fatherId].children.push(classNode);

@ -11,10 +11,23 @@
// | =
// | ------------------------------------------------------------
export default function binarySearch(arr, id, att) {
export default function binarySearch(arr, id, att = undefined) {
let bi = 0, ai = arr.length -1;
if(!Object.keys(arr[0]).includes(att)){
if(!Object.keys(arr[0]).includes(att) && att !== undefined){
throw new Error('不存在属性', att)
}else if(att === undefined){
while (bi <= ai){
const mi = Math.floor((bi + ai)/2);
const miId = arr[mi]
if(miId === id){
return mi
}else if(miId < id){
bi = mi + 1
}else{
ai = mi -1
}
}
return -1
}
while (bi <= ai){
const mi = Math.floor((bi + ai)/2);

@ -30,6 +30,7 @@ function binarySearch2(arr, id, att, bi, ai) {
}
export default function binarySearchMore(arr, ids, att, bi, ai){
if(ids.length == 0)return []
const firstIndex = binarySearch2(arr, ids[0], att, bi, ai);
if(firstIndex != -1){
bi = firstIndex

@ -86,6 +86,29 @@ atomModel.post('/createAtomModelItem', async (ctx, next) => {
] = newAtomModel.dataValues;
resourceCache.atomModelPool.length++;
resourceCache.atomModelPool.updatetime = new Date().getTime();
const RRP = resourceCache.resourcePool;
RRP.classListForAtomModel[newAtomModel.dataValues.atomModelId] = []
RRP.classNodeObjectForAtomModel[newAtomModel.dataValues.atomModelId] = []
// 给元分类加入基础几点
const RBP = resourceCache.baseDictPool
RBP.atomModelObject[newAtomModel.dataValues.atomModelId] = {
baseDictTree: [],
reduceBaseDictTree: [],
};
RBP.atomModelObject[newAtomModel.dataValues.atomModelId].baseDictTree = RBP.atomObject[
'0'
].children.filter(
(dict) => !(dict.atomModel && newAtomModel.dataValues.atomModelId != dict.atomModel),
);
RBP.atomModelObject[newAtomModel.dataValues.atomModelId].reduceBaseDictTree = RBP.reduceObject[
'0'
].children.filter(
(dict) => !(dict.atomModel && newAtomModel.dataValues.atomModelId != dict.atomModel),
);
ctx.body = {
message: '新建元分类成功。',
data: newAtomModel.dataValues,

@ -219,6 +219,7 @@ baseDict.post('/createBaseDictItem', async (ctx, next) => {
atomModelId,
'atomModelId',
);
// 判断字典缓存是否存在元分类
if (hasAtomModel == -1) {
// 检查是否存在元分类/模型
return ctx.throw(400, { e: '不存在目标元分类/模型' });
@ -275,7 +276,7 @@ baseDict.post('/createBaseDictItem', async (ctx, next) => {
}
// 分别压入精简原始字典对象到根节点树
RBP.atomModelObject[atomModelId].baseDictTree.push(newBaseDictItem);
RBP.atomModelObject[atomModelId].baseDictTree.push(reduceData);
RBP.atomModelObject[atomModelId].reduceBaseDictTree.push(reduceData);
return (ctx.body = {
message: '添加字典项成功',
data: newBaseDictItem,

@ -369,19 +369,19 @@ export function DeleteResourceClassItemDTO(data) {
const schema = {
type: 'object',
properties: {
resourceClassBaseId: {
nodeId: {
type: ['integer'],
minimum: 0,
errorMessage: {
type: '资源类ID必须是整数',
minimum: '资源类ID是一个正整数',
type: '资源类节点ID必须是整数',
minimum: '资源类节点ID是一个正整数',
},
},
},
required: ['resourceClassBaseId'],
required: ['nodeId'],
errorMessage: {
required: {
resourceClassBaseId: '资源类ID为必填项',
nodeId: '资源类节点ID为必填项',
},
},
};

@ -27,6 +27,9 @@ import {
} from '#routes/graphResource2/resourceClass/index.dto.js';
import getPage from '#common/tools/getArrayPage.js';
import getNoSpacesStr from '#common/tools/getNoSpacesStr.js';
import binarySearch from '#common/tools/binarySearch.js';
import binarySearchMore from '#common/tools/binarySearchMore.js';
import { Op } from 'sequelize';
const resourceClass = new Router();
@ -145,16 +148,24 @@ resourceClass.post('/createResourceClassItem', async (ctx, next) => {
return ctx.throw(400, { e: '资源类标识已存在' });
}
// @ 判断是否存在父节点
if(resourceClassRelationId != 0){
if(RRP.classRelationObject[resourceClassRelationId] == undefined){
if (resourceClassRelationId != 0) {
if (RRP.classRelationObject[resourceClassRelationId] == undefined) {
return ctx.throw(400, { e: '不存在目标资源类树节点' });
}
if(!RRP.classListForAtomModel[atomModelId].some(i => i.resourceClassBaseId == RRP.classRelationObject[resourceClassRelationId].resourceClassRelationTarget)){
return ctx.throw(400, { e: '目标资源类树节点不存在于目标元分类/模型中' });
if (
!RRP.classListForAtomModel[atomModelId].some(
(i) =>
i.resourceClassBaseId ==
RRP.classRelationObject[resourceClassRelationId]
.resourceClassRelationTarget,
)
) {
return ctx.throw(400, {
e: '目标资源类树节点不存在于目标元分类/模型中',
});
}
}
// 写入资源类
const newClassItem = await ctx.sequelize.models.ResourceClassBase.create({
atomModel: atomModelId,
@ -196,8 +207,10 @@ resourceClass.post('/createResourceClassItem', async (ctx, next) => {
// ! 写入classRelationObjectForTargetClass
RRP.classRelationObjectForTargetClass[classId] = [];
// @ 获取目标资源关系节点的资源类ID
const fatherClassId = resourceClassRelationId == 0 ? 0 :
RRP.classRelationObject[resourceClassRelationId]
const fatherClassId =
resourceClassRelationId == 0
? 0
: RRP.classRelationObject[resourceClassRelationId]
.resourceClassRelationTarget;
// 在数据库添加这条关系
const newClassRelation =
@ -230,23 +243,20 @@ resourceClass.post('/createResourceClassItem', async (ctx, next) => {
const nowRelationList = nowClassModel.classRelationList;
// 拿到父节点和节点ID
const nodeId = nowRelationList[0].resourceClassRelationId;
const classNode = new RRP.ClassNodeModel(
nowClassModel,
nodeId,
);
RRP.classNodeObject[nodeId] = classNode
const classNode = new RRP.ClassNodeModel(nowClassModel, nodeId);
RRP.classNodeObject[nodeId] = classNode;
RRP.classNodeObject[resourceClassRelationId].children.push(classNode);
if(resourceClassRelationId == 0){
RRP.classNodeObjectForAtomModel[atomModelId].push(classNode)
if (resourceClassRelationId == 0) {
RRP.classNodeObjectForAtomModel[atomModelId].push(classNode);
}
ctx.body = {
message: '创建资源类成功',
data: {
resourceClassBase: newClassData,
resourceClassRelation: newClassRelationData
}
resourceClassRelation: newClassRelationData,
},
};
});
@ -264,67 +274,99 @@ resourceClass.post('/editResourceClassItem', async (ctx, next) => {
resourceClassBaseAvatar,
resourceClassBaseDefine,
resourceClassBaseColor,
resourceClassBaseType
resourceClassBaseType,
} = ctx.request.body;
const RRP = resourceCache.resourcePool;
let oldName,oldIdentify,atomModelId
let oldName, oldIdentify, atomModelId;
// @ 判断ID是否存在
if(!RRP.classIdList.includes(resourceClassBaseId)){
if (!RRP.classIdList.includes(resourceClassBaseId)) {
return ctx.throw(400, { e: '资源类不存在' });
}else{
oldName = RRP.classObject[resourceClassBaseId].resourceClassBaseId
oldIdentify = RRP.classObject[resourceClassBaseId].resourceClassBaseIdentify
atomModelId = RRP.classObject[resourceClassBaseId].atomModel
} else {
oldName = RRP.classObject[resourceClassBaseId].resourceClassBaseId;
oldIdentify =
RRP.classObject[resourceClassBaseId].resourceClassBaseIdentify;
atomModelId = RRP.classObject[resourceClassBaseId].atomModel;
}
// @ 判断名称是否重复
if(RRP.classListForAtomModel[atomModelId].some(i => i.resourceClassBaseName == getNoSpacesStr(resourceClassBaseName) && i.resourceClassBaseId != resourceClassBaseId)){
if (
RRP.classListForAtomModel[atomModelId].some(
(i) =>
i.resourceClassBaseName ==
getNoSpacesStr(resourceClassBaseName) &&
i.resourceClassBaseId != resourceClassBaseId,
)
) {
return ctx.throw(400, { e: '资源类重名' });
}
// @ 判断标识是否重复
if(RRP.classList.some(i => i.resourceClassBaseIdentify == getNoSpacesStr(resourceClassBaseIdentify).toUpperCase() && i.resourceClassBaseId != resourceClassBaseId)){
if (
RRP.classList.some(
(i) =>
i.resourceClassBaseIdentify ==
getNoSpacesStr(resourceClassBaseIdentify).toUpperCase() &&
i.resourceClassBaseId != resourceClassBaseId,
)
) {
return ctx.throw(400, { e: '资源类标识已存在' });
}
// 修改信息
RRP.classObject[resourceClassBaseId].resourceClassBaseName = getNoSpacesStr(resourceClassBaseName);
RRP.classObject[resourceClassBaseId].resourceClassBaseDescribe = resourceClassBaseDescribe;
RRP.classObject[resourceClassBaseId].resourceClassBaseIdentify = getNoSpacesStr(resourceClassBaseIdentify).toUpperCase();
RRP.classObject[resourceClassBaseId].resourceClassBaseId = resourceClassBaseId;
RRP.classObject[resourceClassBaseId].resourceClassBaseAvatar = resourceClassBaseAvatar;
RRP.classObject[resourceClassBaseId].resourceClassBaseDefine = resourceClassBaseDefine;
RRP.classObject[resourceClassBaseId].resourceClassBaseColor = resourceClassBaseColor;
RRP.classObject[resourceClassBaseId].resourceClassBaseType = resourceClassBaseType;
RRP.classObject[resourceClassBaseId].resourceClassBaseName = getNoSpacesStr(
resourceClassBaseName,
);
RRP.classObject[resourceClassBaseId].resourceClassBaseDescribe =
resourceClassBaseDescribe;
RRP.classObject[resourceClassBaseId].resourceClassBaseIdentify =
getNoSpacesStr(resourceClassBaseIdentify).toUpperCase();
RRP.classObject[resourceClassBaseId].resourceClassBaseId =
resourceClassBaseId;
RRP.classObject[resourceClassBaseId].resourceClassBaseAvatar =
resourceClassBaseAvatar;
RRP.classObject[resourceClassBaseId].resourceClassBaseDefine =
resourceClassBaseDefine;
RRP.classObject[resourceClassBaseId].resourceClassBaseColor =
resourceClassBaseColor;
RRP.classObject[resourceClassBaseId].resourceClassBaseType =
resourceClassBaseType;
// @ 是否修改标识
console.log(oldIdentify, getNoSpacesStr(resourceClassBaseIdentify).toUpperCase())
if(oldIdentify != getNoSpacesStr(resourceClassBaseIdentify).toUpperCase()){
console.log('更改表名')
if (
oldIdentify != getNoSpacesStr(resourceClassBaseIdentify).toUpperCase()
) {
// 需要更改表明
// ! 删除模型
delete ctx.sequelize.models[oldIdentify.toLowerCase()]
delete ctx.sequelize.models[oldIdentify.toLowerCase()];
// ! 修改表名
const results = await ctx.sequelize.queryInterface.renameTable('entity_' + oldIdentify.toLowerCase(),'entity_' + getNoSpacesStr(resourceClassBaseIdentify).toLowerCase())
const results = await ctx.sequelize.queryInterface.renameTable(
'entity_' + oldIdentify.toLowerCase(),
'entity_' + getNoSpacesStr(resourceClassBaseIdentify).toLowerCase(),
);
// ! 启动新模型
await RRP.classModelObject[resourceClassBaseId].createSequelizeModel();
// | 更新资源实体ID
}
ctx.body = {
message: '修改资源类信息成功'
message: '修改资源类信息成功',
};
await next()
await ctx.sequelize.models.ResourceClassBase.update({
resourceClassBaseName : getNoSpacesStr(resourceClassBaseName),
resourceClassBaseDescribe : resourceClassBaseDescribe,
resourceClassBaseIdentify : getNoSpacesStr(resourceClassBaseIdentify).toUpperCase(),
resourceClassBaseId : resourceClassBaseId,
resourceClassBaseAvatar : resourceClassBaseAvatar,
resourceClassBaseDefine : resourceClassBaseDefine,
resourceClassBaseColor : resourceClassBaseColor,
resourceClassBaseType : resourceClassBaseType,
},{
where:{
resourceClassBaseId
}
})
await next();
await ctx.sequelize.models.ResourceClassBase.update(
{
resourceClassBaseName: getNoSpacesStr(resourceClassBaseName),
resourceClassBaseDescribe: resourceClassBaseDescribe,
resourceClassBaseIdentify: getNoSpacesStr(
resourceClassBaseIdentify,
).toUpperCase(),
resourceClassBaseId: resourceClassBaseId,
resourceClassBaseAvatar: resourceClassBaseAvatar,
resourceClassBaseDefine: resourceClassBaseDefine,
resourceClassBaseColor: resourceClassBaseColor,
resourceClassBaseType: resourceClassBaseType,
},
{
where: {
resourceClassBaseId,
},
},
);
});
// @ 删除资源类
@ -333,7 +375,195 @@ resourceClass.delete('/deleteResourceClassItem', async (ctx, next) => {
if (!verif.status) {
return ctx.throw(400, { e: verif.error.map((i) => i.message) });
}
ctx.body = 6;
const nodeId = ctx.query.nodeId;
// 判断是否存在节点
const RRP = resourceCache.resourcePool;
const findNodeId = binarySearch(RRP.classRelationIdList, nodeId);
if (findNodeId == -1) {
return ctx.throw(400, { e: '不存在此资源类节点ID' });
}
const classNodeObject = RRP.classNodeObject[nodeId];
if (classNodeObject.children.length != 0) {
return ctx.throw(400, {
e: '该资源类节点下存在子节点,无法删除,请先删除子节点。',
});
}
const classId = classNodeObject.classId;
const fatherId = classNodeObject.fatherId;
const atomModel = classNodeObject.atomModel;
const classIdentify = classNodeObject.classIdentify;
let entityListB, expandListB;
// @ 删掉关联列表
RRP.classRelationList.splice(findNodeId, 1);
// @ 删掉关联ID列表
RRP.classRelationIdList.splice(findNodeId, 1);
// @ 删掉关联ID对象集合
delete RRP.classRelationObject[nodeId];
// @ 删除资源类的关联对象中的当前节点
const relationList = RRP.classRelationObjectForTargetClass[classId];
relationList.splice(
binarySearch(relationList, nodeId, 'resourceClassRelationId'),
1,
);
// @ 删除父节点下的children的此节点
RRP.classNodeObject[fatherId].children.splice(
binarySearch(RRP.classNodeObject[fatherId].children, nodeId, 'nodeId'),
1,
);
// @ 删除节点列表上的此节点
delete RRP.classNodeObject[nodeId];
// 删除原分类下的根节点
if (fatherId == 0) {
RRP.classNodeObjectForAtomModel[atomModel].splice(
binarySearch(
RRP.classNodeObjectForAtomModel[atomModel],
nodeId,
'nodeId',
),
1,
);
}
if (classNodeObject.classRelationIdList.length == 0) {
// 最后一个节点了,删掉的话就删掉了资源类
// @ 删掉资源类的关联列表
delete RRP.classRelationObjectForTargetClass[classId];
// @ 删资源类
const classIdIndex = binarySearch(RRP.classIdList, classId);
RRP.classList.splice(classIdIndex, 1);
RRP.classIdList.splice(classIdIndex, 1);
delete RRP.classObject[classId];
RRP.classListForAtomModel[atomModel].splice(
binarySearch(
RRP.classListForAtomModel[atomModel],
classId,
'resourceClassBaseId',
),
);
// @ 删资源类拓展字段
if (
Object.keys(RRP.classExpandForClassBaseObject).includes(
classId.toString(),
)
) {
const expandList = RRP.classExpandForClassBaseObject[classId];
const expandIdList = Object.keys(expandList).map((i) => {
delete RRP.classExpandObject[
expandList[i].resourceClassExpandFieldId
];
return expandList[i].resourceClassExpandFieldId;
});
expandListB = expandIdList;
delete RRP.classExpandForClassBaseObject[classId];
const expandIdIndexList = binarySearchMore(
RRP.classExpandList,
expandIdList,
'resourceClassExpandFieldId',
0,
RRP.classExpandList.length,
).sort((a, b) => b - a);
for (let i of expandIdIndexList) {
RRP.classExpandList.splice(i, 1);
RRP.classExpandIdList.splice(i, 1);
}
}
// @ 删除资源实体字段
if (
Object.keys(RRP.entityStructForClassBaseObject).includes(
classId.toString(),
)
) {
const entityNameObject =
RRP.entityStructForClassBaseObject[classId];
const entityIdList = Object.keys(entityNameObject).map((i) => {
delete RRP.entityStructObject[
entityNameObject[i].resourceEntityStructId
];
return entityNameObject[i].resourceEntityStructId;
});
entityListB = entityIdList;
delete RRP.entityStructForClassBaseObject[classId];
const entityIndexList = binarySearchMore(
RRP.entityStructList,
entityIdList,
'resourceEntityStructId',
0,
RRP.entityStructList.length,
).sort((a, b) => b - a);
for (let i of entityIndexList) {
RRP.entityStructList.splice(i, 1);
RRP.entityStructIdList.splice(i, 1);
}
}
// ! @ 删资源对象
// @ 删除表
const data = await ctx.sequelize.query(
'DROP TABLE IF EXISTS ' + 'entity_' + classIdentify.toLowerCase(),
);
// 删除资源对象缓存
}
ctx.body = {
message: '删除资源类节点成功。',
};
// 删除关联
ctx.sequelize.models.ResourceClassRelation.update(
{
isDelete: new Date().toISOString(),
},
{
where: {
resourceClassRelationId: nodeId,
},
},
);
if (classNodeObject.classRelationIdList.length == 0) {
// 删除资源类
ctx.sequelize.models.ResourceClassBase.update(
{
isDelete: new Date().toISOString(),
},
{
where: {
resourceClassBaseId: classId,
},
},
);
// 删除拓展字段
if (expandListB) {
ctx.sequelize.models.ResourceClassExpandField.update(
{
isDelete: new Date().toISOString(),
},
{
where: {
resourceClassExpandFieldId: {
[Op.in]: expandListB,
},
},
},
);
}
// 删除实体字段
if (entityListB) {
ctx.sequelize.models.ResourceEntityStruct.update(
{
isDelete: new Date().toISOString(),
},
{
where: {
resourceEntityStructId: {
[Op.in]: entityListB,
},
},
},
);
}
}
});
// @ 创建资源类关联
@ -351,6 +581,7 @@ resourceClass.delete('/deleteResourceClassRelation', async (ctx, next) => {
if (!verif.status) {
return ctx.throw(400, { e: verif.error.map((i) => i.message) });
}
const RRP = resourceCache.resourcePool;
ctx.body = 8;
});

@ -13,14 +13,11 @@
import loadtest from 'loadtest'
// 定义要测试的目标 URL
const url = ['http://localhost:5000/graphResource2/resourceClass/getResourceClassTree?searchData&atomModelId=1',
'http://localhost:5000/graphResource2/resourceClass/getResourceClassCompleteInfo?resourceClassBaseId=1&resourceClassBaseIdentify=',
'http://localhost:5000/graphResource2/resourceClass/getResourceClassList?searchData=%E4%BC%81%E4%B8%9A&atomModelId=1'
]
const url = 'http://localhost:3001'
// 定义 loadtest 的参数
const options = {
url: url,
maxRequests: 1000, // 总请求数
maxRequests: 50000, // 总请求数
concurrency: 20 // 并发请求数
};
@ -28,15 +25,15 @@ loadtest.loadTest(options, function(error, result) {
if (error) {
console.error('压力测试失败:', error);
} else {
console.log('压力测试结果1:');
console.log('压力测试结果:');
console.log('总请求数:', result.totalRequests);
console.log('请求失败数:', result.totalErrors);
console.log('总运行时间(秒):', result.totalTimeSeconds);
console.log('平均延迟时间(毫秒):', result.meanLatencyMs);
console.log('最小延迟时间(毫秒):', result.minLatencyMs);
console.log('最大延迟时间(毫秒):', result.maxLatencyMs);
console.log('请求总字节数:', result.requestBytes);
console.log('响应总字节数:', result.responseBytes);
// console.log('请求总字节数:', result.requestBytes);
// console.log('响应总字节数:', result.responseBytes);
console.log('每秒请求数:', result.rps);
}
});

Loading…
Cancel
Save