import { GraphQLBoolean, GraphQLFloat, GraphQLInt, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLString, isEqualType, getNamedType, isNullableType, isListType } from "graphql"; import * as _ from "lodash"; import {AbstractDataType} from "sequelize"; import {SequelizeAdapter} from "../../SequelizeAdapter"; import {DateType, JSONType} from "../../sequelizeImpl/types"; import CONS from "../../constant"; import {ModelValidateOptions} from "sequelize/types/lib/model"; import {GenerateAdapterConfig} from "../../utils"; type FieldMetadata = { type: string; dataType: string; name: string; description: string; title: string; allowNull: boolean; isPk: boolean; isList: boolean; editable: boolean; createAble: boolean; sortable: boolean; validate?: ModelValidateOptions; } type AssociationsMetadata = { type: string; name: string; isList: boolean; } const FieldMetadataType = new GraphQLObjectType({ name: "FieldMetadata", description: "字段描述", fields: { type: { description: "gql数据类型", type: GraphQLNonNull(GraphQLString) }, dataType: { description: "sequelize定义类型", type: GraphQLString }, name: { description: "字段键值", type: GraphQLNonNull(GraphQLString) }, description: { description: "字段描述", type: GraphQLString }, title: { description: "字段标签", type: GraphQLString }, allowNull: { description: "允许为空", type: GraphQLNonNull(GraphQLBoolean) }, isPk: { description: "是否主键", type: GraphQLBoolean }, isList: { description: "是否列表", type: GraphQLNonNull(GraphQLBoolean) }, sortable: { description: "是否可以排序", type: GraphQLNonNull(GraphQLBoolean) }, editable: { description: "是否可编辑", type: GraphQLNonNull(GraphQLBoolean) }, createAble: { description: "是否可创建", type: GraphQLNonNull(GraphQLBoolean) }, validate: { description: "验证规则", type: JSONType } } }); const AssociationMetadataType = new GraphQLObjectType({ name: "AssociationMetadataType", description: "字段描述", fields: { type: { description: "gql数据类型", type: GraphQLNonNull(GraphQLString) }, name: { description: "字段键值", type: GraphQLNonNull(GraphQLString) }, associationType: { description: "关联类型", type: GraphQLNonNull(GraphQLString) }, isList: { description: "是否列表", type: GraphQLNonNull(GraphQLBoolean) } } }); export const MetaDataType = new GraphQLObjectType({ name: "GqlTableMetaData", description: "单表的定义", fields: { name: { description: "表名", type: new GraphQLNonNull(GraphQLString) }, type: { description: "类型", type: new GraphQLNonNull(GraphQLString) }, pkName: { description: "主键字段", type: GraphQLString }, fields: { description: "所有模型字段", type: new GraphQLList(FieldMetadataType) }, associations: { description: "关联字段", type: new GraphQLList(AssociationMetadataType) }, description: { description: "描述字段", type: GraphQLString }, editable: { description: "是否可编辑", type: GraphQLNonNull(GraphQLBoolean) }, createAble: { description: "是否可创建", type: GraphQLNonNull(GraphQLBoolean) }, removeAble: { description: "是否可删除", type: GraphQLNonNull(GraphQLBoolean) }, } }); type TableMetaData = { name: string; description: string; type: string; pkName?: string; createAble: boolean; editable: boolean; removeAble: boolean; fields: FieldMetadata[]; associations: AssociationsMetadata[]; } function getSortable(key: string, adapter: SequelizeAdapter): boolean { const field = adapter.modelType.getFields()[key]; const attribute = adapter.model.rawAttributes[key]; if (attribute) { return ["TIME", "BIGINT", "DECIMAL", "DATE", "INTEGER", "FLOAT", "DOUBLE", "DOUBLE PRECISION"].some(type => (attribute.type as AbstractDataType).key === type); } return [GraphQLInt, GraphQLFloat, DateType].some(type => isEqualType(type, field.type)); } /** * 获取所有字段数据 * @param type * @param adapter * @returns {FieldMetadata[]} */ function getTypeFieldsMetadata(type: GraphQLObjectType, adapter: SequelizeAdapter) { const fields = type.getFields(); return Object.keys(fields).filter(key => ![CONS.aggregationName, CONS.colName].includes(key)).map(key => { const field = fields[key]; const attribute = adapter.model.rawAttributes[key]; return { type: getNamedType(field.type).toString(), dataType: attribute ? (_.isString(attribute.type) ? attribute.type : attribute.type.key) : undefined, isPk: attribute ? Boolean(attribute.primaryKey) : undefined, isList: isListType(field.type), allowNull: isNullableType(field.type), name: key, description: field.description, title: field.description || key, sortable: getSortable(key, adapter), editable: !!adapter.updateType.getFields()[key], createAble: !!adapter.createType.getFields()[key], validate: attribute?.validate }; }); } /** * 获取关联关系数据 * @param type * @param adapter * @returns {AssociationsMetadata[]} */ function getAssociationsMetadata(type: GraphQLObjectType, adapter: SequelizeAdapter) { const fields = type.getFields(); return Object.keys(fields).filter(key => adapter.model.associations[key]).map(key => { const field = fields[key]; return { type: getNamedType(field.type).toString(), isList: isListType(field.type), name: key }; }); } export function getMetaData(adapter: SequelizeAdapter, options: GenerateAdapterConfig): TableMetaData { const mutationFields = (adapter.mutationFields[adapter.name]?.type as GraphQLObjectType)?.getFields() || {}; return { name: adapter.name, pkName: adapter.primaryKeyName, type: adapter.modelType.toString(), description: adapter.description, createAble: !!options.includeMutation && !!mutationFields[adapter.nameMutationCreate], editable: !!options.includeMutation && !!mutationFields[adapter.nameMutationUpdate], removeAble: !!options.includeMutation && !!mutationFields[adapter.nameMutationRemove], fields: getTypeFieldsMetadata(adapter.modelType, adapter), associations: getAssociationsMetadata(adapter.modelType, adapter), }; } export function getMetaDataList(adapters: { [key: string]: SequelizeAdapter }, options: GenerateAdapterConfig): TableMetaData[] { return Object.keys(adapters).map(key => { const adapter = adapters[key]; return getMetaData(adapter, options); }); }