mongoose-to-swagger
Version:
Conversion library for transforming Mongoose schema objects into Swagger schema definitions.
654 lines • 27.7 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (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;
};
Object.defineProperty(exports, "__esModule", { value: true });
const chai_1 = require("chai");
const documentModel = require(".");
const mongoose_1 = __importStar(require("mongoose"));
const { getFieldsFromMongooseSchema } = documentModel;
describe('index.test.ts', () => {
describe('mixed', () => {
it('basic mixed type handling', () => {
const schema = new mongoose_1.default.Schema({
a: {
type: mongoose_1.default.Schema.Types.Mixed,
},
});
const swagger = documentModel({ schema });
chai_1.expect(swagger.properties).to.exist;
chai_1.expect(swagger.properties.a.type).to.equal('object');
chai_1.expect(swagger.properties.a.properties).to.deep.equal({});
console.log(JSON.stringify(swagger, null, 2));
});
it('basic mixed type handling - inferred', () => {
const schema = new mongoose_1.default.Schema({
a: {
type: {},
},
});
const swagger = documentModel({ schema });
chai_1.expect(swagger.properties).to.exist;
chai_1.expect(swagger.properties.a.type).to.equal('object');
chai_1.expect(swagger.properties.a.properties).to.deep.equal({});
console.log(JSON.stringify(swagger, null, 2));
});
it('basic mixed type handling - inferred shorthand', () => {
const schema = new mongoose_1.default.Schema({
a: {},
});
const swagger = documentModel({ schema });
chai_1.expect(swagger.properties).to.exist;
chai_1.expect(swagger.properties.a.type).to.equal('object');
chai_1.expect(swagger.properties.a.properties).to.deep.equal({});
console.log(JSON.stringify(swagger, null, 2));
});
it('nested mixed type handling', () => {
const schema = new mongoose_1.default.Schema({
a: new mongoose_1.default.Schema({
b: {
type: new mongoose_1.default.Schema({}),
},
}),
});
const swagger = documentModel({ schema: schema });
chai_1.expect(swagger.properties).to.exist;
console.log(JSON.stringify(swagger, null, 2));
chai_1.expect(swagger.properties.a.properties.b.type).to.equal('object');
chai_1.expect(swagger.properties.a.properties.b.properties).to.deep.equal({
_id: {
type: 'string',
},
});
});
it('nested omitFields handling', () => {
const schema = new mongoose_1.default.Schema({
a: new mongoose_1.default.Schema({
b: {
type: new mongoose_1.default.Schema({}),
},
}),
});
const swagger = documentModel({ schema: schema }, { omitFields: ['_id'] });
chai_1.expect(swagger.properties._id).to.be.undefined;
chai_1.expect(swagger.properties.a.properties._id).to.be.undefined;
chai_1.expect(swagger.properties.a.properties.b._id).to.be.undefined;
});
it('nested mixed type handling - inferred shorthand', () => {
const schema = new mongoose_1.default.Schema({
a: new mongoose_1.default.Schema({
b: {},
}),
});
const swagger = documentModel({ schema: schema });
chai_1.expect(swagger.properties).to.exist;
chai_1.expect(swagger.properties.a.properties.b.type).to.equal('object');
chai_1.expect(swagger.properties.a.properties.b.properties).to.deep.equal({});
});
it('nested mixed type handling - inferred shorthand 2', () => {
const schema = new mongoose_1.default.Schema({
a: new mongoose_1.default.Schema({
b: { type: {} },
c: String,
}),
});
const swagger = documentModel({ schema: schema });
console.log(JSON.stringify(swagger, null, 2));
chai_1.expect(swagger.properties).to.exist;
chai_1.expect(swagger.properties.a.properties.c.type).to.equal('string');
chai_1.expect(swagger.properties.a.properties.b.type).to.equal('object');
chai_1.expect(swagger.properties.a.properties.b.properties).to.deep.equal({});
});
it('nested mixed type handling - addtl fields', () => {
const schema = new mongoose_1.default.Schema({
a: new mongoose_1.default.Schema({
b: {
type: new mongoose_1.default.Schema({
d: String,
e: new mongoose_1.default.Schema({}),
}),
},
c: String,
}),
});
const swagger = documentModel({ schema: schema });
console.log(JSON.stringify(swagger, null, 2));
chai_1.expect(swagger.properties).to.exist;
chai_1.expect(swagger.properties.a.properties.c.type).to.equal('string');
chai_1.expect(swagger.properties.a.properties.b.type).to.equal('object');
chai_1.expect(swagger.properties.a.properties.b.properties.d.type).to.equal('string');
chai_1.expect(swagger.properties.a.properties.b.properties.e.type).to.equal('object');
});
});
it.skip('should do something', () => {
const Cat = mongoose_1.default.model('Cat', new mongoose_1.Schema({ name: String }));
const swagger = documentModel(Cat);
chai_1.expect(swagger.properties).to.exist;
});
describe('adjustType', () => {
it('should work for string', () => {
const result = documentModel.adjustType('String');
chai_1.expect(result).to.equal('string');
});
it('should work for object - 1 of 2', () => {
const result = documentModel.adjustType('ObjectId');
chai_1.expect(result).to.equal('string');
});
it('should work for object - 2 of 2 - different spelling', () => {
const result = documentModel.adjustType('ObjectID');
chai_1.expect(result).to.equal('string');
});
});
describe('documentModel', () => {
let schema;
before(() => {
schema = new mongoose_1.default.Schema({
title: String,
author: String,
body: String,
comments: [{ body: String, date: Date }],
likes: [],
date: { type: Date, default: Date.now },
hidden: { type: Boolean, required: true },
toggles: {
type: Map,
of: Boolean,
},
meta: {
votes: Number,
favs: Number,
},
user: {
type: mongoose_1.default.Schema.Types.ObjectId,
ref: 'User',
},
nestedUser: new mongoose_1.default.Schema({
user: {
type: mongoose_1.default.Schema.Types.ObjectId,
ref: 'User',
},
}),
});
});
it('virtual handling', () => {
const schema = new mongoose_1.Schema({});
schema.virtual('f', () => 'b');
const result = documentModel({ schema });
const virtualField = result.properties.f;
chai_1.expect(virtualField).to.not.exist;
});
it('sub schema array handling', () => {
const Thing = new mongoose_1.Schema({
cost: {
type: Number,
required: true,
},
});
const schema = new mongoose_1.Schema({
f: {
things: {
type: [Thing],
required: true,
},
},
});
const result = documentModel({ schema });
const field = result.properties.f;
chai_1.expect(field).to.exist;
chai_1.expect(field.type).to.equal('object');
chai_1.expect(field.properties.things).to.exist;
chai_1.expect(field.properties.things.type).to.equal('array');
chai_1.expect(field.properties.things.items.required).to.include('cost');
});
it('should respect omitMongooseInternals option', () => {
const schema = new mongoose_1.Schema({
name: String,
id: String,
__v: Number,
});
const results = getFieldsFromMongooseSchema(schema, {
props: [],
omitFields: [],
omitMongooseInternals: false,
});
const nameField = results.find(x => x.field === 'name');
chai_1.expect(nameField.type, 'nameField.type').to.exist;
chai_1.expect(nameField.type).to.equal('string');
const idField = results.find(x => x.field === 'id');
chai_1.expect(idField.type, 'idField.type').to.exist;
chai_1.expect(idField.type).to.equal('string');
const vField = results.find(x => x.field === '__v');
chai_1.expect(vField.type, 'vField.type').to.exist;
chai_1.expect(vField.type).to.equal('number');
const result = documentModel({
schema,
}, {
omitMongooseInternals: false,
});
const props = result.properties;
chai_1.expect(props.name).to.exist;
chai_1.expect(props.id).to.exist;
chai_1.expect(props._id).to.exist;
chai_1.expect(props.__v).to.exist;
const propsPartialOmit = documentModel({
schema,
}, {
omitFields: ['__v'],
omitMongooseInternals: false,
}).properties;
chai_1.expect(propsPartialOmit.name).to.exist;
chai_1.expect(propsPartialOmit.id).to.exist;
chai_1.expect(propsPartialOmit._id).to.exist;
chai_1.expect(propsPartialOmit.__v).to.not.exist;
const propsFullOmit = documentModel({
schema,
}, {
omitMongooseInternals: true,
}).properties;
chai_1.expect(propsFullOmit.name).to.exist;
chai_1.expect(propsFullOmit.id).to.not.exist;
chai_1.expect(propsFullOmit._id).to.exist;
chai_1.expect(propsFullOmit.__v).to.not.exist;
});
it('other various types', () => {
const schema = new mongoose_1.Schema({
name: String,
tags: [String],
age: {
type: Number,
},
bonus: {
max: {
type: Number,
},
},
names: {
asd: String,
fgh: [String],
fgz: [Number],
jkl: [{
foo: String,
}],
},
birthday: Date,
birthday2: { type: Date },
status: {
type: Number,
},
ref: {
type: mongoose_1.default.Schema.Types.ObjectId,
ref: 'ref',
required: true,
},
bla: [{
foo: String,
bar: String,
}],
schemaArr: [new mongoose_1.Schema({
type: {
type: Number,
enum: [1, 2, 3],
},
})],
decimal: {
type: mongoose_1.default.Types.Decimal128,
},
});
schema.virtual('f', () => 'b');
const results = getFieldsFromMongooseSchema(schema, { props: [], omitFields: [] });
const nameField = results.find(x => x.field === 'name');
chai_1.expect(nameField.type, 'nameField.type').to.exist;
chai_1.expect(nameField.type).to.equal('string');
const tagsField = results.find(x => x.field === 'tags');
chai_1.expect(tagsField.type).to.equal('array');
if (tagsField.type !== 'array') {
throw new Error('fail');
}
chai_1.expect(tagsField.items, 'tagsField.items').to.exist;
chai_1.expect(tagsField.items.type, 'tagsField.items.type').to.equal('string');
const namesField = results.find(x => x.field === 'names');
chai_1.expect(namesField.type).to.equal('object');
const birthdayField = results.find(x => x.field === 'birthday');
chai_1.expect(birthdayField.type).to.equal('string');
chai_1.expect(birthdayField.format).to.equal('date-time');
const statusField = results.find(x => x.field === 'status');
chai_1.expect(statusField.type).to.equal('number');
const refField = results.find(x => x.field === 'ref');
chai_1.expect(refField.type).to.equal('string');
const schemaArr = results.find(x => x.field === 'schemaArr');
if (schemaArr.type !== 'array') {
throw new Error('fail');
}
if (schemaArr.items.type !== 'object') {
throw new Error('fail');
}
const decimal = results.find(x => x.field === 'decimal');
chai_1.expect(decimal.type).to.equal('number');
chai_1.expect(schemaArr.items.properties).to.exist;
chai_1.expect(schemaArr.items.properties.type).to.exist;
});
it('nested string array 1 of 2', () => {
const result = documentModel({
schema: new mongoose_1.default.Schema({
scopes: [
{
actions: [String],
},
],
}),
});
const props = result.properties;
chai_1.expect(props.scopes).to.exist;
chai_1.expect(props.scopes.items.properties.actions.type).to.equal('array');
chai_1.expect(props.scopes.items.properties.actions.items.type).to.equal('string');
});
it('nested string array 2 of 2', () => {
const result = documentModel({
schema: new mongoose_1.default.Schema({
scopes: [
{
actions: [{ type: String, required: true }],
},
],
}),
});
const props = result.properties;
chai_1.expect(props.scopes).to.exist;
chai_1.expect(props.scopes.items.properties.actions.type).to.equal('array');
chai_1.expect(props.scopes.items.properties.actions.items.type).to.equal('string');
const actions = props.scopes.items.properties.actions;
});
it('string', () => {
const result = documentModel({ schema });
const props = result.properties;
chai_1.expect(props.author).to.exist;
chai_1.expect(props.author.type).to.equal('string');
});
it('string - lowercase', () => {
const result = documentModel({
schema: new mongoose_1.Schema({
author: {
type: 'string',
},
}),
});
const props = result.properties;
chai_1.expect(props.author).to.exist;
chai_1.expect(props.author.type).to.equal('string');
});
it('string + enum', () => {
const result = documentModel({
schema: new mongoose_1.Schema({
foo: {
type: String,
enum: ['bar', 'baz'],
required: true,
},
}),
});
const props = result.properties;
chai_1.expect(props.foo).to.exist;
chai_1.expect(props.foo.type).to.equal('string');
chai_1.expect(props.foo.enum).to.exist;
chai_1.expect(props.foo.enum).to.not.be.empty;
chai_1.expect(props.foo.enum).to.contain('bar');
chai_1.expect(result.required).to.not.be.empty;
chai_1.expect(result.required).to.contain('foo');
});
it('date', () => {
const result = documentModel({ schema });
const props = result.properties;
chai_1.expect(props.date).to.exist;
chai_1.expect(props.date.type).to.equal('string');
chai_1.expect(props.date.format).to.equal('date-time');
});
it('map', () => {
const result = documentModel({ schema });
const props = result.properties;
chai_1.expect(props.toggles).to.exist;
chai_1.expect(props.toggles.type).to.equal('object');
const additionalProperties = props.toggles.additionalProperties;
chai_1.expect(additionalProperties).to.exist;
chai_1.expect(additionalProperties.type).to.equal('boolean');
});
it('mongoose model relation', () => {
const result = documentModel({ schema });
const props = result.properties;
chai_1.expect(props.user).to.exist;
chai_1.expect(props.user.type).to.equal('string');
});
it('nested mongoose model', () => {
const result = documentModel({ schema });
const props = result.properties;
chai_1.expect(props.nestedUser).to.exist;
chai_1.expect(props.nestedUser.properties).to.exist;
});
it('array', () => {
const result = documentModel({ schema });
const props = result.properties;
chai_1.expect(props.comments).to.exist;
chai_1.expect(props.comments.type).to.equal('array');
chai_1.expect(props.comments.items).to.exist;
chai_1.expect(Array.isArray(props.comments.items)).to.equal(false);
chai_1.expect(props.comments.items.properties).to.exist;
chai_1.expect(props.comments.items.properties.body).to.exist;
chai_1.expect(props.comments.items.properties.date).to.exist;
chai_1.expect(props.comments.items.properties.body).to.deep.equal({ type: 'string' });
chai_1.expect(result.required).to.deep.equal(['hidden']);
});
});
describe('configurable meta fields', () => {
it('should be able to add a an arbitrary field to a property on the root object', () => {
const description = 'something cool';
const bar = 'baz';
const result = documentModel({
schema: new mongoose_1.Schema({
foo: {
type: String,
description,
bar,
},
}),
}, {
props: ['bar'],
});
const field = result.properties.foo;
chai_1.expect(field).to.exist;
chai_1.expect(field.description).to.equal(description);
chai_1.expect(field.bar).to.equal(bar);
});
it('should be able to add a an arbitrary field to a property on a nested object', () => {
const description = 'something cool';
const bar = 'baz';
const result = documentModel({
schema: new mongoose_1.Schema({
foo: {
buzz: {
type: [{
barry: {
type: String,
description,
},
}],
description,
bar,
},
},
}),
}, {
props: ['bar'],
});
const field = result.properties.foo.properties.buzz;
chai_1.expect(field).to.exist;
chai_1.expect(field.description).to.equal(description);
chai_1.expect(field.bar).to.equal(bar);
chai_1.expect(field.items.properties.barry.description).to.equal(description);
});
it('id should be excluded by default', () => {
const schema = new mongoose_1.Schema({});
const result = documentModel({
schema,
});
chai_1.expect(result.properties).to.not.have.keys('id');
chai_1.expect(result.properties).to.have.keys('_id');
});
});
describe('required array', () => {
it('root props without required fields shold omit required array (for space?)', () => {
const result = documentModel({
schema: new mongoose_1.Schema({
foo: {
type: String,
enum: ['bar', 'baz'],
},
}),
});
chai_1.expect(result.required).to.not.exist;
});
it('root with required fields should have the required array', () => {
const result = documentModel({
schema: new mongoose_1.Schema({
foo: {
type: String,
enum: ['bar', 'baz'],
required: true,
},
}),
});
chai_1.expect(result.required).to.not.be.empty;
chai_1.expect(result.required).to.include('foo');
});
it('nested', () => {
const Paw = new mongoose_1.Schema({
numToes: {
type: Number,
required: true,
},
});
const schema = new mongoose_1.Schema({
name: {
type: String,
required: true,
},
color: {
type: String,
required: true,
},
hasTail: {
type: Boolean,
},
paws: {
type: [Paw],
required: true,
},
});
const result = documentModel({ schema });
chai_1.expect(result.required).to.not.be.empty;
chai_1.expect(result.required).to.not.contain(null);
chai_1.expect(result.properties.paws.items.required).to.not.be.empty;
chai_1.expect(result.properties.paws.items.required).to.not.contain(null);
const [f] = result.properties.paws.items.required;
chai_1.expect(f).to.exist;
});
it('nested - alt format', () => {
const Paw = new mongoose_1.Schema({
numToes: {
type: Number,
required: true,
},
});
const schema = new mongoose_1.Schema({
name: {
type: String,
required: true,
},
color: {
type: String,
required: true,
},
hasTail: {
type: Boolean,
},
paws: [Paw],
});
const result = documentModel({ schema });
chai_1.expect(result.required).to.not.be.empty;
chai_1.expect(result.required).to.not.contain(null);
chai_1.expect(result.properties.paws.items.required).to.not.be.empty;
chai_1.expect(result.properties.paws.items.required).to.not.contain(null);
const [f] = result.properties.paws.items.required;
chai_1.expect(f).to.exist;
});
it('other various types', () => {
const schema = new mongoose_1.default.Schema({
a: { type: mongoose_1.default.Schema.Types.ObjectId, ref: 'AdminUser' },
b: { type: Number, default: 0 },
c: String,
d: { type: mongoose_1.default.Schema.Types.ObjectId },
e: String,
f: Object,
g: { type: mongoose_1.default.Schema.Types.Mixed },
h: Boolean,
i: [Object],
j: {
type: Object,
},
k: {
type: [Object],
},
});
const result = documentModel({ modelName: 'Cat', schema });
});
});
it('should be able to remove custom fields', () => {
const result = documentModel({
schema: new mongoose_1.Schema({
name: String,
surname: String,
nickname: String,
}),
}, {
omitFields: ['_id', 'surname'],
});
const root = result.properties;
chai_1.expect(root).to.exist;
chai_1.expect(root._id).to.not.exist;
chai_1.expect(root.surname).to.not.exist;
chai_1.expect(root.__v).to.not.exist;
chai_1.expect(root.name).to.exist;
chai_1.expect(root.nickname).to.exist;
});
it('should be able to remove __v field and leave other fields by default', () => {
const result = documentModel({
schema: new mongoose_1.Schema({
name: String,
surname: String,
nickname: String,
}),
});
const root = result.properties;
chai_1.expect(root).to.exist;
chai_1.expect(root._id).to.exist;
chai_1.expect(root.name).to.exist;
chai_1.expect(root.nickname).to.exist;
chai_1.expect(root.surname).to.exist;
chai_1.expect(root.__v).to.not.exist;
});
});
//# sourceMappingURL=index.test.js.map