loopback/lib/asteroid.js

267 lines
6.4 KiB
JavaScript
Raw Normal View History

2013-04-09 16:02:36 +00:00
/**
* Module dependencies.
*/
var express = require('express')
, fs = require('fs')
2013-06-13 04:30:20 +00:00
, EventEmitter = require('events').EventEmitter
2013-04-09 16:02:36 +00:00
, path = require('path')
2013-05-07 18:38:52 +00:00
, proto = require('./application')
2013-06-08 00:37:30 +00:00
, utils = require('express/node_modules/connect').utils
, DataSource = require('jugglingdb').DataSource
2013-06-13 04:30:20 +00:00
, ModelBuilder = require('jugglingdb').ModelBuilder
, assert = require('assert')
, i8n = require('inflection');
2013-04-09 16:02:36 +00:00
/**
* Expose `createApplication()`.
*/
var asteroid = exports = module.exports = createApplication;
/**
* Framework version.
*/
asteroid.version = require('../package.json').version;
/**
* Expose mime.
*/
asteroid.mime = express.mime;
/**
* Create an asteroid application.
*
* @return {Function}
* @api public
*/
function createApplication() {
var app = express();
2013-05-24 14:59:23 +00:00
utils.merge(app, proto);
2013-04-09 16:02:36 +00:00
return app;
}
/**
* Expose express.middleware as asteroid.*
* for example `asteroid.errorHandler` etc.
*/
for (var key in express) {
Object.defineProperty(
asteroid
, key
, Object.getOwnPropertyDescriptor(express, key));
}
/**
* Expose additional asteroid middleware
* for example `asteroid.configure` etc.
*/
fs
.readdirSync(path.join(__dirname, 'middleware'))
.filter(function (file) {
return file.match(/\.js$/);
})
.forEach(function (m) {
asteroid[m.replace(/\.js$/, '')] = require('./middleware/' + m);
});
2013-04-09 16:02:36 +00:00
/**
* Error handler title
*/
2013-06-08 00:37:30 +00:00
asteroid.errorHandler.title = 'Asteroid';
/**
* Create a data source with passing the provided options to the connector.
2013-06-11 16:01:44 +00:00
*
* @param {String} name (optional)
* @param {Object} options
*
* - connector - an asteroid connector
* - other values - see the specified `connector` docs
*/
asteroid.createDataSource = function (name, options) {
2013-06-12 22:44:38 +00:00
var ds = new DataSource(name, options);
ds.createModel = function (name, properties, settings) {
2013-06-13 04:30:20 +00:00
var ModelCtor = asteroid.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;
2013-06-12 22:44:38 +00:00
}
return ds;
2013-06-11 16:01:44 +00:00
}
/**
* 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)
2013-06-08 00:37:30 +00:00
*/
2013-06-11 16:01:44 +00:00
asteroid.createModel = function (name, properties, options) {
2013-06-12 22:44:38 +00:00
assert(typeof name === 'string', 'Cannot create a model without a name');
2013-06-11 16:01:44 +00:00
var mb = new ModelBuilder();
var ModelCtor = mb.define(name, properties, options);
2013-06-12 22:44:38 +00:00
ModelCtor.shared = true;
ModelCtor.sharedCtor = function (data, id, fn) {
if(typeof data === 'function') {
fn = data;
data = null;
id = null;
} else if (typeof id === 'function') {
fn = id;
2013-06-13 04:30:20 +00:00
if(typeof data !== 'object') {
id = data;
data = null;
} else {
id = null;
}
2013-06-12 22:44:38 +00:00
}
if(id && data) {
var model = new ModelCtor(data);
model.id = id;
fn(null, model);
} else if(data) {
fn(null, new ModelCtor(data));
} else if(id) {
ModelCtor.find(id, function (err, model) {
if(err) {
fn(err);
} else if(model) {
fn(null, model);
} else {
err = new Error('could not find a model with id ' + id);
err.statusCode = 404;
fn(err);
}
});
2013-06-12 22:44:38 +00:00
} else {
fn(new Error('must specify an id or data'));
}
};
ModelCtor.sharedCtor.accepts = [
{arg: 'data', type: 'object', http: {source: 'body'}},
{arg: 'id', type: 'any', http: {source: 'url'}}
2013-06-12 22:44:38 +00:00
];
ModelCtor.sharedCtor.http = [
{path: '/'},
{path: '/:id'}
];
// before remote hook
ModelCtor.beforeRemote = function (name, fn) {
2013-06-13 04:30:20 +00:00
var self = this;
if(this.app) {
var remotes = this.app.remotes();
remotes.before(self.pluralModelName + '.' + name, function (ctx, next) {
fn(ctx, ctx.instance, next);
});
} else {
var args = arguments;
2013-07-02 23:51:38 +00:00
this.once('attached', function () {
self.beforeRemote.apply(self, args);
2013-06-13 04:30:20 +00:00
});
}
2013-06-12 22:44:38 +00:00
}
// after remote hook
ModelCtor.afterRemote = function (name, fn) {
2013-06-13 04:30:20 +00:00
var self = this;
if(this.app) {
var remotes = this.app.remotes();
remotes.after(self.pluralModelName + '.' + name, function (ctx, next) {
fn(ctx, ctx.instance, next);
});
} else {
var args = arguments;
2013-07-02 23:51:38 +00:00
this.once('attached', function () {
2013-06-13 04:30:20 +00:00
self.afterRemote.apply(ModelCtor, args);
});
}
2013-06-12 22:44:38 +00:00
}
return ModelCtor;
2013-06-11 16:01:44 +00:00
}
/**
* Add a remote method to a model.
* @param {Function} fn
* @param {Object} options (optional)
*/
asteroid.remoteMethod = function (fn, options) {
fn.shared = true;
2013-06-13 04:30:20 +00:00
if(typeof options === 'object') {
Object.keys(options).forEach(function (key) {
fn[key] = options[key];
});
}
fn.http = fn.http || {verb: 'get'};
2013-06-11 16:01:44 +00:00
}
2013-07-01 23:50:03 +00:00
/*
* Built in models
*/
asteroid.Model = asteroid.createModel('model');
asteroid.User = require('./models/user');
2013-07-02 23:51:38 +00:00
asteroid.Session = require('./models/session');