Merge pull request #82 from strongloop/feature/ldl-scopes

Allows scopes to be defined in LDL
This commit is contained in:
Raymond Feng 2014-03-04 09:50:27 -08:00
commit 464d23891b
4 changed files with 92 additions and 24 deletions

View File

@ -7,11 +7,18 @@ var jutil = require('./jutil');
var utils = require('./utils');
var ModelBaseClass = require('./model.js');
var DataAccessObject = require('./dao.js');
var defineScope = require('./scope.js').defineScope;
var EventEmitter = require('events').EventEmitter;
var util = require('util');
var assert = require('assert');
var async = require('async');
if (process.env.DEBUG === 'loopback') {
// For back-compatibility
process.env.DEBUG = 'loopback:*';
}
var debug = require('debug')('loopback:datasource');
/**
* Export public API
*/
@ -238,11 +245,10 @@ DataSource.prototype.setup = function (name, settings) {
// just save everything we get
this.settings = settings || {};
// Check the debug env settings
var debugEnv = process.env.DEBUG || process.env.NODE_DEBUG || '';
var debugModules = debugEnv.split(/[\s,]+/);
if (debugModules.indexOf('loopback') !== -1) {
this.settings.debug = true;
this.settings.debug = this.settings.debug || debug.enabled;
if(this.settings.debug) {
debug('Settings: %j', this.settings);
}
// Disconnected by default
@ -346,6 +352,20 @@ DataSource.relationTypes = ['belongsTo', 'hasMany', 'hasAndBelongsToMany'];
function isModelDataSourceAttached(model) {
return model && (!model.settings.unresolved) && (model.dataSource instanceof DataSource);
}
/*!
* Define scopes for the model class from the scopes object
* @param modelClass
* @param scopes
*/
DataSource.prototype.defineScopes = function (modelClass, scopes) {
if(scopes) {
for(var s in scopes) {
defineScope(modelClass, modelClass, s, scopes[s]);
}
}
};
/*!
* Define relations for the model class from the relations object
* @param modelClass
@ -451,6 +471,9 @@ DataSource.prototype.setupDataAccess = function (modelClass, settings) {
var relations = settings.relationships || settings.relations;
this.defineRelations(modelClass, relations);
var scopes = settings.scopes || {};
this.defineScopes(modelClass, scopes);
};
/**
@ -655,7 +678,7 @@ DataSource.prototype.defineProperty = function (model, prop, params) {
this.modelBuilder.defineProperty(model, prop, params);
var resolvedProp = this.getModelDefinition(model).properties[prop];
if (this.connector.defineProperty) {
if (this.connector && this.connector.defineProperty) {
this.connector.defineProperty(model, prop, resolvedProp);
}
};
@ -722,7 +745,7 @@ DataSource.prototype.discoverModelDefinitions = function (options, cb) {
if (this.connector.discoverModelDefinitions) {
this.connector.discoverModelDefinitions(options, cb);
} else if (cb) {
cb();
process.nextTick(cb);
}
};
@ -767,7 +790,7 @@ DataSource.prototype.discoverModelProperties = function (modelName, options, cb)
if (this.connector.discoverModelProperties) {
this.connector.discoverModelProperties(modelName, options, cb);
} else if (cb) {
cb();
process.nextTick(cb);
}
};
@ -811,7 +834,7 @@ DataSource.prototype.discoverPrimaryKeys = function (modelName, options, cb) {
if (this.connector.discoverPrimaryKeys) {
this.connector.discoverPrimaryKeys(modelName, options, cb);
} else if (cb) {
cb();
process.nextTick(cb);
}
};
@ -858,7 +881,7 @@ DataSource.prototype.discoverForeignKeys = function (modelName, options, cb) {
if (this.connector.discoverForeignKeys) {
this.connector.discoverForeignKeys(modelName, options, cb);
} else if (cb) {
cb();
process.nextTick(cb);
}
};
@ -875,7 +898,7 @@ DataSource.prototype.discoverForeignKeysSync = function (modelName, options) {
return this.connector.discoverForeignKeysSync(modelName, options);
}
return null;
}
};
/**
* Retrieves a description of the foreign key columns that reference the given table's primary key columns (the foreign keys exported by a table).
@ -906,7 +929,7 @@ DataSource.prototype.discoverExportedForeignKeys = function (modelName, options,
if (this.connector.discoverExportedForeignKeys) {
this.connector.discoverExportedForeignKeys(modelName, options, cb);
} else if (cb) {
cb();
process.nextTick(cb);
}
};
@ -971,7 +994,7 @@ DataSource.prototype.discoverSchema = function (modelName, options, cb) {
return;
}
});
}
};
/**
* Discover schema from a given modelName/view
@ -1028,7 +1051,7 @@ DataSource.prototype.discoverSchemas = function (modelName, options, cb) {
});
if (self.settings.debug) {
console.log('Primary keys: ', pks);
debug('Primary keys: ', pks);
}
var schema = {
@ -1075,7 +1098,7 @@ DataSource.prototype.discoverSchemas = function (modelName, options, cb) {
var schemaKey = columns[0].owner + '.' + modelName;
if (!options.visited.hasOwnProperty(schemaKey)) {
if (self.settings.debug) {
console.log('Adding schema for ' + schemaKey);
debug('Adding schema for ' + schemaKey);
}
options.visited[schemaKey] = schema;
}
@ -1100,7 +1123,7 @@ DataSource.prototype.discoverSchemas = function (modelName, options, cb) {
});
if (self.settings.debug) {
console.log('Foreign keys: ', fks);
debug('Foreign keys: ', fks);
}
schema.options.relations = {};
@ -1125,7 +1148,7 @@ DataSource.prototype.discoverSchemas = function (modelName, options, cb) {
var moreTasks = [];
for (var t in otherTables) {
if (self.settings.debug) {
console.log('Discovering related schema for ' + schemaKey);
debug('Discovering related schema for ' + schemaKey);
}
var newOptions = {};
for (var key in options) {
@ -1173,7 +1196,7 @@ DataSource.prototype.discoverSchemasSync = function (modelName, options) {
});
if (self.settings.debug) {
console.log('Primary keys: ', pks);
debug('Primary keys: ', pks);
}
var schema = {
@ -1220,7 +1243,7 @@ DataSource.prototype.discoverSchemasSync = function (modelName, options) {
var schemaKey = columns[0].owner + '.' + modelName;
if (!options.visited.hasOwnProperty(schemaKey)) {
if (self.settings.debug) {
console.log('Adding schema for ' + schemaKey);
debug('Adding schema for ' + schemaKey);
}
options.visited[schemaKey] = schema;
}
@ -1246,7 +1269,7 @@ DataSource.prototype.discoverSchemasSync = function (modelName, options) {
});
if (self.settings.debug) {
console.log('Foreign keys: ', fks);
debug('Foreign keys: ', fks);
}
schema.options.relations = {};
@ -1271,7 +1294,7 @@ DataSource.prototype.discoverSchemasSync = function (modelName, options) {
var moreTasks = [];
for (var t in otherTables) {
if (self.settings.debug) {
console.log('Discovering related schema for ' + schemaKey);
debug('Discovering related schema for ' + schemaKey);
}
var newOptions = {};
for (var key in options) {
@ -1377,6 +1400,7 @@ DataSource.prototype.isActual = function (models, cb) {
* @private used by connectors
*/
DataSource.prototype.log = function (sql, t) {
debug(sql, t);
this.emit('log', sql, t);
};
@ -1384,13 +1408,16 @@ DataSource.prototype.log = function (sql, t) {
* Freeze dataSource. Behavior depends on connector
*/
DataSource.prototype.freeze = function freeze() {
if(!this.connector) {
throw new Error('The connector has not been initialized.');
}
if (this.connector.freezeDataSource) {
this.connector.freezeDataSource();
}
if (this.connector.freezeSchema) {
this.connector.freezeSchema();
}
}
};
/**
* Return table name for specified `modelName`

View File

@ -103,7 +103,7 @@ function defineScope(cls, targetClass, name, params, methods) {
fn.shared = true;
fn.http = {verb: 'get', path: '/' + name};
fn.accepts = {arg: 'where', type: 'object'};
fn.accepts = {arg: 'filter', type: 'object'};
fn.description = 'Fetches ' + name;
fn.returns = {arg: name, type: 'array', root: true};
@ -188,6 +188,18 @@ function defineScope(cls, targetClass, name, params, methods) {
base.order = update.order;
}
if(update.limit !== undefined) {
base.limit = update.limit;
}
if(update.skip !== undefined) {
base.skip = update.skip;
}
if(update.offset !== undefined) {
base.offset = update.offset;
}
if(update.fields !== undefined) {
base.fields = update.fields;
}
return base;
}

View File

@ -30,7 +30,8 @@
"async": "~0.2.10",
"inflection": "~1.3.5",
"traverse": "~0.6.6",
"qs": "~0.6.6"
"qs": "~0.6.6",
"debug": "~0.7.4"
},
"license": {
"name": "Dual MIT/StrongLoop",

View File

@ -1,6 +1,7 @@
// This test written in mocha+should.js
var should = require('./init.js');
var assert = require('assert');
var async = require('async');
var jdb = require('../');
var ModelBuilder = jdb.ModelBuilder;
@ -796,6 +797,33 @@ describe('Load models with relations', function () {
});
describe('Model with scopes', function () {
it('should create scopes', function (done) {
var ds = new DataSource('memory');
var User = ds.define('User', {name: String, vip: Boolean, age: Number},
{scopes: {vips: {where: {vip: true}}, top5: {limit: 5, order: 'age'}}});
var users = [];
for (var i = 0; i < 10; i++) {
users.push({name: 'User' + i, vip: i % 3 === 0, age: 20 + i * 2});
}
async.each(users, function (user, callback) {
User.create(user, callback);
}, function (err) {
User.vips(function (err, vips) {
if(err) {
return done(err);
}
assert.equal(vips.length, 4);
User.top5(function (err, top5) {
assert.equal(top5.length, 5);
done(err);
});
});
});
});
});
describe('DataAccessObject', function () {
var ds, model, where;