diff --git a/README.md b/README.md index f0305046..ed6ede1e 100644 --- a/README.md +++ b/README.md @@ -10,9 +10,10 @@ v0.0.1 - [App](#app) - [asteroid.Model](#model) - [asteroid.DataSource](#data-source) + - [Adapters](#adapters) - [asteroid.GeoPoint](#geo-point) - - [asteroid.rest](#rest) - [Asteroid Types](#asteroid-types) + - [asteroid.rest](#rest-middleware) ## Client APIs @@ -20,7 +21,7 @@ _TODO_ ### App -Create an asteroid application. +Create an asteroid application. var asteroid = require('asteroid'); var app = asteroid(); @@ -120,30 +121,34 @@ Define a static model method. Expose the static model method to clients as a [remote method](#remote-method). - User.expose('login', { - accepts: [ - {arg: 'username', type: 'string', required: true}, - {arg: 'password', type: 'string', required: true} - ], - returns: {arg: 'sessionId', type: 'any'} - }); + asteroid.remoteMethod( + User, + User.login, + { + accepts: [ + {arg: 'username', type: 'string', required: true}, + {arg: 'password', type: 'string', required: true} + ], + returns: {arg: 'sessionId', type: 'any'}, + http: {path: '/sign-in'} + } + ); #### Instance Methods -Define an instance method +Define an instance method. User.prototype.logout = function (fn) { MySessionModel.destroyAll({userId: this.id}, fn); } -Expose the model instance method to clients using remoting. +Define a remote model instance method. - User.prototype.logout.shared = true; - User.expose('logout', {instance: true}); + asteroid.remoteMethod(User, User.prototype.logout); #### Remote Methods -Both instance and static methods may be shared exposed to clients using remoting. A remote method must accept a callback with the conventional `fn(err, result, ...)` signature. +Both instance and static methods can be exposed to clients. A remote method must accept a callback with the conventional `fn(err, result, ...)` signature. ##### Model.expose(method, [options]); @@ -153,7 +158,7 @@ Expose a remote method. myApi.getStats('products', fn); } - Product.expose('stats', { + asteroid.remoteMethod('stats', { returns: {arg: 'stats', type: 'array'}, http: {path: '/info', verb: 'get'} }); @@ -166,19 +171,18 @@ Expose a remote method. - **http** - (advanced / optional, object) http routing info - **http.path** - the relative path the method will be exposed at. May be a path fragment (eg. '/:myArg') which will be populated by an arg of the same name in the accepts description. - **http.verb** - (get, post, put, del, all) - the route verb the method will be available from. - **Argument Description** An arguments description defines either a single argument as an object or an ordered set of arguments as an array. - // examples - {arg: 'myArg', type: 'number'} - - [ - {arg: 'arg1', type: 'number', required: true}, - {arg: 'arg2', type: 'array'} - ] + // examples + {arg: 'myArg', type: 'number'} + + [ + {arg: 'arg1', type: 'number', required: true}, + {arg: 'arg2', type: 'array'} + ] **Types** @@ -358,13 +362,39 @@ Discover a set of models based on tables or collections in a data source. **Note:** The `models` will contain all properties and settings discovered from the data source. It will also automatically discover and create relationships. -#### dataSource.discoverModelsSync(options) +#### dataSource.discoverModelsSync(options) Synchronously Discover a set of models based on tables or collections in a data source. var models = oracle.discoverModels({owner: 'MYORG'}); var ProductModel = models.Product; +#### Adapters + +Create a data source with a specific adapter. + + var memory = asteroid.createDataSource({ + adapter: require('asteroid-memory') + }); + +**Available Adapters** + + - [Oracle](http://github.com/strongloop/asteroid-adapters/oracle) + - [In Memory](http://github.com/strongloop/asteroid-adapters/memory) + + +**Installing Adapters** + +Include the adapter in your package.json dependencies and run `npm install`. + ### GeoPoint Embed a latitude / longitude point in a [Model](#model). @@ -413,7 +443,7 @@ The longitude point in degrees. Range: -180 to 180. ### Asteroid Types -Various APIs in Asteroid accept type descriptions (eg. [remote methods](#remote-methods), [asteroid.createModel()](#asteroidcreateModel)). The following is a list of supported types. +Various APIs in Asteroid accept type descriptions (eg. [remote methods](#remote-methods), [asteroid.createModel()](#model)). The following is a list of supported types. - `null` - JSON null - `Boolean` - JSON boolean @@ -423,4 +453,17 @@ Various APIs in Asteroid accept type descriptions (eg. [remote methods](#remote- - `Array` - JSON array - `Date` - a JavaScript date object - `Buffer` - a node.js Buffer object - - [GeoPoint](#geopoint) - an asteroid GeoPoint object. \ No newline at end of file + - [GeoPoint](#geopoint) - an asteroid GeoPoint object. + +### Rest Middleware + +Expose models over rest using the `asteroid.rest` middleware. + + app.use(asteroid.rest()); + +### SocketIO Middleware **Not Available** + +**Coming Soon** - Expose models over socket.io using the `asteroid.sio()` middleware. + + app.use(asteroid.sio); + diff --git a/lib/application.js b/lib/application.js index 37eba58b..ceaa3350 100644 --- a/lib/application.js +++ b/lib/application.js @@ -45,115 +45,24 @@ app.disuse = function (route) { * App models. */ -app.models = {}; +app._models = []; /** - * Get ModelBuilder. - */ - -app.modelBuilder = function () { - return this._modelBuilder || (this._modelBuilder = new ModelBuilder()) -} - -/** - * Define a model. + * Expose a model. * - * @param name {String} - * @param options {Object} - * @returns {Model} + * @param Model {Model} */ -app.model = -app.defineModel = -app.define = function (name, properties, options) { - var modelBuilder = this.modelBuilder(); - - var ModelCtor = modelBuilder.define(name, properties, options); - - ModelCtor.dataSource = function (name) { - var dataSource = app.dataSources[name]; - - dataSource.attach(this); - - var hasMany = ModelCtor.hasMany; - - // override the default relations to add shared proxy methods - // cannot expose the relation methods since they are only defined - // once you get them (eg. prototype[name]) - 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 cannot be a shared method - // because it is defined when you - // get it... - this[methodName].apply(thisClass, arguments); - }; - fn.shared = true; - fn.http = {verb: 'get', path: '/' + methodName}; - - hasMany.apply(this, arguments); - }; - }; - - ModelCtor.shared = true; - ModelCtor.sharedCtor = function (id, fn) { - ModelCtor.find(id, fn); - }; - ModelCtor.sharedCtor.accepts = [ - // todo... models need to expose what id type they need - {arg: 'id', type: 'number', optional: true}, - {arg: 'data', type: 'object', optional: true} - ]; - ModelCtor.sharedCtor.http = [ - {path: '/'}, - {path: '/:id'} - ]; - - - return (app._models[ModelCtor.pluralModelName] = ModelCtor); +app.model = function (Model) { + this._models.push(Model); } /** - * Get all models. + * Get all exposed models. */ app.models = function () { - var models = this._models; - var dataSources = this.dataSources; - - // add in any model from a data source - Object.keys(this.dataSources).forEach(function (name) { - var dataSource = dataSources[name]; - - Object.keys(dataSource.models).forEach(function (className) { - var model = dataSource.models[className]; - models[i8n.pluralize(model.modelName)] = model; - }); - }); - - return models; + return this._models; } @@ -179,13 +88,6 @@ app.remoteObjects = function () { return result; } -/** - * App data sources and models. - */ - -app._models = {}; -app.dataSources = {}; - /** * Get the apps set of remote objects. */ diff --git a/test/app.test.js b/test/app.test.js new file mode 100644 index 00000000..d3fc6219 --- /dev/null +++ b/test/app.test.js @@ -0,0 +1,17 @@ +var asteroid = require('../'); + +describe('app', function(){ + var app; + + beforeEach(function () { + app = asteroid(); + }); + + describe('asteroid.createModel(name, properties, settings)', function(){ + var User = asteroid.createModel('user', { + first: String, + last: String, + age: Number + }); + }); +}); \ No newline at end of file diff --git a/test/asteroid.test.js b/test/asteroid.test.js deleted file mode 100644 index 9979110d..00000000 --- a/test/asteroid.test.js +++ /dev/null @@ -1,2 +0,0 @@ -var Asteroid = require('../'); - diff --git a/test/model.test.js b/test/model.test.js new file mode 100644 index 00000000..449b3979 --- /dev/null +++ b/test/model.test.js @@ -0,0 +1,19 @@ +var asteroid = require('../'); + +describe('app', function(){ + var app; + + beforeEach(function () { + app = asteroid(); + }); + + describe('.model(Model)', function(){ + it('should expose a Model to remote clients', function() { + var memory = asteroid.createDataSource({adapter: 'memory'}); + var Color = memory.defineModel({name: String}); + + app.model(Color); + assert(app.models()[0] === MyModel, 'should add MyModel to the app models'); + }); + }); +}); \ No newline at end of file