@lcap/asl
Version:
NetEase Application Specific Language
493 lines (466 loc) • 16.7 kB
text/typescript
import { vertexsMap, Entity, Structure, LogicItem, LEVEL_ENUM, utils } from '../..';
import { NameGroup } from './utils';
export function genQueryStructure(allEntities: Array<Entity>, 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>): 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<Entity>, 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<any>,
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<any>,
},
from,
where,
groupBy: [] as Array<any>,
having: [] as Array<any>,
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<Entity>, 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":"<structureRef>"},"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<any>,
body: [
{
level: 'logicNode',
label: '开始',
folded: false,
type: 'Start',
},
genQueryAssignment(allEntities, nameGroup, supportFilter, supportSort),
{
level: 'logicNode',
label: '结束',
folded: false,
type: 'End',
},
],
playground: [] as Array<any>,
},
};
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;