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 { /** * 概念类型 */ @immutable() public readonly level: LEVEL_ENUM = LEVEL_ENUM.entity; /** * 实体 Id */ @immutable() public readonly id: string = undefined; /** * dataTypes 中的唯一标识 */ @immutable() public readonly schemaRef: string = undefined; /** * 实体名称 */ @immutable() public readonly name: string = undefined; /** * 实体描述 */ @immutable() public readonly description: string = undefined; /** * 实体类型(如enum) */ @immutable() public readonly type: 'object' = 'object'; /** * 实体属性列表 */ @immutable() public readonly propertyList: Array = []; /** * 实体索引列表 */ @immutable() public readonly indexList: Array = []; @excludedInJSON() @immutable() public readonly resolvers: Array = []; /** * 所属服务 Id */ @immutable() public readonly serviceId: string = undefined; /** * 所属服务类型 */ @immutable() public readonly serviceType: string = undefined; /** * 所属服务 */ @immutable() public readonly service: MicroService = undefined; /** * 上个版本数据 */ @immutable() @excludedInJSON() public readonly lastVersionDef: any = undefined; /** * 父节点 */ @circular() @immutable() public readonly dataNode: DataNode = undefined; /** * 周边存在的名称 */ @excludedInJSON() public existingNames: Array = []; static properties2PropertyList: any; /** * @param source 需要合并的部分参数 */ constructor(source?: Partial) { 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; } /** * 添加实体 */ @action('添加实体') 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) { 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; } /** * 删除实体 */ @action('删除实体') 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 名称 */ @action('设置实体名称') 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 描述 */ @action('设置实体描述') 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 = await interfaceService.loadList({ query: { serviceId: service.id, entityId: this.id, }, }); const entity = this; entity.assign({ resolvers: [] }); let newInterfaces: Array = []; interfaces.forEach((itface) => { if (itface.serviceType === 'export') { return; } let tempItface = vertexsMap.get(itface.id); if (tempItface) { tempItface.plainAssign(itface); if (tempItface.logic) { tempItface.logic.plainAssign(itface.logic); const params: Array = []; const returns: Array = []; const variables: Array = []; itface.logic.params.forEach((param) => { const tempParam = 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 = 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 = 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 = await structureService.loadList({ query: { id: service.id, }, }); const newStructures: Array = []; structures.forEach((structure) => { let structureInstance = 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; 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; propertyList.forEach((property, index) => { property = propertyList[index] = new EntityProperty(property); property.assign({ root: entity }); }); entity.assign({ resolvers: undefined }); const indexList = entity.indexList as Array; indexList.forEach((indexItem, index) => { indexItem = indexList[index] = new EntityIndex(indexItem); indexItem.assign({ root: entity }); }); dataTypesMap[entity.schemaRef] = entity; return entity; } } export default Entity;