UNPKG

simple-graphql

Version:

The simple way to generates GraphQL schemas and Sequelize models from your models definition.

435 lines 21.6 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const definition_1 = require("../definition"); const graphql_1 = require("graphql"); const relay = __importStar(require("graphql-relay")); const toGraphQLFieldConfigMap_1 = __importDefault(require("../transformer/toGraphQLFieldConfigMap")); const globalIdType_1 = __importDefault(require("./type/globalIdType")); const sequelize_1 = __importDefault(require("sequelize")); const toGraphQLInputFieldConfigMap_1 = __importDefault(require("../transformer/toGraphQLInputFieldConfigMap")); const type_1 = __importDefault(require("./type")); const dataType_1 = __importDefault(require("./dataType")); const lodash_1 = __importDefault(require("lodash")); const StringHelper_1 = __importDefault(require("../utils/StringHelper")); function buildModelType(schema, fieldTypeContext, context) { var _a; const typeName = schema.name; return { name: typeName, description: schema.options.description, inputType: (_a = fieldTypeContext.typeConfig(schema.name + 'Id')) === null || _a === void 0 ? void 0 : _a.inputType, outputType: new graphql_1.GraphQLObjectType({ name: typeName, interfaces: [context.interface('Node')], fields: () => (0, toGraphQLFieldConfigMap_1.default)(typeName, '', Object.assign(Object.assign({ id: { type: 'Id', nullable: false, metadata: { graphql: { resolve: function (root) { return __awaiter(this, void 0, void 0, function* () { return relay.toGlobalId(schema.name, root.id); }); } } } } }, schema.config.fields), lodash_1.default.mapValues(schema.config.links, (value, key) => { var _a; return Object.assign(Object.assign({}, value.output), { metadata: { description: value.description || ((_a = value.output.metadata) === null || _a === void 0 ? void 0 : _a.description), hookOptions: value.hookOptions, graphql: { input: value.input, dependentFields: value.dependentFields, resolve: value.resolve } } }); })), { hookFieldResolve: (name, options) => context.hookFieldResolve(name, options), hookQueryResolve: (name, options) => context.hookQueryResolve(name, options), hookSubscriptionResolve: (name, options) => context.hookSubscriptionResolve(name, options), hookMutationResolve: (name, options) => context.hookMutationResolve(name, options), typeConfig: (typeName) => fieldTypeContext.typeConfig(typeName) }) }), outputResolve: function (root, args, context, info, sgContext) { return __awaiter(this, void 0, void 0, function* () { const fieldName = info.fieldName; if (root[fieldName]) { if (typeof root[fieldName] === 'string') { const { type, id } = StringHelper_1.default.fromGlobalId(root[fieldName]); if (type === typeName) { return sgContext.models[typeName].findByPkForGraphQL(id, {}, context, info); } else { return sgContext.models[typeName].findByPkForGraphQL(root[fieldName], {}, context, info); } } else if (typeof root[fieldName] === 'number') { return sgContext.models[typeName].findByPkForGraphQL(root[fieldName], {}, context, info); } else if (typeof root[fieldName].id === 'string') { const { type, id } = StringHelper_1.default.fromGlobalId(root[fieldName].id); if (type === typeName) { return sgContext.models[typeName].findByPkForGraphQL(id, {}, context, info); } else { return root[fieldName]; } } else { return root[fieldName]; } } else if (root[fieldName + 'Id']) { return sgContext.models[typeName].findByPkForGraphQL(root[fieldName + 'Id'], {}, context, info); } return null; }); }, columnOptions: (schema, fieldName, options) => { var _a, _b, _c, _d, _e, _f, _g, _h; const foreignField = fieldName; let onDelete = ((_b = (_a = options.metadata) === null || _a === void 0 ? void 0 : _a.column) === null || _b === void 0 ? void 0 : _b.onDelete) || 'RESTRICT'; let constraints = true; if (((_d = (_c = options.metadata) === null || _c === void 0 ? void 0 : _c.column) === null || _d === void 0 ? void 0 : _d.constraints) !== undefined) { constraints = options.metadata.column.constraints; onDelete = undefined; } schema.belongsTo({ [fieldName]: { target: typeName, hidden: true, foreignField: foreignField, foreignKey: { name: ((_f = (_e = options.metadata) === null || _e === void 0 ? void 0 : _e.column) === null || _f === void 0 ? void 0 : _f.field) || foreignField + 'Id', allowNull: options.nullable !== false }, targetKey: (_h = (_g = options.metadata) === null || _g === void 0 ? void 0 : _g.column) === null || _h === void 0 ? void 0 : _h.targetKey, onDelete: onDelete, constraints: constraints } }); return null; } }; } function buildModelTypeId(schema, fieldTypeContext) { const typeName = schema.name + 'Id'; const idType = (0, globalIdType_1.default)(schema.name); return { name: typeName, description: typeName, inputType: idType, outputType: idType }; } function buildDataType(dataTypeOptions, fieldTypeContext, context) { var _a, _b; const toOutputType = (name, options) => { const outputConfigMap = (0, toGraphQLFieldConfigMap_1.default)(name, '', { '': options }, { hookFieldResolve: (name, options) => context.hookFieldResolve(name, options), hookQueryResolve: (name, options) => context.hookQueryResolve(name, options), hookSubscriptionResolve: (name, options) => context.hookSubscriptionResolve(name, options), hookMutationResolve: (name, options) => context.hookMutationResolve(name, options), typeConfig: (typeName) => fieldTypeContext.typeConfig(typeName) })['']; return outputConfigMap && outputConfigMap.type; }; const toInputType = (name, options) => { const inputConfigMap = (0, toGraphQLInputFieldConfigMap_1.default)(name, { '': options }, fieldTypeContext)['']; return inputConfigMap && inputConfigMap.type; }; let outputType, inputType; outputType = toOutputType(dataTypeOptions.name, dataTypeOptions.definition); inputType = toInputType(dataTypeOptions.name, dataTypeOptions.definition); return { name: dataTypeOptions.name, description: dataTypeOptions.description || dataTypeOptions.name, inputType: inputType, outputType: outputType, outputResolve: (_b = (_a = dataTypeOptions.definition.metadata) === null || _a === void 0 ? void 0 : _a.graphql) === null || _b === void 0 ? void 0 : _b.resolve, columnOptions: (schema, fieldName, options) => { var _a, _b; let columnOptions = null; const definition = dataTypeOptions.definition; if (definition.type) { const typeConfig = fieldTypeContext.typeConfig(definition.type); if (!typeConfig) { throw new Error(`Type "${definition.type}" has not register.`); } if (!typeConfig.columnOptions) { throw new Error(`Column type of "${definition.type}" is not supported.`); } columnOptions = typeof typeConfig.columnOptions === 'function' ? typeConfig.columnOptions(schema, fieldName, options) : typeConfig.columnOptions; } else if (definition.enum) { columnOptions = { type: sequelize_1.default.STRING(191) }; } else if (definition.elements) { columnOptions = { type: sequelize_1.default.JSON }; } else { columnOptions = { type: sequelize_1.default.JSON }; } if (columnOptions) { columnOptions = Object.assign(Object.assign({}, columnOptions), (dataTypeOptions.columnOptions || {})); if ((_a = options === null || options === void 0 ? void 0 : options.metadata) === null || _a === void 0 ? void 0 : _a.column) { columnOptions = Object.assign(Object.assign({}, columnOptions), (_b = options === null || options === void 0 ? void 0 : options.metadata) === null || _b === void 0 ? void 0 : _b.column); } return columnOptions; } else { return null; } } }; } function buildUnionWrapType(wrapType, fieldTypeContext, context) { const name = `_Union_${wrapType}`; const typeConfig = fieldTypeContext.typeConfig(wrapType); if (!(typeConfig === null || typeConfig === void 0 ? void 0 : typeConfig.outputType)) { throw new Error(`Type ${wrapType} has not register`); } return { name: name, description: `Union wrap type for ${wrapType}`, inputType: null, outputType: new graphql_1.GraphQLObjectType({ name: name, fields: { variant: { type: graphql_1.GraphQLString }, value: { type: typeConfig.outputType, resolve: (typeConfig === null || typeConfig === void 0 ? void 0 : typeConfig.outputResolve) ? context.hookFieldResolve('value', { output: { type: wrapType }, resolve: typeConfig.outputResolve }) : undefined } } }), columnOptions: { type: sequelize_1.default.JSON } }; } function default_1(types, dataTypes, schemas, context) { const typeMap = {}; const schemaMap = {}; schemas.forEach((schema) => (schemaMap[schema.name] = schema)); const resolves = [ function resolveInterfaceType(typeName) { if (typeName.endsWith('Interface')) { const gIntf = context.interface(typeName.substr(0, typeName.length - 'Interface'.length)); if (gIntf) { return { name: typeName, outputType: gIntf }; } } }, function resolveArrayType(typeName) { if (typeName.startsWith('[') && typeName.endsWith(']')) { const subTypeName = typeName.substr(1, typeName.length - 2); const typeConfig = fieldTypeContext.typeConfig(subTypeName); if (!typeConfig) { return undefined; } return { name: typeName, description: `Array of type ${subTypeName}`, inputType: typeConfig.inputType ? new graphql_1.GraphQLList(typeConfig.inputType) : null, outputType: typeConfig.outputType ? new graphql_1.GraphQLList(typeConfig.outputType) : null, outputResolve: function (root, args, context, info, sgContext) { return __awaiter(this, void 0, void 0, function* () { const fieldName = info.fieldName; if (schemaMap[subTypeName] != null) { if (root[fieldName] != null && root[fieldName].length > 0 && (typeof root[fieldName][0] === 'string' || typeof root[fieldName][0] === 'number' || (root[fieldName][0] != null && typeof root[fieldName][0].id === 'string' && StringHelper_1.default.fromGlobalId(root[fieldName][0].id).type === subTypeName))) { const dbModel = sgContext.models[subTypeName]; const ids = root[fieldName].map((r) => { if (typeof r === 'string' && StringHelper_1.default.fromGlobalId(r).type === subTypeName) { return StringHelper_1.default.fromGlobalId(r).id; } else if (r != null && typeof r.id === 'string' && StringHelper_1.default.fromGlobalId(r.id).type === subTypeName) { return StringHelper_1.default.fromGlobalId(r.id).id; } return r; }); const option = dbModel.resolveQueryOption({ info: info }); const list = dbModel.withCache ? yield dbModel.withCache().findAll({ where: { id: { [sequelize_1.default.Op.in]: ids } }, include: option.include, attributes: option.attributes }) : yield dbModel.findAll({ where: { id: { [sequelize_1.default.Op.in]: ids } }, include: option.include, attributes: option.attributes }); const result = []; for (const id of ids) { const element = list.find((e) => '' + e.id === '' + id); if (element) { result.push(element); } } return result; } } return root[fieldName]; }); }, columnOptions: { type: sequelize_1.default.JSON } }; } }, function resolveModelType(typeName) { const schema = schemaMap[typeName]; if (schema instanceof definition_1.SGSchema) { return buildModelType(schema, fieldTypeContext, context); } }, function resolveModelIdType(typeName) { if (typeName.endsWith('Id')) { const schema = schemaMap[typeName.substring(0, typeName.length - 2)]; if (schema instanceof definition_1.SGSchema) { return buildModelTypeId(schema, fieldTypeContext); } } }, function resolveModelConnectionType(typeName) { let schema = typeName.endsWith('Connection') ? schemaMap[typeName.substring(0, typeName.length - 'Connection'.length)] : null; if (typeName.endsWith('Edge')) { schema = schemaMap[typeName.substring(0, typeName.length - 'Edge'.length)]; } if (schema) { const typeConfig = fieldTypeContext.typeConfig(schema.name); if (!(typeConfig === null || typeConfig === void 0 ? void 0 : typeConfig.outputType)) { return undefined; } const connectionInfo = relay.connectionDefinitions({ name: schema.name, nodeType: typeConfig.outputType, connectionFields: { count: { type: graphql_1.GraphQLFloat } } }); typeMap[schema.name + 'Connection'] = { name: schema.name + 'Connection', description: schema.name + 'Connection', additionalInput: { after: { type: 'String' }, first: { type: 'Number' }, before: { type: 'String' }, last: { type: 'Number' } }, inputType: undefined, outputType: connectionInfo.connectionType }; typeMap[schema.name + 'Edge'] = { name: schema.name + 'Edge', description: schema.name + 'Edge', inputType: undefined, outputType: connectionInfo.edgeType }; return typeMap[typeName]; } }, function resolveUnionWrapType(typeName) { if (typeName.startsWith('_Union_')) { return buildUnionWrapType(typeName.substr('_Union_'.length), fieldTypeContext, context); } } ]; const fieldTypeContext = { typeConfig: (typeName) => { if (typeMap[typeName]) { return typeMap[typeName]; } for (const resolve of resolves) { const type = resolve(typeName); if (type) { typeMap[type.name] = type; return type; } } return null; } }; for (const f of [...type_1.default, ...types]) { typeMap[f.name] = f; } for (const d of [...dataType_1.default, ...dataTypes]) { typeMap[d.name] = buildDataType(d, fieldTypeContext, context); } return fieldTypeContext; } exports.default = default_1; //# sourceMappingURL=buildFieldTypeContext.js.map