Tidy up model building from data sources

See https://github.com/strongloop/loopback/issues/560
This commit is contained in:
Raymond Feng 2014-09-12 14:25:35 -07:00
parent 3655107334
commit fe74c8019c
5 changed files with 125 additions and 51 deletions

View File

@ -1427,6 +1427,7 @@ DataSource.prototype.discoverSchemasSync = function (modelName, options) {
*/
DataSource.prototype.discoverAndBuildModels = function (modelName, options, cb) {
var self = this;
options = options || {};
this.discoverSchemas(modelName, options, function (err, schemas) {
if (err) {
cb && cb(err, schemas);
@ -1436,14 +1437,16 @@ DataSource.prototype.discoverAndBuildModels = function (modelName, options, cb)
var schemaList = [];
for (var s in schemas) {
var schema = schemas[s];
if (options.base) {
schema.options = schema.options || {};
schema.options.base = options.base;
}
schemaList.push(schema);
}
var models = self.modelBuilder.buildModels(schemaList);
// Now attach the models to the data source
for (var m in models) {
models[m].attachTo(self);
}
var models = self.modelBuilder.buildModels(schemaList,
self.createModel.bind(self));
cb && cb(err, models);
});
};
@ -1462,18 +1465,41 @@ DataSource.prototype.discoverAndBuildModels = function (modelName, options, cb)
* @param {Object} [options] The options
*/
DataSource.prototype.discoverAndBuildModelsSync = function (modelName, options) {
options = options || {};
var schemas = this.discoverSchemasSync(modelName, options);
var schemaList = [];
for (var s in schemas) {
var schema = schemas[s];
if (options.base) {
schema.options = schema.options || {};
schema.options.base = options.base;
}
schemaList.push(schema);
}
var models = this.modelBuilder.buildModels(schemaList);
var models = this.modelBuilder.buildModels(schemaList,
this.createModel.bind(this));
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
* This method applies only to SQL connectors.

View File

@ -24,12 +24,13 @@ module.exports = function getIntrospector(ModelBuilder) {
return 'date';
}
var itemType;
if (Array.isArray(value)) {
for (var i = 0; i < value.length; i++) {
if (value[i] === null || value[i] === undefined) {
continue;
}
var itemType = introspectType(value[i]);
itemType = introspectType(value[i]);
if (itemType) {
return [itemType];
}
@ -43,7 +44,7 @@ module.exports = function getIntrospector(ModelBuilder) {
var properties = {};
for (var p in value) {
var itemType = introspectType(value[p]);
itemType = introspectType(value[p]);
if (itemType) {
properties[p] = itemType;
}
@ -54,6 +55,7 @@ module.exports = function getIntrospector(ModelBuilder) {
return properties;
}
ModelBuilder.introspect = introspectType;
return introspectType;
}

View File

@ -632,7 +632,7 @@ ModelBuilder.prototype.resolveType = function (type) {
* @param {*} schemas The schemas
* @returns {Object} A map of model constructors keyed by model name
*/
ModelBuilder.prototype.buildModels = function (schemas) {
ModelBuilder.prototype.buildModels = function (schemas, createModel) {
var models = {};
// 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) {
var name = this.getSchemaName(schemas[s].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;
relations = relations.concat(model.definition.relations);
}

View File

@ -1,8 +1,29 @@
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 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 () {
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) {
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 schema = introspectType(json);
@ -97,5 +97,33 @@ describe('Introspection of model definitions from JSON', function () {
assert.deepEqual(obj, copy);
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();
});
});

View File

@ -1418,28 +1418,31 @@ describe('DataAccessObject', function () {
});
describe('Load models from json', function () {
it('should be able to define models from json', function () {
var path = require('path'),
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);
var path = require('path'),
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) {
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'));
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 () {
var modelBuilder = new ModelBuilder();