@lcap/asl
Version:
NetEase Application Specific Language
517 lines (484 loc) • 17.3 kB
text/typescript
import { immutable, circular, excludedInJSON, action } from '../decorators';
import {
config, utils, LEVEL_ENUM, Vertex, DataNode, Service, Structure,
StructureProperty, MicroService, Schema, Interface, Param, Return,
Variable, ObjectSchema, dataTypesMap, convert2RefType,
updateDataTypeList, EntityProperty, ActionOptions, EntityIndex,
} from '..';
import { entityService, interfaceService, structureService } from '../../service/data';
import { vertexsMap } from '../cacheData';
export interface Resolver {
level: 'resolver';
name: string;
interface: Interface;
entity: Entity;
isLeaf: boolean;
}
export const systemProperty: { [name: string]: any, } = {
id: {
name: 'id',
label: '主键',
description: '主键',
primaryKey: true,
typeKey: '#/basicTypes/Long',
type: 'integer',
format: 'long',
editable: false,
display: {
inTable: false,
inFilter: false,
inForm: false,
inDetail: false,
},
},
createdTime: {
name: 'createdTime',
label: '创建时间',
description: '创建时间',
typeKey: '#/basicTypes/DateTime',
type: 'string',
format: 'date-time',
editable: false,
display: {
inTable: true,
inFilter: false,
inForm: false,
inDetail: false,
},
},
updatedTime: {
name: 'updatedTime',
label: '更新时间',
description: '更新时间',
typeKey: '#/basicTypes/DateTime',
type: 'string',
format: 'date-time',
editable: false,
display: {
inTable: true,
inFilter: false,
inForm: false,
inDetail: false,
},
},
createdBy: {
name: 'createdBy',
label: '创建者',
description: '创建者',
typeKey: '#/basicTypes/String',
type: 'string',
format: '',
editable: false,
display: {
inTable: false,
inFilter: false,
inForm: false,
inDetail: false,
},
},
updatedBy: {
name: 'updatedBy',
label: '更新者',
description: '更新者',
typeKey: '#/basicTypes/String',
type: 'string',
format: '',
editable: false,
display: {
inTable: false,
inFilter: false,
inForm: false,
inDetail: false,
},
},
};
/**
* 实体类
*/
export class Entity extends Vertex implements ObjectSchema {
/**
* 概念类型
*/
()
public readonly level: LEVEL_ENUM = LEVEL_ENUM.entity;
/**
* 实体 Id
*/
()
public readonly id: string = undefined;
/**
* dataTypes 中的唯一标识
*/
()
public readonly schemaRef: string = undefined;
/**
* 实体名称
*/
()
public readonly name: string = undefined;
/**
* 实体描述
*/
()
public readonly description: string = undefined;
/**
* 实体类型(如enum)
*/
()
public readonly type: 'object' = 'object';
/**
* 实体属性列表
*/
()
public readonly propertyList: Array<EntityProperty> = [];
/**
* 实体索引列表
*/
()
public readonly indexList: Array<EntityIndex> = [];
()
()
public readonly resolvers: Array<Resolver> = [];
/**
* 所属服务 Id
*/
()
public readonly serviceId: string = undefined;
/**
* 所属服务类型
*/
()
public readonly serviceType: string = undefined;
/**
* 所属服务
*/
()
public readonly service: MicroService = undefined;
/**
* 上个版本数据
*/
()
()
public readonly lastVersionDef: any = undefined;
/**
* 父节点
*/
()
()
public readonly dataNode: DataNode = undefined;
/**
* 周边存在的名称
*/
()
public existingNames: Array<string> = [];
static properties2PropertyList: any;
/**
* @param source 需要合并的部分参数
*/
constructor(source?: Partial<Entity>) {
super();
source && this.assign(source);
}
/**
* 按当前 id 加载实体数据
* @requires this.id
*/
async load() {
const result = await entityService.loadDetail({
query: {
id: this.id,
},
config: {
mock: config.mock,
},
});
this.assign(result);
return this;
}
/**
* 添加实体
*/
('添加实体')
async create(none?: void, actionOptions?: ActionOptions) {
config.defaultApp?.emit('saving', true);
Object.keys(systemProperty).forEach((propertyKey) => {
this.propertyList.push(new EntityProperty(Object.assign({ root: this }, systemProperty[propertyKey])));
});
const body = this.toJSON();
body.propertyList.forEach((property: any, index: number) => property._posIndex = index);
utils.logger.debug('添加实体', body);
try {
const result: Entity = await entityService.create({
headers: {
appId: config.defaultApp?.id,
operationAction: actionOptions?.actionName || 'Entity.create',
operationDesc: actionOptions?.actionDesc || `添加实体"${this.name}"`,
},
body,
});
this.deepPick(result, ['id']);
this.emit('created');
this.assign({
schemaRef: `#/${this.dataNode.service.id}/${result.id}`,
});
dataTypesMap[this.schemaRef] = this;
// 先改成异步的
Promise.all([
this.syncInterfaces(),
]).then(() => {
updateDataTypeList();
this.dataNode.service.emit('dataTypesChange');
this.dataNode.service.emit('vertexIdToNameChange', this.id, this.name);
});
await config.defaultApp?.history.load();
config.defaultApp?.emit('saved');
return this;
} 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('', ['propertyList', 'schemaRef']);
utils.logger.debug('修改实体', body);
const result: Entity = await entityService.update({
headers: {
appId: config.defaultApp?.id,
operationAction: actionOptions?.actionName || 'Entity.update',
operationDesc: actionOptions?.actionDesc || `修改实体"${this.name}"`,
},
body,
});
await then?.();
await config.defaultApp?.history.load();
config.defaultApp?.emit('saved');
return this;
}
/**
* 删除实体
*/
('删除实体')
async delete(none?: void, actionOptions?: ActionOptions) {
config.defaultApp?.emit('saving', true);
if (this.id) {
await entityService.delete({
headers: {
appId: config.defaultApp?.id,
operationAction: actionOptions?.actionName || 'Entity.delete',
operationDesc: actionOptions?.actionDesc || `删除实体"${this.name}"`,
},
query: {
id: this.id,
},
});
}
const index = this.dataNode.entities.indexOf(this);
~index && this.dataNode.entities.splice(index, 1);
delete dataTypesMap[this.schemaRef];
if (this.id) {
await this.syncInterfaces(true);
}
updateDataTypeList();
this.destroy();
this.dataNode.service.emit('dataTypesChange');
await config.defaultApp?.history.load();
config.defaultApp?.emit('saved');
}
/**
* 设置实体名称
* @param name 名称
*/
('设置实体名称')
async setName(name: string) {
const oldName = this.name;
this.assign({ name });
await this.update(undefined, {
actionDesc: `设置实体"${oldName}"的名称为"${name}"`,
}, async () => {
await this.syncInterfaces();
});
updateDataTypeList();
this.dataNode.service.emit('dataTypesChange');
this.dataNode.service.emit('vertexIdToNameChange', this.id, this.name);
}
/**
* 设置实体描述
* @param description 描述
*/
('设置实体描述')
async setDescription(description: string) {
this.assign({ description });
await this.update(undefined, {
actionDesc: `设置实体"${this.name}"的描述为"${description}"`,
});
}
/**
* 同步interfaces
* interface、logic、params、returns、variabes采用plainAssign
* 创建、删除实体,修改实体名称、增删改实体property需要同步
*/
async syncInterfaces(isDelete?: boolean) {
if (isDelete) {
const service = this.dataNode.service;
const newInterfaces = service.interfaces.filter((itface) => itface.logic.entityId !== this.id);
service.assign({ interfaces: newInterfaces });
} else {
const service = this.dataNode.service;
const interfaces: Array<Interface> = await interfaceService.loadList({
query: {
serviceId: service.id,
entityId: this.id,
},
});
const entity = this;
entity.assign({ resolvers: [] });
let newInterfaces: Array<Interface> = [];
interfaces.forEach((itface) => {
if (itface.serviceType === 'export') {
return;
}
let tempItface = <Interface>vertexsMap.get(itface.id);
if (tempItface) {
tempItface.plainAssign(itface);
if (tempItface.logic) {
tempItface.logic.plainAssign(itface.logic);
const params: Array<Param> = [];
const returns: Array<Return> = [];
const variables: Array<Variable> = [];
itface.logic.params.forEach((param) => {
const tempParam = <Param>vertexsMap.get(param.id);
if (tempParam) {
tempParam.plainAssign(param);
tempParam.genSchemaChildren();
params.push(tempParam);
} else {
params.push(Param.from(param, tempItface.logic));
}
});
tempItface.logic.assign({ params });
itface.logic.returns.forEach((ret) => {
const tempRet = <Return>vertexsMap.get(ret.id);
if (tempRet) {
tempRet.plainAssign(ret);
tempRet.genSchemaChildren();
returns.push(tempRet);
} else {
returns.push(Return.from(ret, tempItface.logic));
}
});
tempItface.logic.assign({ returns });
itface.logic.variables.forEach((variable) => {
const tempVariable = <Variable>vertexsMap.get(variable.id);
if (tempVariable) {
tempVariable.plainAssign(variable);
tempVariable.genSchemaChildren();
variables.push(tempVariable);
} else {
variables.push(Variable.from(variable, tempItface.logic));
}
});
tempItface.logic.assign({ variables });
}
} else {
tempItface = Interface.from(itface, service);
tempItface.entityId = entity.id;
newInterfaces.push(tempItface);
}
// 重新生成resolvers
// const RESOLVER_NAMES = ['getAll', 'get', 'create', 'update', 'delete', 'count', 'import', 'export', 'batchDelete', 'batchCreate', 'batchUpdate'];
// if (tempItface.logic && tempItface.logic.entityId) {
// entity.assign({ resolvers: entity.resolvers || [] });
// const resolverName = RESOLVER_NAMES.find((name) => tempItface.name.startsWith(name));
// entity.resolvers.push({
// level: 'resolver',
// name: resolverName,
// interface: tempItface,
// entity,
// isLeaf: true,
// });
// }
});
newInterfaces = newInterfaces.concat(service.interfaces);
service.assign({ interfaces: newInterfaces });
(service as MicroService).mountResolverOnEntity();
(service as MicroService).mountResolverOnInterface();
}
this.dataNode.service.emit('interfacesChange');
}
/**
* 同步structures
* 创建、删除实体,修改实体名称需要同步
*/
async syncStructures(isDelete?: boolean) {
if (isDelete) {
const service = this.dataNode.service;
const newStructures = service.data.structures.filter((structure) => structure.entityId !== this.id);
service.data.assign({ structures: newStructures });
Object.keys(dataTypesMap).forEach((dataTypeKey) => {
if ((dataTypesMap[dataTypeKey] as any).entityId === this.id) {
delete dataTypesMap[dataTypeKey];
}
});
} else {
const service = this.dataNode.service;
const structures: Array<Structure> = await structureService.loadList({
query: {
id: service.id,
},
});
const newStructures: Array<Structure> = [];
structures.forEach((structure) => {
let structureInstance = <Structure>vertexsMap.get(structure.id);
if (structureInstance) {
structureInstance.plainAssign(structure);
} else {
convert2RefType(structure as any);
structureInstance = new Structure(structure);
structureInstance.assign({
dataNode: this.dataNode,
schemaRef: `#/${service.id}/${structure.id}`,
});
const propertyList = structureInstance.propertyList as Array<StructureProperty>;
propertyList.forEach((property, index) => {
property = propertyList[index] = new StructureProperty(property);
property.assign({ root: structureInstance });
});
structureInstance.assign({ resolvers: undefined });
dataTypesMap[structureInstance.schemaRef] = structureInstance as Schema;
}
newStructures.push(structureInstance);
});
service.data.assign({ structures: newStructures });
return newStructures;
}
}
/**
* 从后端 JSON 生成规范的 Entity 对象
*/
public static from(source: any, service: Service) {
convert2RefType(source);
const entity = new Entity(source);
entity.assign({
dataNode: service.data,
schemaRef: `#/${service.id}/${entity.id}`,
});
const propertyList = entity.propertyList as Array<EntityProperty>;
propertyList.forEach((property, index) => {
property = propertyList[index] = new EntityProperty(property);
property.assign({ root: entity });
});
entity.assign({ resolvers: undefined });
const indexList = entity.indexList as Array<EntityIndex>;
indexList.forEach((indexItem, index) => {
indexItem = indexList[index] = new EntityIndex(indexItem);
indexItem.assign({ root: entity });
});
dataTypesMap[entity.schemaRef] = entity;
return entity;
}
}
export default Entity;