From 1059a7b8632fe27efeeb4b0c3acb88f83124ed5e Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Tue, 16 Jul 2013 11:05:38 -0700 Subject: [PATCH] Add renamed files --- lib/loopback.js | 218 ++++++++++++++++++++++++++++++++++++++++++ test/loopback.test.js | 48 ++++++++++ 2 files changed, 266 insertions(+) create mode 100644 lib/loopback.js create mode 100644 test/loopback.test.js diff --git a/lib/loopback.js b/lib/loopback.js new file mode 100644 index 00000000..14b60a1a --- /dev/null +++ b/lib/loopback.js @@ -0,0 +1,218 @@ +/** + * Module dependencies. + */ + +var express = require('express') + , fs = require('fs') + , ejs = require('ejs') + , EventEmitter = require('events').EventEmitter + , path = require('path') + , proto = require('./application') + , utils = require('express/node_modules/connect').utils + , DataSource = require('jugglingdb').DataSource + , ModelBuilder = require('jugglingdb').ModelBuilder + , assert = require('assert') + , i8n = require('inflection'); + +/** + * Expose `createApplication()`. + */ + +var loopback = exports = module.exports = createApplication; + +/** + * Framework version. + */ + +loopback.version = require('../package.json').version; + +/** + * Expose mime. + */ + +loopback.mime = express.mime; + +/** + * Create an loopback application. + * + * @return {Function} + * @api public + */ + +function createApplication() { + var app = express(); + + utils.merge(app, proto); + + return app; +} + +/** + * Expose express.middleware as loopback.* + * for example `loopback.errorHandler` etc. + */ + +for (var key in express) { + Object.defineProperty( + loopback + , key + , Object.getOwnPropertyDescriptor(express, key)); +} + +/** + * Expose additional loopback middleware + * for example `loopback.configure` etc. + */ + +fs + .readdirSync(path.join(__dirname, 'middleware')) + .filter(function (file) { + return file.match(/\.js$/); + }) + .forEach(function (m) { + loopback[m.replace(/\.js$/, '')] = require('./middleware/' + m); + }); + +/** + * Error handler title + */ + +loopback.errorHandler.title = 'Loopback'; + +/** + * Create a data source with passing the provided options to the connector. + * + * @param {String} name (optional) + * @param {Object} options + * + * - connector - an loopback connector + * - other values - see the specified `connector` docs + */ + +loopback.createDataSource = function (name, options) { + var ds = new DataSource(name, options); + ds.createModel = function (name, properties, settings) { + var ModelCtor = loopback.createModel(name, properties, settings); + ModelCtor.attachTo(ds); + + var hasMany = ModelCtor.hasMany; + + if(hasMany) { + ModelCtor.hasMany = function (anotherClass, params) { + var origArgs = arguments; + var thisClass = this, thisClassName = this.modelName; + params = params || {}; + if (typeof anotherClass === 'string') { + params.as = anotherClass; + if (params.model) { + anotherClass = params.model; + } else { + var anotherClassName = i8n.singularize(anotherClass).toLowerCase(); + for(var name in this.schema.models) { + if (name.toLowerCase() === anotherClassName) { + anotherClass = this.schema.models[name]; + } + } + } + } + + var pluralized = i8n.pluralize(anotherClass.modelName); + var methodName = params.as || + i8n.camelize(pluralized, true); + var proxyMethodName = 'get' + i8n.titleize(pluralized, true); + + // create a proxy method + var fn = this.prototype[proxyMethodName] = function () { + // this[methodName] cannot be a shared method + // because it is defined inside + // a property getter... + + this[methodName].apply(thisClass, arguments); + }; + + fn.shared = true; + fn.http = {verb: 'get', path: '/' + methodName}; + fn.accepts = {arg: 'where', type: 'object'}; + hasMany.apply(this, arguments); + }; + } + + return ModelCtor; + } + return ds; +} + +/** + * Create a named vanilla JavaScript class constructor with an attached set of properties and options. + * + * @param {String} name - must be unique + * @param {Object} properties + * @param {Object} options (optional) + */ + +loopback.createModel = function (name, properties, options) { + return loopback.Model.extend(name, properties, options); +} + +/** + * Add a remote method to a model. + * @param {Function} fn + * @param {Object} options (optional) + */ + +loopback.remoteMethod = function (fn, options) { + fn.shared = true; + if(typeof options === 'object') { + Object.keys(options).forEach(function (key) { + fn[key] = options[key]; + }); + } + fn.http = fn.http || {verb: 'get'}; +} + +/** + * Create a template helper. + * + * var render = loopback.template('foo.ejs'); + * var html = render({foo: 'bar'}); + * + * @param {String} path Path to the template file. + * @returns {Function} + */ + +loopback.template = function (file) { + var templates = this._templates || (this._templates = {}); + var str = templates[file] || (templates[file] = fs.readFileSync(file, 'utf8')); + return ejs.compile(str); +} + +/** + * Get an in-memory data source. Use one if it already exists. + * + * @param {String} [name] The name of the data source. If not provided, the `'default'` is used. + */ + +loopback.memory = function (name) { + name = name || 'default'; + var memory = ( + this._memoryDataSources + || (this._memoryDataSources = {}) + )[name]; + + if(!memory) { + memory = this._memoryDataSources[name] = loopback.createDataSource({ + connector: loopback.Memory + }); + } + + return memory; +} + +/* + * Built in models / services + */ + +loopback.Model = require('./models/model'); +loopback.Email = require('./models/email'); +loopback.User = require('./models/user'); +loopback.Session = require('./models/session'); diff --git a/test/loopback.test.js b/test/loopback.test.js new file mode 100644 index 00000000..0f52636b --- /dev/null +++ b/test/loopback.test.js @@ -0,0 +1,48 @@ +describe('loopback', function() { + describe('loopback.createDataSource(options)', function(){ + it('Create a data source with a connector.', function() { + var dataSource = loopback.createDataSource({ + connector: loopback.Memory + }); + assert(dataSource.connector()); + }); + }); + + describe('loopback.remoteMethod(Model, fn, [options]);', function() { + it("Setup a remote method.", function() { + var Product = loopback.createModel('product', {price: Number}); + + Product.stats = function(fn) { + // ... + } + + loopback.remoteMethod( + Product.stats, + { + returns: {arg: 'stats', type: 'array'}, + http: {path: '/info', verb: 'get'} + } + ); + + assert.equal(Product.stats.returns.arg, 'stats'); + assert.equal(Product.stats.returns.type, 'array'); + assert.equal(Product.stats.http.path, '/info'); + assert.equal(Product.stats.http.verb, 'get'); + assert.equal(Product.stats.shared, true); + }); + }); + + describe('loopback.memory([name])', function(){ + it('Get an in-memory data source. Use one if it already exists.', function() { + var memory = loopback.memory(); + assertValidDataSource(memory); + var m1 = loopback.memory(); + var m2 = loopback.memory('m2'); + var alsoM2 = loopback.memory('m2'); + + assert(m1 === memory); + assert(m1 !== m2); + assert(alsoM2 === m2); + }); + }); +}); \ No newline at end of file