@lcap/asl
Version:
NetEase Application Specific Language
508 lines (483 loc) • 15.3 kB
text/typescript
import { immutable, circular, excludedInJSON, action } from '../decorators';
import {
config, utils, LEVEL_ENUM, Vertex, Entity, Schema, Interface,
convert2RefType, ActionOptions,
} from '..';
import { entityService } from '../../service/data';
import { getBasicTypeDefaultValue } from './basicTypes';
import { updateAllVariablesChildrenSchema } from '../logic/BaseVariable';
import { schemaService } from '../../service/common';
export interface Display {
readonly inDetail: boolean;
readonly inFilter: boolean;
readonly inForm: boolean;
readonly inTable: boolean;
}
/**
* 实体属性类
*/
export class EntityProperty extends Vertex implements Schema {
/**
* 概念类型
*/
public level: LEVEL_ENUM = LEVEL_ENUM.property;
/**
* Id
*/
public readonly id: string = undefined;
/**
* 名称
*/
public readonly name: string = undefined;
/**
* 标题
*/
public readonly label: string = undefined;
/**
* 描述
*/
public readonly description: string = undefined;
/**
* type
*/
public readonly type: string = undefined;
/**
* 数据格式
*/
public readonly format: string = undefined;
/**
* 是否必须
*/
public readonly required: boolean = undefined;
/**
* 数据类型
*/
public readonly $ref: string = undefined;
/**
* 数据结构Id
*/
public readonly $refId: string = undefined;
/**
* 引用关系(多对一、一对多等)
*/
public readonly relationship: string = undefined;
/**
* 规则
*/
public readonly rules: Array<string> = [];
/**
* UI 展示
*/
public readonly display: Display = {
inDetail: true,
inFilter: true,
inForm: true,
inTable: true,
};
/**
* 默认值
*/
public readonly defaultValue: string | boolean | number = undefined;
/**
* 是否为主键
*/
public readonly primaryKey: boolean = undefined;
/**
* 父级 Id
*/
public readonly entityId: string = undefined;
/**
* 父级引用
*/
public root: Entity = undefined;
/**
* 节点是否为叶子节点
* 前端 UI 状态
*/
public isLeaf: boolean = true;
/**
* 周边存在的名称
*/
public existingNames: Array<string> = [];
/**
* 数据类型Key,例子:"/#basicType/String",在前端使用
*/
public readonly typeKey: string = undefined;
/**
* 外键引用实体
*/
public readonly $relationEntity: string = undefined;
/**
* 外键引用实体字段
*/
public readonly $relationProperty: string = undefined;
/**
* 外键删除规则
*/
public readonly relationDelRule: string = undefined;
/**
* 上一版本规则
*/
public readonly lastVersion: EntityProperty = undefined;
/**
* @param source 需要合并的部分参数
*/
constructor(source?: Partial<EntityProperty>) {
super();
source && this.assign(source);
}
/**
* 添加实体属性
*/
async create(none?: void, actionOptions?: ActionOptions) {
config.defaultApp?.emit('saving', true);
const body = this.toJSON();
///
// convert2SchemaType(body);
body._posIndex = this.root.propertyList.indexOf(this);
///
utils.logger.debug('添加实体属性', body);
const result: Entity = await entityService.addProperty({
headers: {
appId: config.defaultApp?.id,
operationAction: actionOptions?.actionName || 'EntityProperty.create',
operationDesc: actionOptions?.actionDesc || `添加实体"${this.root.name}"属性"${this.name}"`,
},
body,
});
this.deepPick(result, ['id']);
// 先改成异步的
this.root.syncInterfaces().then(() => {
updateAllVariablesChildrenSchema();
this.root.dataNode.service.emit('dataTypesChange');
this.root.dataNode.service.emit('vertexIdToNameChange', this.id, this.name);
});
await config.defaultApp?.history.load();
config.defaultApp?.emit('saved');
return this;
}
/**
* 删除实体属性
*/
async delete(none?: void, actionOptions?: ActionOptions) {
config.defaultApp?.emit('saving', true);
try {
if (this.id) {
await entityService.deleteProperty({
headers: {
appId: config.defaultApp?.id,
operationAction: actionOptions?.actionName || 'EntityProperty.delete',
operationDesc: actionOptions?.actionDesc || `删除实体"${this.root.name}"属性"${this.name}"`,
},
query: {
id: this.id,
},
});
}
const index = this.root.propertyList.indexOf(this);
~index && this.root.propertyList.splice(index, 1);
updateAllVariablesChildrenSchema();
if (this.id) {
this.root.syncInterfaces();
}
this.destroy();
this.root.dataNode.service.emit('dataTypesChange');
await config.defaultApp?.history.load();
config.defaultApp?.emit('saved');
} catch (err) {
config.defaultApp?.emit('saved');
throw err;
}
}
/**
* 修改实体属性
*/
async update(none?: void, actionOptions?: ActionOptions, then?: () => Promise<any>) {
config.defaultApp?.emit('saving', true);
const body = this.toJSON();
delete body.display.id;
utils.logger.debug('修改实体属性', body);
const result = await entityService.updateProperty({
headers: {
appId: config.defaultApp?.id,
operationAction: actionOptions?.actionName || 'EntityPropperty.update',
operationDesc: actionOptions?.actionDesc || `修改实体"${this.root.name}"属性"${this.name}"`,
},
body,
});
await then?.();
await config.defaultApp?.history.load();
config.defaultApp?.emit('saved');
return this;
}
/**
* 设置实体属性名称
* @param name 名称
*/
async setName(name: string) {
const oldName = this.name;
this.assign({ name });
await this.update(undefined, {
actionDesc: `设置实体"${this.root.name}"的属性"${oldName}"的名称为"${name}"`,
}, async () => {
await this.root.syncInterfaces();
});
this.root.dataNode.service.emit('dataTypesChange');
this.root.dataNode.service.emit('vertexIdToNameChange', this.id, this.name);
}
/**
* 设置实体属性标题
* @param label 标题
*/
async setLabel(label: string) {
this.assign({ label });
await this.update(undefined, {
actionDesc: `设置实体"${this.root.name}"的属性"${this.name}"的标题为"${label}"`,
});
}
/**
* 设置实体属性描述
* @param description 描述
*/
async setDescription(description: string) {
this.assign({ description });
await this.update(undefined, {
actionDesc: `设置实体"${this.root.name}"的属性"${this.name}"的描述为"${description}"`,
});
}
/**
* 查找schema 顶点被引用的逻辑顶点列表
*/
async getSchemaUsage() {
const result = await schemaService.getSchemaUsage({
query: {
schemaId: this.id,
valSource: 'entity_property',
},
});
return result;
}
/**
* 设置实体属性的数据类型
*/
async setDataType(schema: Schema) {
// 用于update失败后还原数据
const originalData = {
$ref: this.$ref,
type: this.type,
format: this.format,
defaultValue: this.defaultValue,
relationship: this.relationship,
rules: this.rules,
$relationEntity: this.$relationEntity,
$relationProperty: this.$relationProperty,
};
this.assign({
$ref: undefined, //引用到Entity或者structure
type: undefined,
format: undefined,
});
this.assign(schema);
this.assign({
defaultValue: getBasicTypeDefaultValue(),
relationship: '',
rules: [],
$relationEntity: '',
$relationProperty: '',
});
try {
await this.update(undefined, {
actionDesc: `设置实体"${this.root.name}"的属性"${this.name}"的数据类型为"${schema.typeKey}"`,
});
this.assign({ isDataTypeSetting: false });
await this.root.syncInterfaces();
updateAllVariablesChildrenSchema();
this.root.dataNode.service.emit('dataTypesChange');
} catch (err) {
this.assign(convert2RefType(originalData));
config.defaultApp?.emit('saved');
throw err;
}
}
/**
* 设置实体属性关系
*/
async setRelationship(relationship: string) {
this.assign({ relationship });
await this.update(undefined, {
actionDesc: `设置实体"${this.root.name}"的属性"${this.name}"的关系为"${relationship}"`,
});
this.root.dataNode.service.emit('dataTypesChange');
}
/**
* 设置实体属性外键
* reference: {$relationEntity, $relationProperty}
*/
async setReference(reference: any) {
this.assign(reference);
await this.update(undefined, {
actionDesc: `设置实体"${this.root.name}"的属性"${this.name}"的关联字段为"${reference.$relationProperty}"`,
});
this.root.dataNode.service.emit('dataTypesChange');
}
/**
* 清除实体属性外键
*/
async clearReference() {
this.assign({
$relationEntity: undefined,
$relationProperty: undefined,
relationDelRule: undefined,
});
await this.update(undefined, {
actionDesc: `清除实体"${this.root.name}"的属性"${this.name}"的外键`,
});
this.root.dataNode.service.emit('dataTypesChange');
}
async setRelationDelRule(relationDelRule: string) {
this.assign({ relationDelRule });
await this.update(undefined, {
actionDesc: `设置实体属性外键删除规则`,
});
}
async setRules(rules: any) {
this.assign({ rules });
await this.update(undefined, {
actionDesc: `设置实体属性规则`,
});
}
/**
* 设置实体属性的默认值
*/
async setDefaultValue(defaultValue: string) {
this.assign({ defaultValue });
await this.update(undefined, {
actionDesc: `设置实体"${this.root.name}"的属性"${this.name}"的默认值为"${defaultValue}"`,
});
this.root.dataNode.service.emit('dataTypesChange');
}
/**
* 设置实体属性是否必须
* @param required 必须
*/
async setRequired(required: boolean) {
this.assign({ required });
await this.update(undefined, {
actionDesc: `设置实体"${this.root.name}"的属性"${this.name}"为"${required ? '必须' : '不必须'}"`,
});
this.root.dataNode.service.emit('dataTypesChange');
}
async setDisplay(display: Display) {
this.assign({ display });
await this.update(undefined, {
actionDesc: '设置实体属性显示',
});
}
/**
* 移动位置
* @param index 目标位置
*/
async moveTo(index: number, oldIndex?: number) {
const propertyList = this.root.propertyList;
if (oldIndex === undefined)
oldIndex = propertyList.indexOf(this);
propertyList.splice(oldIndex, 1);
propertyList.splice(index, 0, this);
await entityService.moveProperty({
headers: {
appId: config.defaultApp?.id,
operationAction: null,
operationDesc: null,
},
query: {
id: this.id,
targetIndex: index,
},
});
}
/**
* 上移实体属性
*/
moveUp() {
const propertyList = this.root.propertyList;
const oldIndex = propertyList.indexOf(this);
if (oldIndex === 0)
return;
return this.moveTo(oldIndex - 1, oldIndex);
}
/**
* 属性下移
*/
moveDown() {
const propertyList = this.root.propertyList;
const oldIndex = propertyList.indexOf(this);
if (oldIndex === propertyList.length - 1)
return;
return this.moveTo(oldIndex + 1, oldIndex);
}
/**
* 只更改Entity Property的名称
*/
async updateLogicParamsForName(entity: Entity, property: EntityProperty) {
const itfacePrefix = ['getAll', 'count', 'export'];
const interfaces: Array<Interface> = (entity.resolvers || [])
.filter((resolver) => itfacePrefix.includes(resolver.name))
.map((resolver) => resolver.interface);
const tasks = interfaces.map((itface) => {
if (itface.logic) {
return itface.logic.params.filter((param) => param.entityFieldId === this.id)
.map((param) => {
const name = param.name.split('.');
const newName = `${property.name}.${name[1]}`;
return param.setName(newName);
});
} else {
return [];
}
});
await Promise.all(tasks);
}
}
export default EntityProperty;