Merge pull request #69 from strongloop/datasource-auto-wiring

Initial auto wiring for model dataSources
This commit is contained in:
Ritchie Martori 2013-11-19 13:11:54 -08:00
commit e5a55846e8
10 changed files with 111 additions and 66 deletions

View File

@ -221,6 +221,9 @@ app.boot = function(options) {
app.model(key, obj);
});
// attach models to dataSources by type
loopback.autoAttach();
// require directories
var requiredModels = requireDir(path.join(appRootDir, 'models'));
}

View File

@ -96,6 +96,11 @@ loopback.createDataSource = function (name, options) {
ModelCtor.attachTo(ds);
return ModelCtor;
};
if(options && options.defaultForType) {
loopback.setDefaultDataSourceForType(options.defaultForType, ds);
}
return ds;
};
@ -108,7 +113,12 @@ loopback.createDataSource = function (name, options) {
*/
loopback.createModel = function (name, properties, options) {
return loopback.Model.extend(name, properties, options);
var model = loopback.Model.extend(name, properties, options);
// try to attach
loopback.autoAttachModel(model);
return model;
}
/**
@ -173,6 +183,58 @@ loopback.getModel = function(modelName) {
return loopback.Model.modelBuilder.models[modelName];
};
/**
* Set the default `dataSource` for a given `type`.
*/
loopback.setDefaultDataSourceForType = function(type, dataSource) {
var defaultDataSources = this.defaultDataSources || (this.defaultDataSources = {});
if(!(dataSource instanceof DataSource)) {
dataSource = this.createDataSource(dataSource);
}
defaultDataSources[type] = dataSource;
return dataSource;
}
/**
* Get the default `dataSource` for a given `type`.
*/
loopback.getDefaultDataSourceForType = function(type) {
return this.defaultDataSources && this.defaultDataSources[type];
}
/**
* Attach any model that does not have a dataSource to
* the default dataSource for the type the Model requests
*/
loopback.autoAttach = function() {
var models = this.Model.modelBuilder.models;
assert.equal(typeof models, 'object', 'Cannot autoAttach without a models object');
Object.keys(models).forEach(function(modelName) {
var ModelCtor = models[modelName];
if(ModelCtor) {
loopback.autoAttachModel(ModelCtor);
}
});
}
loopback.autoAttachModel = function(ModelCtor) {
if(ModelCtor.autoAttach) {
var ds = loopback.getDefaultDataSourceForType(ModelCtor.autoAttach);
assert(ds instanceof DataSource, 'cannot autoAttach model "' + ModelCtor.modelName
+ '". No dataSource found of type ' + ModelCtor.attachTo);
ModelCtor.attachTo(ds);
}
}
/*
* Built in models / services
*/
@ -182,3 +244,26 @@ loopback.Email = require('./models/email');
loopback.User = require('./models/user');
loopback.Application = require('./models/application');
loopback.AccessToken = require('./models/access-token');
loopback.Role = require('./models/role').Role;
loopback.RoleMapping = require('./models/role').RoleMapping;
loopback.ACL = require('./models/acl').ACL;
loopback.Scope = require('./models/acl').Scope;
/**
* Automatically attach these models to dataSources
*/
var dataSourceTypes = {
DB: 'db',
MAIL: 'mail'
};
loopback.Email.autoAttach = dataSourceTypes.MAIL;
loopback.User.autoAttach = dataSourceTypes.DB;
loopback.AccessToken.autoAttach = dataSourceTypes.DB;
loopback.Role.autoAttach = dataSourceTypes.DB;
loopback.RoleMapping.autoAttach = dataSourceTypes.DB;
loopback.ACL.autoAttach = dataSourceTypes.DB;
loopback.Scope.autoAttach = dataSourceTypes.DB;
loopback.Application.autoAttach = dataSourceTypes.DB;

View File

@ -1,7 +1,7 @@
/**
* Module Dependencies.
*/
var loopback = require('../loopback');
var ModelBuilder = require('loopback-datasource-juggler').ModelBuilder;
var modeler = new ModelBuilder();

View File

@ -1,9 +1,6 @@
var loopback = require('../');
var Token = loopback.AccessToken.extend('MyToken');
// attach Token to testing memory ds
Token.attachTo(loopback.memory());
describe('loopback.token(options)', function() {
beforeEach(createTestingToken);

View File

@ -14,18 +14,10 @@ function checkResult(err, result) {
describe('security scopes', function () {
it("should allow access to models for the given scope by wildcard", function () {
var ds = loopback.createDataSource({connector: loopback.Memory});
Scope.attachTo(ds);
ACL.attachTo(ds);
// console.log(Scope.relations);
Scope.create({name: 'userScope', description: 'access user information'}, function (err, scope) {
// console.log(scope);
ACL.create({principalType: ACL.SCOPE, principalId: scope.id, model: 'User', property: ACL.ALL,
accessType: ACL.ALL, permission: ACL.ALLOW},
function (err, resource) {
// console.log(resource);
Scope.checkPermission('userScope', 'User', ACL.ALL, ACL.ALL, checkResult);
Scope.checkPermission('userScope', 'User', 'name', ACL.ALL, checkResult);
Scope.checkPermission('userScope', 'User', 'name', ACL.READ, checkResult);
@ -36,13 +28,7 @@ describe('security scopes', function () {
it("should allow access to models for the given scope", function () {
var ds = loopback.createDataSource({connector: loopback.Memory});
Scope.attachTo(ds);
ACL.attachTo(ds);
// console.log(Scope.relations);
Scope.create({name: 'userScope', description: 'access user information'}, function (err, scope) {
// console.log(scope);
ACL.create({principalType: ACL.SCOPE, principalId: scope.id,
model: 'User', property: 'name', accessType: ACL.READ, permission: ACL.ALLOW},
function (err, resource) {
@ -74,7 +60,6 @@ describe('security ACLs', function () {
it("should allow access to models for the given principal by wildcard", function () {
var ds = loopback.createDataSource({connector: loopback.Memory});
ACL.attachTo(ds);
ACL.create({principalType: ACL.USER, principalId: 'u001', model: 'User', property: ACL.ALL,
accessType: ACL.ALL, permission: ACL.ALLOW}, function (err, acl) {
@ -117,7 +102,6 @@ describe('security ACLs', function () {
{principalType: ACL.USER, principalId: 'u001', accessType: ACL.ALL, permission: ACL.ALLOW}
];
*/
ACL.attachTo(ds);
ACL.checkPermission(ACL.USER, 'u001', 'Customer', 'name', ACL.WRITE, function (err, perm) {
assert(perm.permission === ACL.DENY);

View File

@ -1,17 +1,8 @@
var loopback = require('../');
var MailConnector = loopback.Mail;
var MyEmail = loopback.Email.extend('my-email');
var assert = require('assert');
describe('Email and SMTP', function () {
var mail = loopback.createDataSource({
connector: MailConnector,
transports: [
{type: 'STUB'}
]
});
MyEmail.attachTo(mail);
it('should have a send method', function () {
assert(typeof MyEmail.send === 'function');

View File

@ -1,16 +1,11 @@
var loopback = require(('../'));
var assert = require('assert');
var dataSource = loopback.createDataSource('db', {connector: loopback.Memory});
var Application = loopback.Application;
Application.attachTo(dataSource);
describe('Application', function () {
var registeredApp = null;
it('Create a new application', function (done) {
Application.create({owner: 'rfeng', name: 'MyApp1', description: 'My first mobile application'}, function (err, result) {
var app = result;
assert.equal(app.owner, 'rfeng');
@ -27,8 +22,7 @@ describe('Application', function () {
});
});
it('Register a new application', function (done) {
beforeEach(function (done) {
Application.register('rfeng', 'MyApp2', {description: 'My second mobile application'}, function (err, result) {
var app = result;
assert.equal(app.owner, 'rfeng');
@ -47,7 +41,6 @@ describe('Application', function () {
});
it('Reset keys', function (done) {
Application.resetKeys(registeredApp.id, function (err, result) {
var app = result;
assert.equal(app.owner, 'rfeng');
@ -73,7 +66,6 @@ describe('Application', function () {
});
it('Authenticate with application id & clientKey', function (done) {
Application.authenticate(registeredApp.id, registeredApp.clientKey, function (err, result) {
assert.equal(result, 'clientKey');
done(err, result);
@ -81,7 +73,6 @@ describe('Application', function () {
});
it('Authenticate with application id & javaScriptKey', function (done) {
Application.authenticate(registeredApp.id, registeredApp.javaScriptKey, function (err, result) {
assert.equal(result, 'javaScriptKey');
done(err, result);
@ -116,6 +107,5 @@ describe('Application', function () {
done(err, result);
});
});
});

View File

@ -13,10 +13,6 @@ function checkResult(err, result) {
describe('role model', function () {
it("should define role/role relations", function () {
var ds = loopback.createDataSource({connector: 'memory'});
Role.attachTo(ds);
RoleMapping.attachTo(ds);
Role.create({name: 'user'}, function (err, userRole) {
Role.create({name: 'admin'}, function (err, adminRole) {
userRole.principals.create({principalType: RoleMapping.ROLE, principalId: adminRole.id}, function (err, mapping) {
@ -41,11 +37,6 @@ describe('role model', function () {
});
it("should define role/user relations", function () {
var ds = loopback.createDataSource({connector: 'memory'});
User.attachTo(ds);
Role.attachTo(ds);
RoleMapping.attachTo(ds);
User.create({name: 'Raymond', email: 'x@y.com', password: 'foobar'}, function (err, user) {
// console.log('User: ', user.id);
Role.create({name: 'userRole'}, function (err, role) {
@ -75,11 +66,6 @@ describe('role model', function () {
});
it("should support getRoles() and isInRole()", function () {
var ds = loopback.createDataSource({connector: 'memory'});
User.attachTo(ds);
Role.attachTo(ds);
RoleMapping.attachTo(ds);
User.create({name: 'Raymond', email: 'x@y.com', password: 'foobar'}, function (err, user) {
// console.log('User: ', user.id);
Role.create({name: 'userRole'}, function (err, role) {

View File

@ -12,6 +12,21 @@ request = require('supertest');
beforeEach(function () {
app = loopback();
// setup default data sources
loopback.setDefaultDataSourceForType('db', {
connector: loopback.Memory
});
loopback.setDefaultDataSourceForType('mail', {
connector: loopback.Mail,
transports: [
{type: 'STUB'}
]
});
// auto attach data sources to models
loopback.autoAttach();
});
assertValidDataSource = function (dataSource) {

View File

@ -8,20 +8,14 @@ var userMemory = loopback.createDataSource({
});
describe('User', function(){
var mailDataSource = loopback.createDataSource({
connector: MailConnector,
transports: [{type: 'STUB'}]
});
User.attachTo(userMemory);
AccessToken.attachTo(userMemory);
// TODO(ritch) - this should be a default relationship
User.hasMany(AccessToken, {as: 'accessTokens', foreignKey: 'userId'});
User.email.attachTo(mailDataSource);
// allow many User.afterRemote's to be called
User.setMaxListeners(0);
before(function () {
debugger;
User.hasMany(AccessToken, {as: 'accessTokens', foreignKey: 'userId'});
});
beforeEach(function (done) {
app.use(loopback.rest());
app.model(User);