import { vertexsMap, Entity, Structure, LogicItem, LEVEL_ENUM, utils } from '../..'; import { NameGroup } from './utils'; export function genQueryStructure(allEntities: Array, nameGroup: NameGroup) { allEntities = Array.from(new Set(allEntities)); return { level: 'structure', ideVersion: '2.0', editable: true, name: nameGroup.structure, type: 'object', propertyList: allEntities.map((entity) => ({ level: 'property', ideVersion: '2.0', editable: true, name: utils.firstLowerCase(entity.name), $ref: entity.schemaRef, _posIndex: 0, typeKey: entity.schemaRef, })), serviceId: allEntities[0].serviceId, serviceType: 'entity', }; } function genWhereExpression(entity: Entity): object { const propertyList = entity.propertyList.filter((property) => property?.display.inFilter); const expressions = propertyList.map((property) => { const res = { left: { level: 'expressionNode', type: 'QueryFieldExpression', label: '查询组件实体属性', joinPartRef: entity.name, propertyRef: property.id, code: `ID_${entity.id}.ID_${property.id}`, }, right: { level: 'expressionNode', type: 'MemberExpression', object: { level: 'expressionNode', type: 'Identifier', name: 'filter', }, property: { level: 'expressionNode', type: 'Identifier', code: `ID_${property.id}`, schemaRef: property.id, }, }, }; if (!property.$relationEntity && ['#/basicTypes/String', '#/basicTypes/Text'].includes(property.typeKey)) { Object.assign(res, { level: 'expressionNode', type: 'QueryStringFilterExpression', filterName: 'like', }); } else { Object.assign(res, { level: 'expressionNode', type: 'BinaryExpression', operator: '==', }); } return res; }); function transList2Tree(arr: Array): object { if (arr.length <= 1) return arr[0]; const len = arr.length; const mid = len >> 1; const left = arr.slice(0, mid); const right = arr.slice(mid); return { level: 'expressionNode', type: 'LogicalExpression', operator: '&&', left: transList2Tree(left), right: transList2Tree(right), }; } return transList2Tree(expressions); } export function genQueryAssignment(allEntities: Array, nameGroup: NameGroup, supportFilter: boolean, supportSort: boolean) { allEntities = Array.from(allEntities); const entity = allEntities.shift(); const from = { level: 'expressionNode', parentAttr: 'from', folded: false, type: 'QueryFromExpression', entityRef: entity.id, joinPartList: allEntities.map((relationEntity) => { const leftProperty = entity.propertyList.find((property) => property.$relationEntity === relationEntity.id); return { level: 'expressionNode', parentAttr: 'joinPartList', folded: false, type: 'QueryJoinExpression', joinType: 'LEFT', entityRef: relationEntity.id, joinPartList: [] as Array, popupOpened: false, onExpressionList: [{ level: 'expressionNode', parentAttr: 'onExpressionList', label: '算术运算', folded: false, type: 'BinaryExpression', left: { level: 'expressionNode', parentAttr: 'left', label: '查询组件实体属性', folded: false, type: 'QueryFieldExpression', propertyRef: leftProperty.id, joinPartRef: entity.name, }, right: { level: 'expressionNode', parentAttr: 'right', label: '查询组件实体属性', folded: false, type: 'QueryFieldExpression', propertyRef: leftProperty.$relationProperty, joinPartRef: relationEntity.name, }, operator: '==', }], serviceId: entity.serviceId, }; }), }; const whereExpression = supportFilter && genWhereExpression(entity); const where = whereExpression ? [whereExpression] : []; return { level: 'logicNode', label: '赋值', folded: false, type: 'AssignmentExpression', operator: '=', left: { level: 'expressionNode', parentAttr: 'left', folded: false, type: 'Identifier', name: 'result', }, right: { level: 'logicNode', parentAttr: 'right', label: '数据查询', folded: false, type: 'CallQueryComponent', structureRef: nameGroup.structure, select: { level: 'expressionNode', parentAttr: 'select', label: '查询组件Select子句', folded: false, type: 'QuerySelectExpression', distinct: false, star: true, selectElementList: [] as Array, }, from, where, groupBy: [] as Array, having: [] as Array, orderBy: supportSort ? [{ level: 'expressionNode', type: 'QueryOrderByExpression', label: '查询组件OrderBy元素', order: { level: 'expressionNode', type: 'Identifier', name: 'order', }, orderElement: { level: 'expressionNode', type: 'Identifier', name: 'sort', }, }] : [], logicName: nameGroup.interface, serviceId: entity.serviceId, structureName: nameGroup.structure, limit: { level: 'expressionNode', parentAttr: 'limit', label: '查询组件 Limit 子句', folded: false, type: 'QueryLimitExpression', pageElement: { level: 'expressionNode', parentAttr: 'pageElement', folded: false, type: 'Identifier', name: 'page', }, pageSizeElement: { level: 'expressionNode', parentAttr: 'pageElement', folded: false, type: 'Identifier', name: 'size', }, }, }, }; } export function genQueryInterface( allEntities: Array, nameGroup: NameGroup, supportFilter: boolean, supportSort: boolean, ) { const itface = { level: LEVEL_ENUM.interface, name: nameGroup.interface, path: '/api/' + nameGroup.interface, method: 'POST', description: '', entityId: allEntities[0].id, serviceType: 'MICROSERVICE', serviceId: allEntities[0].serviceId, parameters: '', requestBody: null as string, responses: '{"200":{"description":"","content":{"application/json":{"schema":{"type":"genericType","typeInstantiation":{"typeName":"PageOf","typeParams":[{"typeParamValue":{"$ref":""},"type":"typeParam","typeParamName":"T"}]}}}}}}', logic: { level: 'logic', name: nameGroup.interface, description: '', moduleId: allEntities[0].serviceId, moduleType: 'microService', params: [ { level: LEVEL_ENUM.param, type: 'Identifier', name: 'page', description: '', schema: { type: 'integer', format: 'int' }, required: false, in: '', }, { level: LEVEL_ENUM.param, type: 'Identifier', name: 'size', description: '', schema: { type: 'integer', format: 'int' }, required: false, in: '', }, ], returns: [ { level: LEVEL_ENUM.return, type: 'Identifier', name: 'result', description: '', schema: { type: 'genericType', typeInstantiation: { typeName: 'PageOf', typeParams: [ { typeParamValue: { $ref: nameGroup.structure, }, type: 'typeParam', typeParamName: 'T', }, ], }, }, }, ], variables: [] as Array, body: [ { level: 'logicNode', label: '开始', folded: false, type: 'Start', }, genQueryAssignment(allEntities, nameGroup, supportFilter, supportSort), { level: 'logicNode', label: '结束', folded: false, type: 'End', }, ], playground: [] as Array, }, }; if (supportSort) itface.logic.params.push( { level: LEVEL_ENUM.param, type: 'Identifier', name: 'sort', description: '', schema: { type: 'string', format: '' }, required: false, in: '', }, { level: LEVEL_ENUM.param, type: 'Identifier', name: 'order', description: '', schema: { type: 'string', format: '' }, required: false, in: '', }, ); if (supportFilter) itface.logic.params.push({ level: LEVEL_ENUM.param, type: 'Identifier', name: 'filter', schema: { $ref: allEntities[0].schemaRef, }, required: false, in: '', } as any); const parameters: any = {}; let requestBody: any; let responses: any; itface.logic.params.forEach((param: any) => { if (param.in === 'body') { requestBody = { description: param.description, content: { 'application/json': { schema: param.schema, }, }, }; } else { parameters[param.name] = { name: param.name, description: param.description, in: param.in, required: param.required, schema: param.schema, }; } }); const ret = itface.logic.returns[0]; if (ret) { responses = { 200: { description: ret.description, content: { 'application/json': { schema: ret.schema, }, }, }, }; } itface.parameters = JSON.stringify(parameters); itface.requestBody = JSON.stringify(requestBody); itface.responses = JSON.stringify(responses); return itface; } export async function joinEntity(callQueryComponent: LogicItem, entity: Entity, recordStructure: Structure) { let lastJoinPart = (callQueryComponent as any).from; const queue = [lastJoinPart]; let joinInfo: { leftPropertyRef: string, rightPropertyRef: string }; // 找出应该 join 的 Part while (queue.length) { lastJoinPart = queue.shift(); queue.push(...lastJoinPart.joinPartList); // 无法判断用户行为,优先加有关系的 const lastEntity = vertexsMap.get(lastJoinPart.entityRef) as Entity; // lastEntity 和 entity Join // 判断要不要自动关联 onExpression // 一般左联是自动有的了 const rightProperty = entity.propertyList.find((property) => lastEntity.id === property.$relationEntity); if (rightProperty) { const leftProperty = vertexsMap.get(rightProperty.$relationProperty); joinInfo = { leftPropertyRef: leftProperty.id, rightPropertyRef: rightProperty.id, }; break; } else { const leftProperty = lastEntity.propertyList.find((property) => property.$relationEntity === entity.id); if (leftProperty) { const rightProperty = vertexsMap.get(leftProperty.$relationProperty); joinInfo = { leftPropertyRef: leftProperty.id, rightPropertyRef: rightProperty.id, }; break; } } } if (!joinInfo) { lastJoinPart = (callQueryComponent as any).from; } const newJoinPartLogicItem = LogicItem.from({ level: 'expressionNode', folded: false, type: 'QueryJoinExpression', joinType: 'LEFT', entityRef: entity.id, joinPartList: [], popupOpened: false, onExpressionList: [], _posIndex: lastJoinPart.length, parentId: lastJoinPart.id, parentAttr: 'joinPartList', logicId: callQueryComponent.logicId, }, callQueryComponent.logic, null); await newJoinPartLogicItem.createOrMove({ parent: lastJoinPart, parentId: lastJoinPart.id, parentAttr: 'joinPartList', }); if (joinInfo) { const onExpression = { level: 'expressionNode', label: '算术运算', folded: false, type: 'BinaryExpression', left: { level: 'expressionNode', ideVersion: '2.0', label: '查询组件实体属性', folded: false, type: 'QueryFieldExpression', propertyRef: joinInfo.leftPropertyRef, joinPartRef: lastJoinPart.id, parentAttr: 'left', }, right: { level: 'expressionNode', ideVersion: '2.0', label: '查询组件实体属性', folded: false, type: 'QueryFieldExpression', propertyRef: joinInfo.rightPropertyRef, joinPartRef: newJoinPartLogicItem.id, parentAttr: 'right', }, operator: '==', parentAttr: 'onExpressionList', _posIndex: 0, logicId: callQueryComponent.logicId, }; const onExpressionLogicItem = LogicItem.from(onExpression, callQueryComponent.logic, newJoinPartLogicItem); await onExpressionLogicItem.createOrMove({ parent: newJoinPartLogicItem, parentId: newJoinPartLogicItem.id, parentAttr: 'onExpressionList', }, { checkTypeIgnore: true, }); } await recordStructure.loadPro(); } export default genQueryAssignment;