mgs-graphql
Version:
The simple way to generates GraphQL schemas and Sequelize models from your models definition,microservice supported
194 lines (176 loc) • 6.63 kB
JavaScript
// @flow
const _ = require('lodash')
const Sequelize = require('sequelize')
const camelCase = require('camelcase')
const Type = require('../type')
const StringHelper = require('../utils/StringHelper')
const ModelRef = require('../definition/RemoteSchema')
module.exports = function toSequelizeModel (sequelize, schema) {
const dbDefinition = {}
const dbType = (fieldType) => {
if (fieldType instanceof Type.ScalarFieldType) {
return fieldType.columnType
}
if (fieldType instanceof ModelRef) {
return Sequelize.INTEGER
}
switch (fieldType) {
case String:
return Sequelize.STRING
case Number:
return Sequelize.DOUBLE
case Boolean:
return Sequelize.BOOLEAN
case Date:
return Sequelize.DATE(6)
case JSON:
return Sequelize.JSON
}
return Sequelize.JSON
}
_.forOwn(schema.config.fields, (value, key) => {
let fType = value
if (value && value['$type']) {
fType = value['$type']
}
if (typeof fType === 'string') {
let foreignField = key
let foreignFieldId = key + 'Id'
let onDelete = 'RESTRICT'
if (value && value['$type'] && value.column) {
if (value.column.onDelete) {
onDelete = value.column.onDelete
}
}
if (value && value['$type'] && value.required) {
schema.belongsTo({
[key]: {
target: fType,
hidden: true,
foreignField: foreignField,
foreignKey: {name: foreignFieldId, field: StringHelper.toUnderscoredName(foreignFieldId), allowNull: false},
onDelete: onDelete,
constraints: true
}
})
} else {
schema.belongsTo({
[key]: {
target: fType,
hidden: true,
foreignField: foreignField,
foreignKey: {name: foreignFieldId, field: StringHelper.toUnderscoredName(foreignFieldId)},
onDelete: onDelete,
constraints: true
}
})
}
} else {
const type = dbType(fType)
if (type) {
if (type === Sequelize.JSON) {
console.warn('please ensure the json field:', key)
}
if (value && value['$type']) {
if (fType instanceof ModelRef) {
// console.log(`schema db mode ${schema.name} generate remote ref:${key} => ${key + 'Id'} `)
if (!fType.name.endsWith('Id') || !key.endsWith('Id')) {
key = key + 'Id'
}
}
dbDefinition[key] = {type: type}
if (value.required != null) {
dbDefinition[key].allowNull = !value.required
}
if (value.default != null) {
dbDefinition[key].defaultValue = value.default
}
if (value.validate != null) {
dbDefinition[key].validate = value.validate
}
if (value.enumValues != null) {
dbDefinition[key].type = Sequelize.ENUM(...value.enumValues)
}
if (value.description != null) {
dbDefinition[key].comment = value.description
}
dbDefinition[key] = {...dbDefinition[key], ...value.column}
} else {
dbDefinition[key] = {type: type}
}
if (sequelize.options.define.underscored && dbDefinition[key].field == null) {
dbDefinition[key].field = StringHelper.toUnderscoredName(key)
}
} else {
throw new Error('Unknown column type for ' + fType)
}
}
})
// schema定义中的indexes的field驼峰名称改为下划线来新建table
if (schema.config.options['table'] && schema.config.options['table']['indexes']) {
schema.config.options['table']['indexes'].forEach((item) => {
let tempFields = []
if (item['fields']) {
item['fields'].forEach((field) => {
tempFields.push(field.replace(/([A-Z])/g, '_$1').toLowerCase())
})
}
item['fields'] = tempFields
})
}
const rewriteHooks = (schema) => {
const schemaOptions = schema.config.options
let tableHooks = schemaOptions['table'] && schemaOptions['table']['hooks'] ? schemaOptions['table']['hooks'] : {}
// 判断schema.options内是否设置了subscription参数,并定义了hook
if (schemaOptions && schemaOptions['subscription'] && schemaOptions['subscription']['hooks']) {
// && schemaOptions['table'] && schemaOptions['table'].hooks
// 重新定义table的hooks
let subscriptionHooks = schemaOptions['subscription']['hooks'] || {}
const pubSub = schemaOptions['subscription']['pubSub']
const baseSubscriptionHookFunction = (instance, {baseHookOptions: {pubSub, key}}) => {
// console.log('instance.id', instance.id)
pubSub.publish(key, {instance})
}
const tableOldHooks = _.clone(tableHooks)
// 遍历所有的subscriptionHooks
_.forOwn(subscriptionHooks, (value, key) => {
// subscriptionHook 未定义或者设置为false, 不做任何事情
if (value) {
// 判断订阅hook的执行方式
let subscriptionHookFunction = (instance, options) => {}
if (typeof value === 'boolean' && value === true) {
if (!pubSub) {
throw new Error('schema options subscription `pubSub` is not defined')
}
subscriptionHookFunction = baseSubscriptionHookFunction
}
if (typeof value === 'function') {
subscriptionHookFunction = value
}
tableHooks[key] = function (instance, options) {
// 当定义了table hooks, 则先执行hooks方法
if (tableOldHooks[key]) {
tableOldHooks[key](instance, options)
}
if (pubSub) {
options.baseHookOptions = {
baseHookOptions: {
key: camelCase(`${schema.name} ${key}SubscriptionKey`),
pubSub
}
}
}
subscriptionHookFunction(instance, options)
}
}
})
}
return tableHooks
}
// // console.log("Create Sequlize Model with config", model.name, dbDefinition, model.config.options["table"])
const dbModel = sequelize.define(schema.name, dbDefinition, {
...schema.config.options['table'],
hooks: rewriteHooks(schema)
})
return dbModel
}