UNPKG

graphql-compose-mongoose

Version:

Plugin for `graphql-compose` which derive a graphql types from a mongoose model.

309 lines 13.1 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; var _a; Object.defineProperty(exports, "__esModule", { value: true }); exports.ComplexTypes = void 0; exports.dotPathsToEmbedded = dotPathsToEmbedded; exports.getFieldsFromModel = getFieldsFromModel; exports.convertModelToGraphQL = convertModelToGraphQL; exports.convertSchemaToGraphQL = convertSchemaToGraphQL; exports.convertFieldToGraphQL = convertFieldToGraphQL; exports.deriveComplexType = deriveComplexType; exports.scalarToGraphQL = scalarToGraphQL; exports.arrayToGraphQL = arrayToGraphQL; exports.embeddedToGraphQL = embeddedToGraphQL; exports.enumToGraphQL = enumToGraphQL; exports.documentArrayToGraphQL = documentArrayToGraphQL; exports.referenceToGraphQL = referenceToGraphQL; const mongoose_1 = __importDefault(require("mongoose")); const graphql_compose_1 = require("graphql-compose"); const MongoID_1 = __importDefault(require("./types/MongoID")); const BSONDecimal_1 = __importDefault(require("./types/BSONDecimal")); var ComplexTypes; (function (ComplexTypes) { ComplexTypes["ARRAY"] = "ARRAY"; ComplexTypes["EMBEDDED"] = "EMBEDDED"; ComplexTypes["DOCUMENT_ARRAY"] = "DOCUMENT_ARRAY"; ComplexTypes["ENUM"] = "ENUM"; ComplexTypes["REFERENCE"] = "REFERENCE"; ComplexTypes["SCALAR"] = "SCALAR"; ComplexTypes["MIXED"] = "MIXED"; ComplexTypes["DECIMAL"] = "DECIMAL"; })(ComplexTypes || (exports.ComplexTypes = ComplexTypes = {})); const SubdocumentTypeClass = ((_a = mongoose_1.default.Schema.Types) === null || _a === void 0 ? void 0 : _a.Embedded) || mongoose_1.default.Schema.Types.Subdocument; function _getFieldName(field) { return field.path || '__unknownField__'; } function _getFieldType(field) { return field.instance; } function _getFieldDescription(field) { if (field.options && field.options.description) { return field.options.description; } return undefined; } function _getFieldEnums(field) { if (field.enumValues && field.enumValues.length > 0) { return field.enumValues; } return undefined; } function dotPathsToEmbedded(fields) { const result = {}; Object.keys(fields).forEach((fieldName) => { const dotIdx = fieldName.indexOf('.'); if (dotIdx === -1) { result[fieldName] = fields[fieldName]; } else if (fieldName.substr(dotIdx, 3) === '.$*') { } else { const name = fieldName.substr(0, dotIdx); if (!result[name]) { const embeddedField = { instance: 'Embedded', path: name, schema: { paths: {}, }, }; result[name] = embeddedField; } const subName = fieldName.substr(dotIdx + 1); const fieldSchema = result[name].schema; if (!fieldSchema) { throw new Error(`Field ${name} does not have schema property`); } fieldSchema.paths[subName] = Object.assign(Object.assign({}, fields[fieldName]), { path: subName }); } }); return result; } function getFieldsFromModel(model) { if (!model || !model.schema || !model.schema.paths) { throw new Error('You provide incorrect mongoose model to `getFieldsFromModel()`. ' + 'Correct model should contain `schema.paths` properties.'); } const fields = {}; const paths = dotPathsToEmbedded(model.schema.paths); Object.keys(paths) .filter((path) => !path.startsWith('__')) .forEach((path) => { fields[path] = paths[path]; }); return fields; } function convertModelToGraphQL(model, typeName, schemaComposer) { const sc = schemaComposer; if (!typeName) { throw new Error('You provide empty name for type. `name` argument should be non-empty string.'); } if (sc.has(model.schema)) { return sc.getOTC(model.schema); } const typeComposer = sc.getOrCreateOTC(typeName); sc.set(model.schema, typeComposer); sc.set(typeName, typeComposer); const mongooseFields = getFieldsFromModel(model); const graphqlFields = {}; const requiredFields = []; Object.keys(mongooseFields).forEach((key) => { var _a, _b; const mongooseField = mongooseFields[key]; let fieldName = key; if (typeof ((_a = mongooseField === null || mongooseField === void 0 ? void 0 : mongooseField.options) === null || _a === void 0 ? void 0 : _a.alias) === 'string') { fieldName = (_b = mongooseField === null || mongooseField === void 0 ? void 0 : mongooseField.options) === null || _b === void 0 ? void 0 : _b.alias; } if (mongooseField.isRequired && typeof (mongooseField === null || mongooseField === void 0 ? void 0 : mongooseField.originalRequiredValue) !== 'function') { requiredFields.push(fieldName); } let type = convertFieldToGraphQL(mongooseField, typeName, sc); if (fieldName === '_id' && type === 'Float') { type = 'Int'; } graphqlFields[fieldName] = { type, description: _getFieldDescription(mongooseField), }; if ((mongooseField === null || mongooseField === void 0 ? void 0 : mongooseField.schema) && (mongooseField === null || mongooseField === void 0 ? void 0 : mongooseField.$isSingleNested)) { graphqlFields[fieldName].extensions = { isSingleNestedMongooseSchema: true, }; } if ((mongooseField === null || mongooseField === void 0 ? void 0 : mongooseField.defaultValue) !== null && (mongooseField === null || mongooseField === void 0 ? void 0 : mongooseField.defaultValue) !== undefined) { if (!graphqlFields[fieldName].extensions) graphqlFields[fieldName].extensions = {}; graphqlFields[fieldName].extensions.defaultValue = mongooseField === null || mongooseField === void 0 ? void 0 : mongooseField.defaultValue; } }); typeComposer.addFields(graphqlFields); typeComposer.makeFieldNonNull(requiredFields); return typeComposer; } function convertSchemaToGraphQL(schema, typeName, schemaComposer) { const sc = schemaComposer; if (!typeName) { throw new Error('You provide empty name for type. `name` argument should be non-empty string.'); } if (sc.has(schema)) { return sc.getOTC(schema); } const tc = convertModelToGraphQL({ schema }, typeName, sc); tc.getInputTypeComposer(); sc.set(schema, tc); return tc; } function convertFieldToGraphQL(field, prefix = '', schemaComposer) { if (!schemaComposer.has('MongoID')) { schemaComposer.add(MongoID_1.default); } const complexType = deriveComplexType(field); switch (complexType) { case ComplexTypes.SCALAR: return scalarToGraphQL(field); case ComplexTypes.ARRAY: return arrayToGraphQL(field, prefix, schemaComposer); case ComplexTypes.EMBEDDED: return embeddedToGraphQL(field, prefix, schemaComposer); case ComplexTypes.ENUM: return enumToGraphQL(field, prefix, schemaComposer); case ComplexTypes.REFERENCE: return referenceToGraphQL(field); case ComplexTypes.DOCUMENT_ARRAY: return documentArrayToGraphQL(field, prefix, schemaComposer); case ComplexTypes.MIXED: return 'JSON'; case ComplexTypes.DECIMAL: if (!schemaComposer.has('BSONDecimal')) { schemaComposer.add(BSONDecimal_1.default); } return 'BSONDecimal'; default: return scalarToGraphQL(field); } } function deriveComplexType(field) { var _a, _b; if (!field || !field.path || !field.instance) { throw new Error('You provide incorrect mongoose field to `deriveComplexType()`. ' + 'Correct field should contain `path` and `instance` properties.'); } const fieldType = _getFieldType(field); if (field instanceof mongoose_1.default.Schema.Types.DocumentArray || (fieldType === 'Array' && ((_a = field === null || field === void 0 ? void 0 : field.schema) === null || _a === void 0 ? void 0 : _a.paths))) { return ComplexTypes.DOCUMENT_ARRAY; } else if (field instanceof SubdocumentTypeClass || fieldType === 'Embedded') { return ComplexTypes.EMBEDDED; } else if (field instanceof mongoose_1.default.Schema.Types.Array || ((_b = field === null || field === void 0 ? void 0 : field.caster) === null || _b === void 0 ? void 0 : _b.instance)) { return ComplexTypes.ARRAY; } else if (field instanceof mongoose_1.default.Schema.Types.Mixed) { return ComplexTypes.MIXED; } else if (fieldType === 'ObjectID' || fieldType === 'ObjectId') { return ComplexTypes.REFERENCE; } else if (fieldType === 'Decimal128') { return ComplexTypes.DECIMAL; } else if (fieldType === 'Number') { return ComplexTypes.SCALAR; } const enums = _getFieldEnums(field); if (enums) { return ComplexTypes.ENUM; } return ComplexTypes.SCALAR; } function scalarToGraphQL(field) { const typeName = _getFieldType(field); switch (typeName) { case 'String': return 'String'; case 'Number': return 'Float'; case 'Date': return 'Date'; case 'Buffer': return 'Buffer'; case 'Boolean': return 'Boolean'; case 'ObjectId': case 'ObjectID': return 'MongoID'; default: return 'JSON'; } } function arrayToGraphQL(field, prefix = '', schemaComposer) { if (!field || (!field.caster && !field.embeddedSchemaType)) { throw new Error('You provide incorrect mongoose field to `arrayToGraphQL()`. ' + 'Correct field should contain `caster` property.'); } const unwrappedField = Object.assign({}, (field.caster || field.embeddedSchemaType)); const outputType = convertFieldToGraphQL(unwrappedField, prefix, schemaComposer); return [outputType]; } function embeddedToGraphQL(field, prefix = '', schemaComposer) { const fieldName = _getFieldName(field); const fieldType = _getFieldType(field); if (fieldType !== 'Embedded') { throw new Error(`You provide incorrect field '${prefix}.${fieldName}' to 'embeddedToGraphQL()'. ` + 'This field should has `Embedded` type. '); } const fieldSchema = field.schema; if (!fieldSchema) { throw new Error(`Mongoose field '${prefix}.${fieldName}' should have 'schema' property`); } const typeName = `${prefix}${(0, graphql_compose_1.upperFirst)(fieldName)}`; return convertSchemaToGraphQL(fieldSchema, typeName, schemaComposer); } function enumToGraphQL(field, prefix = '', schemaComposer) { const valueList = _getFieldEnums(field); if (!valueList) { throw new Error('You provide incorrect mongoose field to `enumToGraphQL()`. ' + 'Correct field should contain `enumValues` property'); } const typeName = `Enum${prefix}${(0, graphql_compose_1.upperFirst)(_getFieldName(field))}`; return schemaComposer.getOrCreateETC(typeName, (etc) => { const desc = _getFieldDescription(field); if (desc) etc.setDescription(desc); const fields = valueList === null || valueList === void 0 ? void 0 : valueList.reduce((result, value) => { var _a, _b; let key; if (value === null) { key = 'NULL'; } else if (value === '') { key = 'EMPTY_STRING'; } else { key = (_b = (_a = value === null || value === void 0 ? void 0 : value.toString()) === null || _a === void 0 ? void 0 : _a.replace(/[^_a-zA-Z0-9]/g, '_')) === null || _b === void 0 ? void 0 : _b.replace(/(^[0-9])(.*)/g, 'a_$1$2'); } result[key] = { value }; return result; }, {}); etc.setFields(fields); }); } function documentArrayToGraphQL(field, prefix = '', schemaComposer) { var _a; if (!(field instanceof mongoose_1.default.Schema.Types.DocumentArray) && !((_a = field === null || field === void 0 ? void 0 : field.schema) === null || _a === void 0 ? void 0 : _a.paths)) { throw new Error('You provide incorrect mongoose field to `documentArrayToGraphQL()`. ' + 'Correct field should be instance of `mongoose.Schema.Types.DocumentArray`'); } const typeName = `${prefix}${(0, graphql_compose_1.upperFirst)(_getFieldName(field))}`; const tc = convertModelToGraphQL(field, typeName, schemaComposer); return [tc]; } function referenceToGraphQL(field) { return scalarToGraphQL(field); } //# sourceMappingURL=fieldsConverter.js.map