@graphql-codegen/typescript-mongodb
Version:
GraphQL Code Generator plugin for generting a ready-to-use ORM types for MongoDB
234 lines (233 loc) • 11.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TsMongoVisitor = void 0;
const tslib_1 = require("tslib");
const auto_bind_1 = tslib_1.__importDefault(require("auto-bind"));
const graphql_1 = require("graphql");
const visitor_plugin_common_1 = require("@graphql-codegen/visitor-plugin-common");
const config_js_1 = require("./config.js");
const fields_tree_js_1 = require("./fields-tree.js");
function resolveObjectId(pointer) {
if (!pointer) {
return { identifier: 'ObjectId', module: 'mongodb' };
}
if (pointer.includes('#')) {
const [path, module] = pointer.split('#');
return { identifier: path, module };
}
return {
identifier: pointer,
module: null,
};
}
class TsMongoVisitor extends visitor_plugin_common_1.BaseVisitor {
constructor(_schema, pluginConfig) {
super(pluginConfig, {
dbTypeSuffix: pluginConfig.dbTypeSuffix || 'DbObject',
dbInterfaceSuffix: pluginConfig.dbInterfaceSuffix || 'DbInterface',
objectIdType: resolveObjectId(pluginConfig.objectIdType).identifier,
objectIdImport: resolveObjectId(pluginConfig.objectIdType).module,
idFieldName: pluginConfig.idFieldName || '_id',
enumsAsString: (0, visitor_plugin_common_1.getConfigValue)(pluginConfig.enumsAsString, true),
avoidOptionals: (0, visitor_plugin_common_1.getConfigValue)(pluginConfig.avoidOptionals, false),
scalars: (0, visitor_plugin_common_1.buildScalarsFromConfig)(_schema, pluginConfig),
});
this._schema = _schema;
(0, auto_bind_1.default)(this);
}
get objectIdImport() {
if (this.config.objectIdImport === null) {
return null;
}
return `import { ${this.config.objectIdType} } from '${this.config.objectIdImport}';`;
}
_resolveDirectiveValue(valueNode) {
switch (valueNode.kind) {
case graphql_1.Kind.INT:
case graphql_1.Kind.STRING:
case graphql_1.Kind.FLOAT:
case graphql_1.Kind.BOOLEAN:
case graphql_1.Kind.ENUM:
return valueNode.value;
case graphql_1.Kind.LIST:
return valueNode.values.map(v => this._resolveDirectiveValue(v));
case graphql_1.Kind.NULL:
return null;
case graphql_1.Kind.OBJECT:
return valueNode.fields.reduce((prev, f) => {
return {
...prev,
[f.name.value]: this._resolveDirectiveValue(f.value),
};
}, {});
default:
return undefined;
}
}
_getDirectiveArgValue(node, argName) {
if (!node || !node.arguments || node.arguments.length === 0) {
return undefined;
}
const foundArgument = node.arguments.find(a => a.name.value === argName);
if (!foundArgument) {
return undefined;
}
return this._resolveDirectiveValue(foundArgument.value);
}
_getDirectiveFromAstNode(node, directiveName) {
if (!node || !node.directives || node.directives.length === 0) {
return null;
}
const foundDirective = node.directives.find(d => d.name === directiveName || (d.name.value && d.name.value === directiveName));
if (!foundDirective) {
return null;
}
return foundDirective;
}
_buildInterfaces(interfaces) {
return (interfaces || [])
.map(namedType => {
const schemaType = this._schema.getType(namedType.name.value);
const abstractEntityDirective = this._getDirectiveFromAstNode(schemaType.astNode, config_js_1.Directives.ABSTRACT_ENTITY);
if (!abstractEntityDirective) {
return null;
}
return this.convertName(namedType.name.value, { suffix: this.config.dbInterfaceSuffix });
})
.filter(a => a);
}
_handleIdField(fieldNode, tree, addOptionalSign) {
tree.addField(`${this.config.idFieldName}${addOptionalSign ? '?' : ''}`, (0, visitor_plugin_common_1.wrapTypeNodeWithModifiers)(this.config.objectIdType, fieldNode.type));
}
_handleLinkField(fieldNode, tree, linkDirective, mapPath, addOptionalSign) {
const overrideType = this._getDirectiveArgValue(linkDirective, 'overrideType');
const coreType = overrideType || (0, visitor_plugin_common_1.getBaseTypeNode)(fieldNode.type);
const type = this.convertName(coreType, { suffix: this.config.dbTypeSuffix });
tree.addField(`${mapPath || fieldNode.name.value}${addOptionalSign ? '?' : ''}`, (0, visitor_plugin_common_1.wrapTypeNodeWithModifiers)(`${type}['${this.config.idFieldName}']`, fieldNode.type));
}
_handleColumnField(fieldNode, tree, columnDirective, mapPath, addOptionalSign) {
const overrideType = this._getDirectiveArgValue(columnDirective, 'overrideType');
const coreType = (0, visitor_plugin_common_1.getBaseTypeNode)(fieldNode.type);
let type = null;
if (this.scalars[coreType.name.value]) {
type = this.scalars[coreType.name.value];
}
else {
const schemaType = this._schema.getType(coreType.name.value);
if ((0, graphql_1.isEnumType)(schemaType) && this.config.enumsAsString) {
type = this.scalars.String;
}
else {
type = coreType.name.value;
}
}
tree.addField(`${mapPath || fieldNode.name.value}${addOptionalSign ? '?' : ''}`, overrideType || (0, visitor_plugin_common_1.wrapTypeNodeWithModifiers)(type, fieldNode.type));
}
_handleEmbeddedField(fieldNode, tree, mapPath, addOptionalSign) {
const coreType = (0, visitor_plugin_common_1.getBaseTypeNode)(fieldNode.type);
const type = this.convertName(coreType, { suffix: this.config.dbTypeSuffix });
tree.addField(`${mapPath || fieldNode.name.value}${addOptionalSign ? '?' : ''}`, (0, visitor_plugin_common_1.wrapTypeNodeWithModifiers)(type, fieldNode.type));
}
_buildFieldsTree(fields) {
const tree = new fields_tree_js_1.FieldsTree();
fields.forEach(field => {
const idDirective = this._getDirectiveFromAstNode(field, config_js_1.Directives.ID);
const linkDirective = this._getDirectiveFromAstNode(field, config_js_1.Directives.LINK);
const columnDirective = this._getDirectiveFromAstNode(field, config_js_1.Directives.COLUMN);
const embeddedDirective = this._getDirectiveFromAstNode(field, config_js_1.Directives.EMBEDDED);
const mapDirective = this._getDirectiveFromAstNode(field, config_js_1.Directives.MAP);
const mapPath = this._getDirectiveArgValue(mapDirective, 'path');
const addOptionalSign = !this.config.avoidOptionals && field.type.kind !== graphql_1.Kind.NON_NULL_TYPE;
if (idDirective) {
this._handleIdField(field, tree, addOptionalSign);
}
else if (linkDirective) {
this._handleLinkField(field, tree, linkDirective, mapPath, addOptionalSign);
}
else if (columnDirective) {
this._handleColumnField(field, tree, columnDirective, mapPath, addOptionalSign);
}
else if (embeddedDirective) {
this._handleEmbeddedField(field, tree, mapPath, addOptionalSign);
}
});
return tree;
}
_addAdditionalFields(tree, additioalFields) {
const { avoidOptionals } = this.config;
if (!additioalFields || additioalFields.length === 0) {
return;
}
for (const field of additioalFields) {
const isOptional = field.path.includes('?');
tree.addField(`${isOptional && avoidOptionals ? field.path.replace(/\?/g, '') : field.path}`, field.type);
}
}
InterfaceTypeDefinition(node) {
const abstractEntityDirective = this._getDirectiveFromAstNode(node, config_js_1.Directives.ABSTRACT_ENTITY);
if (abstractEntityDirective === null) {
return null;
}
const discriminatorField = this._getDirectiveArgValue(abstractEntityDirective, 'discriminatorField');
const additionalFields = this._getDirectiveArgValue(abstractEntityDirective, 'additionalFields');
const fields = this._buildFieldsTree(node.fields);
fields.addField(discriminatorField, this.scalars.String);
this._addAdditionalFields(fields, additionalFields);
return new visitor_plugin_common_1.DeclarationBlock(this._declarationBlockConfig)
.export()
.asKind('type')
.withName(this.convertName(node, { suffix: this.config.dbInterfaceSuffix }))
.withBlock(fields.string).string;
}
UnionTypeDefinition(node) {
const unionDirective = this._getDirectiveFromAstNode(node, config_js_1.Directives.UNION);
if (unionDirective === null) {
return null;
}
const discriminatorField = this._getDirectiveArgValue(unionDirective, 'discriminatorField');
const possibleTypes = node.types
.map(namedType => {
const schemaType = this._schema.getType(namedType.name.value);
const entityDirective = this._getDirectiveFromAstNode(schemaType.astNode, config_js_1.Directives.ENTITY);
const abstractEntityDirective = this._getDirectiveFromAstNode(schemaType.astNode, config_js_1.Directives.ABSTRACT_ENTITY);
if (entityDirective) {
return this.convertName(namedType, { suffix: this.config.dbTypeSuffix });
}
if (abstractEntityDirective) {
return this.convertName(namedType, { suffix: this.config.dbInterfaceSuffix });
}
return null;
})
.filter(a => a);
if (possibleTypes.length === 0) {
return null;
}
const additionalFields = this._getDirectiveArgValue(unionDirective, 'additionalFields');
const fields = new fields_tree_js_1.FieldsTree();
fields.addField(discriminatorField, this.scalars.String);
this._addAdditionalFields(fields, additionalFields);
return new visitor_plugin_common_1.DeclarationBlock(this._declarationBlockConfig)
.export()
.asKind('type')
.withName(this.convertName(node, { suffix: this.config.dbTypeSuffix }))
.withContent(`(${possibleTypes.join(' | ')}) & `)
.withBlock(fields.string).string;
}
ObjectTypeDefinition(node) {
const entityDirective = this._getDirectiveFromAstNode(node, config_js_1.Directives.ENTITY);
if (entityDirective === null) {
return null;
}
const implementingInterfaces = this._buildInterfaces(node.interfaces);
const fields = this._buildFieldsTree(node.fields);
const additionalFields = this._getDirectiveArgValue(entityDirective, 'additionalFields');
this._addAdditionalFields(fields, additionalFields);
return new visitor_plugin_common_1.DeclarationBlock(this._declarationBlockConfig)
.export()
.asKind('type')
.withName(this.convertName(node, { suffix: this.config.dbTypeSuffix }))
.withContent(implementingInterfaces.length ? implementingInterfaces.join(' & ') + ' & ' : '')
.withBlock(fields.string).string;
}
}
exports.TsMongoVisitor = TsMongoVisitor;