Merge pull request #301 from strongloop/feature/allow-base-for-discovery
Tidy up model building from data sources
This commit is contained in:
commit
43e0f0f6fa
|
@ -1427,6 +1427,7 @@ DataSource.prototype.discoverSchemasSync = function (modelName, options) {
|
||||||
*/
|
*/
|
||||||
DataSource.prototype.discoverAndBuildModels = function (modelName, options, cb) {
|
DataSource.prototype.discoverAndBuildModels = function (modelName, options, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
options = options || {};
|
||||||
this.discoverSchemas(modelName, options, function (err, schemas) {
|
this.discoverSchemas(modelName, options, function (err, schemas) {
|
||||||
if (err) {
|
if (err) {
|
||||||
cb && cb(err, schemas);
|
cb && cb(err, schemas);
|
||||||
|
@ -1436,14 +1437,16 @@ DataSource.prototype.discoverAndBuildModels = function (modelName, options, cb)
|
||||||
var schemaList = [];
|
var schemaList = [];
|
||||||
for (var s in schemas) {
|
for (var s in schemas) {
|
||||||
var schema = schemas[s];
|
var schema = schemas[s];
|
||||||
|
if (options.base) {
|
||||||
|
schema.options = schema.options || {};
|
||||||
|
schema.options.base = options.base;
|
||||||
|
}
|
||||||
schemaList.push(schema);
|
schemaList.push(schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
var models = self.modelBuilder.buildModels(schemaList);
|
var models = self.modelBuilder.buildModels(schemaList,
|
||||||
// Now attach the models to the data source
|
self.createModel.bind(self));
|
||||||
for (var m in models) {
|
|
||||||
models[m].attachTo(self);
|
|
||||||
}
|
|
||||||
cb && cb(err, models);
|
cb && cb(err, models);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -1462,18 +1465,41 @@ DataSource.prototype.discoverAndBuildModels = function (modelName, options, cb)
|
||||||
* @param {Object} [options] The options
|
* @param {Object} [options] The options
|
||||||
*/
|
*/
|
||||||
DataSource.prototype.discoverAndBuildModelsSync = function (modelName, options) {
|
DataSource.prototype.discoverAndBuildModelsSync = function (modelName, options) {
|
||||||
|
options = options || {};
|
||||||
var schemas = this.discoverSchemasSync(modelName, options);
|
var schemas = this.discoverSchemasSync(modelName, options);
|
||||||
|
|
||||||
var schemaList = [];
|
var schemaList = [];
|
||||||
for (var s in schemas) {
|
for (var s in schemas) {
|
||||||
var schema = schemas[s];
|
var schema = schemas[s];
|
||||||
|
if (options.base) {
|
||||||
|
schema.options = schema.options || {};
|
||||||
|
schema.options.base = options.base;
|
||||||
|
}
|
||||||
schemaList.push(schema);
|
schemaList.push(schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
var models = this.modelBuilder.buildModels(schemaList);
|
var models = this.modelBuilder.buildModels(schemaList,
|
||||||
|
this.createModel.bind(this));
|
||||||
|
|
||||||
return models;
|
return models;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Introspect a JSON object and build a model class
|
||||||
|
* @param {String} name Name of the model
|
||||||
|
* @param {Object} json The json object representing a model instance
|
||||||
|
* @param {Object} options Options
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
DataSource.prototype.buildModelFromInstance = function (name, json, options) {
|
||||||
|
|
||||||
|
// Introspect the JSON document to generate a schema
|
||||||
|
var schema = ModelBuilder.introspect(json);
|
||||||
|
|
||||||
|
// Create a model for the generated schema
|
||||||
|
return this.createModel(name, schema, options);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether migrations needed
|
* Check whether migrations needed
|
||||||
* This method applies only to SQL connectors.
|
* This method applies only to SQL connectors.
|
||||||
|
|
|
@ -24,12 +24,13 @@ module.exports = function getIntrospector(ModelBuilder) {
|
||||||
return 'date';
|
return 'date';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var itemType;
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
for (var i = 0; i < value.length; i++) {
|
for (var i = 0; i < value.length; i++) {
|
||||||
if (value[i] === null || value[i] === undefined) {
|
if (value[i] === null || value[i] === undefined) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
var itemType = introspectType(value[i]);
|
itemType = introspectType(value[i]);
|
||||||
if (itemType) {
|
if (itemType) {
|
||||||
return [itemType];
|
return [itemType];
|
||||||
}
|
}
|
||||||
|
@ -43,7 +44,7 @@ module.exports = function getIntrospector(ModelBuilder) {
|
||||||
|
|
||||||
var properties = {};
|
var properties = {};
|
||||||
for (var p in value) {
|
for (var p in value) {
|
||||||
var itemType = introspectType(value[p]);
|
itemType = introspectType(value[p]);
|
||||||
if (itemType) {
|
if (itemType) {
|
||||||
properties[p] = itemType;
|
properties[p] = itemType;
|
||||||
}
|
}
|
||||||
|
@ -54,6 +55,7 @@ module.exports = function getIntrospector(ModelBuilder) {
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ModelBuilder.introspect = introspectType;
|
||||||
return introspectType;
|
return introspectType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -632,7 +632,7 @@ ModelBuilder.prototype.resolveType = function (type) {
|
||||||
* @param {*} schemas The schemas
|
* @param {*} schemas The schemas
|
||||||
* @returns {Object} A map of model constructors keyed by model name
|
* @returns {Object} A map of model constructors keyed by model name
|
||||||
*/
|
*/
|
||||||
ModelBuilder.prototype.buildModels = function (schemas) {
|
ModelBuilder.prototype.buildModels = function (schemas, createModel) {
|
||||||
var models = {};
|
var models = {};
|
||||||
|
|
||||||
// Normalize the schemas to be an array of the schema objects {name: <name>, properties: {}, options: {}}
|
// Normalize the schemas to be an array of the schema objects {name: <name>, properties: {}, options: {}}
|
||||||
|
@ -656,7 +656,12 @@ ModelBuilder.prototype.buildModels = function (schemas) {
|
||||||
for (var s in schemas) {
|
for (var s in schemas) {
|
||||||
var name = this.getSchemaName(schemas[s].name);
|
var name = this.getSchemaName(schemas[s].name);
|
||||||
schemas[s].name = name;
|
schemas[s].name = name;
|
||||||
var model = this.define(schemas[s].name, schemas[s].properties, schemas[s].options);
|
var model;
|
||||||
|
if(typeof createModel === 'function') {
|
||||||
|
model = createModel(schemas[s].name, schemas[s].properties, schemas[s].options);
|
||||||
|
} else {
|
||||||
|
model = this.define(schemas[s].name, schemas[s].properties, schemas[s].options);
|
||||||
|
}
|
||||||
models[name] = model;
|
models[name] = model;
|
||||||
relations = relations.concat(model.definition.relations);
|
relations = relations.concat(model.definition.relations);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,29 @@
|
||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var ModelBuilder = require('../lib/model-builder').ModelBuilder;
|
var ModelBuilder = require('..').ModelBuilder;
|
||||||
|
var DataSource = require('../').DataSource;
|
||||||
var introspectType = require('../lib/introspection')(ModelBuilder);
|
var introspectType = require('../lib/introspection')(ModelBuilder);
|
||||||
var traverse = require('traverse');
|
var traverse = require('traverse');
|
||||||
|
|
||||||
|
var json = {
|
||||||
|
name: 'Joe',
|
||||||
|
age: 30,
|
||||||
|
birthday: new Date(),
|
||||||
|
vip: true,
|
||||||
|
address: {
|
||||||
|
street: '1 Main St',
|
||||||
|
city: 'San Jose',
|
||||||
|
state: 'CA',
|
||||||
|
zipcode: '95131',
|
||||||
|
country: 'US'
|
||||||
|
},
|
||||||
|
friends: ['John', 'Mary'],
|
||||||
|
emails: [
|
||||||
|
{label: 'work', id: 'x@sample.com'},
|
||||||
|
{label: 'home', id: 'x@home.com'}
|
||||||
|
],
|
||||||
|
tags: []
|
||||||
|
};
|
||||||
|
|
||||||
describe('Introspection of model definitions from JSON', function () {
|
describe('Introspection of model definitions from JSON', function () {
|
||||||
|
|
||||||
it('should handle simple types', function () {
|
it('should handle simple types', function () {
|
||||||
|
@ -61,27 +82,6 @@ describe('Introspection of model definitions from JSON', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should build a model from the introspected schema', function (done) {
|
it('should build a model from the introspected schema', function (done) {
|
||||||
|
|
||||||
var json = {
|
|
||||||
name: 'Joe',
|
|
||||||
age: 30,
|
|
||||||
birthday: new Date(),
|
|
||||||
vip: true,
|
|
||||||
address: {
|
|
||||||
street: '1 Main St',
|
|
||||||
city: 'San Jose',
|
|
||||||
state: 'CA',
|
|
||||||
zipcode: '95131',
|
|
||||||
country: 'US'
|
|
||||||
},
|
|
||||||
friends: ['John', 'Mary'],
|
|
||||||
emails: [
|
|
||||||
{label: 'work', id: 'x@sample.com'},
|
|
||||||
{label: 'home', id: 'x@home.com'}
|
|
||||||
],
|
|
||||||
tags: []
|
|
||||||
};
|
|
||||||
|
|
||||||
var copy = traverse(json).clone();
|
var copy = traverse(json).clone();
|
||||||
|
|
||||||
var schema = introspectType(json);
|
var schema = introspectType(json);
|
||||||
|
@ -97,5 +97,33 @@ describe('Introspection of model definitions from JSON', function () {
|
||||||
assert.deepEqual(obj, copy);
|
assert.deepEqual(obj, copy);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should build a model using buildModelFromInstance', function (done) {
|
||||||
|
var copy = traverse(json).clone();
|
||||||
|
|
||||||
|
var builder = new ModelBuilder();
|
||||||
|
var Model = builder.buildModelFromInstance('MyModel', copy, {idInjection: false});
|
||||||
|
|
||||||
|
var obj = new Model(json);
|
||||||
|
obj = obj.toObject();
|
||||||
|
assert.deepEqual(obj, copy);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should build a model using DataSource.buildModelFromInstance', function (done) {
|
||||||
|
var copy = traverse(json).clone();
|
||||||
|
|
||||||
|
var builder = new DataSource('memory');
|
||||||
|
var Model = builder.buildModelFromInstance('MyModel', copy,
|
||||||
|
{idInjection: false});
|
||||||
|
|
||||||
|
assert.equal(Model.dataSource, builder);
|
||||||
|
|
||||||
|
var obj = new Model(json);
|
||||||
|
obj = obj.toObject();
|
||||||
|
assert.deepEqual(obj, copy);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1418,28 +1418,31 @@ describe('DataAccessObject', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Load models from json', function () {
|
describe('Load models from json', function () {
|
||||||
it('should be able to define models from json', function () {
|
var path = require('path'),
|
||||||
var path = require('path'),
|
fs = require('fs');
|
||||||
fs = require('fs');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load LDL schemas from a json doc
|
|
||||||
* @param schemaFile The dataSource json file
|
|
||||||
* @returns A map of schemas keyed by name
|
|
||||||
*/
|
|
||||||
function loadSchemasSync(schemaFile, dataSource) {
|
|
||||||
// Set up the data source
|
|
||||||
if (!dataSource) {
|
|
||||||
dataSource = new DataSource('memory');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the dataSource JSON file
|
|
||||||
var schemas = JSON.parse(fs.readFileSync(schemaFile));
|
|
||||||
|
|
||||||
return dataSource.modelBuilder.buildModels(schemas);
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load LDL schemas from a json doc
|
||||||
|
* @param schemaFile The dataSource json file
|
||||||
|
* @returns A map of schemas keyed by name
|
||||||
|
*/
|
||||||
|
function loadSchemasSync(schemaFile, dataSource) {
|
||||||
|
var modelBuilder, createModel;
|
||||||
|
// Set up the data source
|
||||||
|
if (!dataSource) {
|
||||||
|
modelBuilder = new ModelBuilder();
|
||||||
|
} else {
|
||||||
|
modelBuilder = dataSource.modelBuilder;
|
||||||
|
createModel = dataSource.createModel.bind(dataSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read the dataSource JSON file
|
||||||
|
var schemas = JSON.parse(fs.readFileSync(schemaFile));
|
||||||
|
return modelBuilder.buildModels(schemas, createModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
it('should be able to define models from json', function () {
|
||||||
|
|
||||||
var models = loadSchemasSync(path.join(__dirname, 'test1-schemas.json'));
|
var models = loadSchemasSync(path.join(__dirname, 'test1-schemas.json'));
|
||||||
|
|
||||||
models.should.have.property('AnonymousModel_0');
|
models.should.have.property('AnonymousModel_0');
|
||||||
|
@ -1459,6 +1462,16 @@ describe('Load models from json', function () {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should be able to define models from json using dataSource', function() {
|
||||||
|
var ds = new DataSource('memory');
|
||||||
|
|
||||||
|
var models = loadSchemasSync(path.join(__dirname, 'test2-schemas.json'), ds);
|
||||||
|
models.should.have.property('Address');
|
||||||
|
models.should.have.property('Account');
|
||||||
|
models.should.have.property('Customer');
|
||||||
|
assert.equal(models.Address.dataSource, ds);
|
||||||
|
});
|
||||||
|
|
||||||
it('should allow customization of default model base class', function () {
|
it('should allow customization of default model base class', function () {
|
||||||
var modelBuilder = new ModelBuilder();
|
var modelBuilder = new ModelBuilder();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue