Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable polymorphism #30

Closed
wants to merge 25 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
eb7f003
Enable polymorphism by merging members of "allOf" into a single prope…
Oct 25, 2016
42cb222
export swaggerJSON
Nov 4, 2016
5327109
Fix export
Nov 4, 2016
72a8f64
Fix typo
Nov 4, 2016
8c4370a
handling $ref only members of polymorphic defintions
celalo Feb 5, 2017
f77d019
mongodb and mongoose should be peer dependencies
Feb 28, 2017
6392959
Remove mongodb dependency as unnecessary (mongoose already depends on…
Feb 28, 2017
09e6dda
async => ^2.0.0, mockgoose => ^7.0.0, remove mongoose dev dep as unne…
nakamorichi Mar 8, 2017
4e07cd4
Correct some deprecated syntax, set mongoose to use ES6 Promise in tests
nakamorichi Mar 8, 2017
b295787
Add definitions containing "allOf' syntax, and a basic test case
nakamorichi Mar 8, 2017
4d6af3c
Merge branch 'complex-defs' into process-allof
nakamorichi Mar 8, 2017
967b183
Upgrade Node version in Travis to the most recent LTS (i.e. 6)
nakamorichi Mar 8, 2017
f3e27da
Merge branch 'complex-defs' of github.com:Kitanotori/swagger-mongoose…
nakamorichi Mar 8, 2017
4f5116a
Increase mocha's timeout limit to 10s
nakamorichi Mar 8, 2017
2e313e4
Merge branch 'complex-defs' of github.com:Kitanotori/swagger-mongoose…
nakamorichi Mar 8, 2017
b4a5b63
mongodb and mongoose should be peer dependencies
Feb 28, 2017
e43252f
Remove mongodb dependency as unnecessary (mongoose already depends on…
Feb 28, 2017
92d681a
Update deps
nakamorichi Mar 8, 2017
32363c2
Correct some deprecated syntax, set mongoose to use ES6 Promise in tests
nakamorichi Mar 8, 2017
8107bd8
Upgrade Node version in Travis to the most recent LTS (i.e. 6)
nakamorichi Mar 8, 2017
2b911bb
‘date’ and ‘double’ are not valid types
Mar 9, 2017
fc3e873
Fix type handling:
Mar 9, 2017
92cd927
Increase Mocha’s timeout limit because of Mocha’s slow initialization
Mar 9, 2017
fa838b6
Merge branch 'update-deps-and-travis' into process-allof
Mar 9, 2017
462f34d
Fix type handling: all ‘integer’s and ‘number’s as Number, all ‘strin…
Mar 10, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
language: node_js
node_js:
- "0.11"
- "6"
98 changes: 69 additions & 29 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var path = require('path');

var allowedTypes = ['number','integer', 'long', 'float', 'double', 'string', 'password', 'boolean', 'date', 'dateTime', 'array'];
// Allowed property types defined in OpenAPI specifications
// https://github.com/OAI/OpenAPI-Specification/tree/master/versions
var allowedTypes = ['integer', 'number', 'string', 'boolean', 'array', 'object'];
var definitions = null;
var swaggerVersion = null;
var v2MongooseProperty = 'x-swagger-mongoose';
Expand All @@ -16,41 +18,34 @@ var xSwaggerMongoose = {
documentIndex: {},
};
var validators = {};
var swaggerJSON = {};

var propertyMap = function (property) {
if (!property) {
throw new Error('Tried to process undefined property');
}

switch (property.type) {
case 'integer':
case 'number':
return Number
case 'string':
switch (property.format) {
case 'integer':
case 'long':
case 'float':
case 'double':
return Number;
case 'date':
case 'date-time':
return Date;
default:
throw new Error('Unrecognised schema format: ' + property.format);
return String;
}
case 'integer':
case 'long' :
case 'float' :
case 'double' :
return Number;
case 'string':
case 'password':
return String;
case 'boolean':
return Boolean;
case 'date':
case 'dateTime':
return Date;
case 'array':
return [propertyMap(property.items)];
default:
throw new Error('Unrecognized schema type: ' + property.type);
}
throw new Error('Unrecognised schema format: ' + property.format);
};

var convertToJSON = function (spec) {
var swaggerJSON = {};
var type = typeof(spec);
switch (type) {
case 'object':
Expand Down Expand Up @@ -208,11 +203,53 @@ var processRef = function (property, objectName, props, key, required) {
fillRequired(props, key, required);
};

var isPolymorphic = function (def) {
return def['allOf'];
}

/*
* Merges members of 'allOf' into a single 'properties' object,
* and a single 'required' array, and assigns these to the parent definition.
*
* NOTE: needs more thorough testing!
*/
var processPolymorphic = function (definition) {
var mergedProps = {};
var mergedReqs = new Set();
definition['allOf'].forEach(function(polyDef) {
if(polyDef['$ref']) {
var refRegExp = /^#\/definitions\/(\w*)$/;
var refString = polyDef['$ref'];
var propType = refString.match(refRegExp)[1];
var object = definitions[propType];
Object.assign(mergedProps, object['properties']);
if (object['required']) {
object['required'].forEach(function(req) {
mergedReqs.add(req);
});
}
}else {
Object.assign(mergedProps, polyDef['properties']);
if (polyDef['required']) {
polyDef['required'].forEach(function(req) {
mergedReqs.add(req);
});
}
}
});
if (!_.isEmpty(mergedProps)) definition['properties'] = mergedProps;
if (!_.isEmpty(mergedReqs)) definition['required'] = Array.from(mergedReqs);
delete definition['allOf'];
}

var getSchema = function (objectName, fullObject) {
var props = {};
var required = fullObject.required || [];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line 247 (var required = fullObject.required || [];) should be moved to line 251 (i.e. after processPolymorphic runs if the definition is polymorphic) otherwise we're not adding in the merged required fields.

var object = fullObject['properties'] ? fullObject['properties'] : fullObject;
if (isPolymorphic(fullObject)) {
processPolymorphic(fullObject);
}

var object = fullObject['properties'] ? fullObject['properties'] : fullObject;
_.forEach(object, function (property, key) {
var schemaProperty = getSchemaProperty(property, key, required, objectName, object);
props = _.extend(props, schemaProperty);
Expand All @@ -236,17 +273,19 @@ var getSchemaProperty = function(property, key, required, objectName, object) {
else if (isPropertyHasRef(property)) {
processRef(property, objectName, props, key, required);
}
else if (isPolymorphic(property)) {
processPolymorphic(property);
}
else if (!property.type || property.type === 'object') {
props[key] = getSchema(key, property);
}
else if (property.type !== 'object') {
var type = propertyMap(property);
if (property.enum && _.isArray(property.enum)) {
props[key] = {type: type, enum: property.enum};
} else {
props[key] = {type: type};
}

}
else if (property.type === 'object') {
props[key] = getSchema(key, property);
}
else if (isSimpleSchema(object)) {
props = {type: propertyMap(object)};
Expand Down Expand Up @@ -275,6 +314,9 @@ var processDocumentIndex = function(schema, index){

};

module.exports.getSwaggerJSON = function () {
return swaggerJSON;
};

module.exports.compileAsync = function (spec, callback) {
try {
Expand All @@ -286,13 +328,11 @@ module.exports.compileAsync = function (spec, callback) {

module.exports.compile = function (spec, _extraDefinitions) {
if (!spec) throw new Error('Swagger spec not supplied');
var swaggerJSON = convertToJSON(spec);
swaggerJSON = convertToJSON(spec);
if (swaggerJSON.swagger) {
swaggerVersion = new Number(swaggerJSON.swagger);
}



definitions = swaggerJSON['definitions'];

applyExtraDefinitions(definitions, _extraDefinitions);
Expand Down
12 changes: 7 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,17 @@
"lodash": "^4.6.1"
},
"devDependencies": {
"async": "^2.0.0-rc.1",
"async": "^2.0.0",
"chai": "^3.5.0",
"mocha": "^2.4.5",
"mockgoose": "^6.0.0",
"mongodb": "^2.1.11",
"mongoose": "^4.4.9"
"mockgoose": "^7.0.0",
"mongoose": "^4.8.6"
},
"peerDependencies": {
"mongoose": "^4.8.6"
},
"scripts": {
"test": "mocha"
"test": "mocha --timeout 60000"
},
"repository": {
"type": "git",
Expand Down
62 changes: 62 additions & 0 deletions test/complex.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{
"swagger": "2.0",
"info": {
"version": "1.0.0",
"title": "Complex definitions",
"contact": {
"name": "Petri Kivikangas",
"email": "[email protected]"
},
"license": {
"name": "The MIT License (MIT)",
"url": "https://opensource.org/licenses/MIT"
}
},
"basePath": "/api",
"schemes": [
"http"
],
"x-swagger-mongoose": {
"validators": "./lib/validators",
"description": "The relative path to validators library from process.cwd()"
},
"definitions": {
"Customer": {
"description": "Customer company",
"type": "object",
"required": ["contact_information", "person_in_charge", "id"],
"properties": {
"person_in_charge": {
"type": "object",
"allOf": [
{ "$ref": "#/definitions/ContactInformation" },
{
"type": "object",
"properties": {
"skype": { "description": "Skype", "type": "string" }
}
}
]
},
"contact_information": {
"$ref": "#/definitions/ContactInformation"
},
"id": { "type": "string" },
"created_at": { "type": "string", "format": "date-time" },
"updated_at": { "type": "string", "format": "date-time" }
}
},
"ContactInformation": {
"required": ["name", "email"],
"type": "object",
"properties": {
"name": { "type": "string" },
"tel": { "type": "string" },
"mobile": { "type": "string" },
"fax": { "type": "string" },
"email": { "type": "string", "format": "email" },
"address": { "type": "string" }
}
}
}
}
32 changes: 19 additions & 13 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,35 @@ var swaggerMongoose = require('./../lib/index');
var fs = require('fs');
var async = require('async');
var mongoose = require('mongoose');
var mockgoose = require('mockgoose');
// mockgoose(mongoose);
mongoose.Promise = global.Promise; // Mongoose's default Promise is deprecated
var Mockgoose = require('mockgoose').Mockgoose;
var mockgoose = new Mockgoose(mongoose);
var assert = require('chai').assert;
var Schema = mongoose.Schema;
var _ = require('lodash');

describe('swagger-mongoose tests', function () {

before(function(done) {
mockgoose(mongoose).then(function() {
mongoose.connect('mongodb://127.0.0.1:27017/TestingDB', function(err) {
done(err);
});
});
});

mockgoose.prepareStorage().then(function() {
mongoose.connect('mongodb://127.0.0.1:27017/TestingDB', function(err) {
done(err);
});
});
});

afterEach(function (done) {

delete mongoose.models.Pet;
delete mongoose.models.Address;
delete mongoose.models.Error;
delete mongoose.models.Person;
delete mongoose.models.House;
delete mongoose.models.Car;
delete mongoose.models.Human;
mockgoose.reset(function(){
done()
mockgoose.helper.reset()
.then(function () {
done();
});

});

it('should create an example pet and return all valid properties', function (done) {
Expand Down Expand Up @@ -450,4 +449,11 @@ describe('swagger-mongoose tests', function () {
done();
});

it('should compile complex definitions', function (done) {
var swagger = fs.readFileSync('./test/complex.json');
var models = swaggerMongoose.compile(swagger.toString());

done();
});

});
6 changes: 4 additions & 2 deletions test/person.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,12 @@
"type": "string"
},
"lng": {
"type": "double"
"type": "number",
"format": "double"
},
"lat": {
"type": "double"
"type": "number",
"format": "double"
}
}
},
Expand Down
8 changes: 5 additions & 3 deletions test/petstore.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,12 @@
"type": "string"
},
"dob": {
"type": "date"
"type": "string",
"format": "date"
},
"price": {
"type": "double"
"type": "number",
"format": "double"
},
"sold": {
"type": "boolean"
Expand Down Expand Up @@ -124,4 +126,4 @@
}
}
}
}
}