This commit is contained in:
Ritchie Martori 2013-06-21 14:59:44 -07:00
commit 3ba2b0512b
5 changed files with 133 additions and 113 deletions

186
README.md
View File

@ -145,7 +145,7 @@ Validate the model instance.
Attach a model to a [DataSource](#data-source). Attaching a [DataSource](#data-source) updates the model with additional methods and behaviors. Attach a model to a [DataSource](#data-source). Attaching a [DataSource](#data-source) updates the model with additional methods and behaviors.
var oracle = asteroid.createDataSource({ var oracle = asteroid.createDataSource({
connector: require('asteroid-oracle'), connector: require('asteroid-connector-oracle'),
host: '111.22.333.44', host: '111.22.333.44',
database: 'MYDB', database: 'MYDB',
username: 'username', username: 'username',
@ -210,11 +210,11 @@ Find instance by id.
console.info(user.id); // 23 console.info(user.id); // 23
}); });
##### Model.findOne(filter, callback) ##### Model.findOne(where, callback)
Find a single instance that matches the given filter. Find a single instance that matches the given where expression.
User.find(23, function(err, user) { User.findOne({id: 23}, function(err, user) {
console.info(user.id); // 23 console.info(user.id); // 23
}); });
@ -226,6 +226,8 @@ Update when record with id=data.id found, insert otherwise. **Note:** no setters
Define a static model method. Define a static model method.
User.login = function (username, password, fn) { User.login = function (username, password, fn) {
var passwordHash = hashPassword(password); var passwordHash = hashPassword(password);
this.findOne({username: username}, function (err, user) { this.findOne({username: username}, function (err, user) {
@ -441,25 +443,29 @@ Define a "one to many" relationship.
Query and create the related models. Query and create the related models.
Book.create(function(err, book) { Book.create(function(err, book) {
// using 'chapters' scope for build: // create a chapter instance
var c = book.chapters.build({name: 'Chapter 1'}); // ready to be saved in the data source
var chapter = book.chapters.build({name: 'Chapter 1'});
// same as: // save the new chapter
c = new Chapter({name: 'Chapter 1', bookId: book.id}); chapter.save();
// using 'chapters' scope for create: // you can also call the Chapter.create method with
book.chapters.create(); // the `chapters` property which will build a chapter
// instance and save the it in the data source
book.chapters.create({name: 'Chapter 2'}, function(err, savedChapter) {
// this callback is optional
});
// same as: // query chapters for the book using the
Chapter.create({bookId: book.id});
// using scope for querying:
book.chapters(function(err, chapters) { book.chapters(function(err, chapters) {
/* all chapters with bookId = book.id */ // all chapters with bookId = book.id
console.log(chapters);
}); });
book.chapters({where: {name: 'test'}, function(err, chapters) { book.chapters({where: {name: 'test'}, function(err, chapters) {
// all chapters with bookId = book.id and name = 'test' // all chapters with bookId = book.id and name = 'test'
console.log(chapters);
}); });
}); });
@ -471,7 +477,6 @@ TODO: implement / document
Any static or instance method can be decorated as `shared`. These methods are exposed over the provided transport (eg. [asteroid.rest](#rest)). Any static or instance method can be decorated as `shared`. These methods are exposed over the provided transport (eg. [asteroid.rest](#rest)).
### Data Source ### Data Source
An Asteroid `DataSource` provides [Models](#model) with the ability to manipulate data. Attaching a `DataSource` to a `Model` adds [instance methods](#instance-methods) and [static methods](#static-methods) to the `Model`. The added methods may be [remote methods](#remote-methods). An Asteroid `DataSource` provides [Models](#model) with the ability to manipulate data. Attaching a `DataSource` to a `Model` adds [instance methods](#instance-methods) and [static methods](#static-methods) to the `Model`. The added methods may be [remote methods](#remote-methods).
@ -492,55 +497,116 @@ Define a model and attach it to a `DataSource`.
var Color = oracle.createModel('color', {name: String}); var Color = oracle.createModel('color', {name: String});
#### dataSource.discoverAndBuildModels(owner, tableOrView, options, fn) #### dataSource.discoverModelDefinitions([username], fn)
Discover a set of models based on tables or collections in a data source. Discover a set of model definitions (table or collection names) based on tables or collections in a data source.
oracle.discoverAndBuildModels('MYORG', function(err, models) { oracle.discoverModelDefinitions(function (err, models) {
var ProductModel = models.Product; models.forEach(function (def) {
// def.name ~ the model name
oracle.discoverSchema(null, def.name, function (err, schema) {
console.log(schema);
});
});
}); });
**Note:** The `models` will contain all properties and options discovered from the data source. It will also automatically discover and create relationships. #### dataSource.discoverSchema([owner], name, fn)
#### dataSource.discoverAndBuildModelsSync(owner, tableOrView, options) Discover the schema of a specific table or collection.
Synchronously Discover a set of models based on tables or collections in a data source. **Example schema from oracle connector:**
var models = oracle.discoverAndBuildModelsSync('MYORG'); {
var ProductModel = models.Product; "name": "Product",
"options": {
#### dataSource.defineOperation(name, options, fn) "idInjection": false,
"oracle": {
Define a new operation available to all model's attached to the data source. "schema": "BLACKPOOL",
"table": "PRODUCT"
var maps = asteroid.createDataSource({ }
connector: require('asteroid-rest'), },
url: 'http://api.googleapis.com/maps/api' "properties": {
}); "id": {
"type": "String",
rest.defineOperation('geocode', { "required": true,
url: '/geocode/json', "length": 20,
verb: 'get', "id": 1,
accepts: [ "oracle": {
{arg: 'address', type: 'string'}, "columnName": "ID",
{arg: 'sensor', default: 'true'} "dataType": "VARCHAR2",
], "dataLength": 20,
returns: {arg: 'location', type: asteroid.GeoPoint, transform: transform}, "nullable": "N"
json: true, }
enableRemote: true },
}); "name": {
"type": "String",
function transform(res) { "required": false,
var geo = res.body.results[0].geometry; "length": 64,
return new asteroid.GeoPoint({lat: geo.lat, long: geo.lng}); "oracle": {
"columnName": "NAME",
"dataType": "VARCHAR2",
"dataLength": 64,
"nullable": "Y"
}
},
"audibleRange": {
"type": "Number",
"required": false,
"length": 22,
"oracle": {
"columnName": "AUDIBLE_RANGE",
"dataType": "NUMBER",
"dataLength": 22,
"nullable": "Y"
}
},
"effectiveRange": {
"type": "Number",
"required": false,
"length": 22,
"oracle": {
"columnName": "EFFECTIVE_RANGE",
"dataType": "NUMBER",
"dataLength": 22,
"nullable": "Y"
}
},
"rounds": {
"type": "Number",
"required": false,
"length": 22,
"oracle": {
"columnName": "ROUNDS",
"dataType": "NUMBER",
"dataLength": 22,
"nullable": "Y"
}
},
"extras": {
"type": "String",
"required": false,
"length": 64,
"oracle": {
"columnName": "EXTRAS",
"dataType": "VARCHAR2",
"dataLength": 64,
"nullable": "Y"
}
},
"fireModes": {
"type": "String",
"required": false,
"length": 64,
"oracle": {
"columnName": "FIRE_MODES",
"dataType": "VARCHAR2",
"dataLength": 64,
"nullable": "Y"
}
}
}
} }
var GeoCoder = rest.createModel('geocoder');
GeoCoder.geocode('123 fake street', function(err, point) {
console.log(point.lat, point.long); // 24.224424 44.444445
});
#### dataSource.enableRemote(operation) #### dataSource.enableRemote(operation)
Enable remote access to a data source operation. Each [connector](#connector) has its own set of set remotely enabled and disabled operations. You can always list these by calling `dataSource.operations()`. Enable remote access to a data source operation. Each [connector](#connector) has its own set of set remotely enabled and disabled operations. You can always list these by calling `dataSource.operations()`.
@ -553,7 +619,7 @@ Disable remote access to a data source operation. Each [connector](#connector) h
// all rest data source operations are // all rest data source operations are
// disabled by default // disabled by default
var oracle = asteroid.createDataSource({ var oracle = asteroid.createDataSource({
connector: require('asteroid-oracle'), connector: require('asteroid-connector-oracle'),
host: '...', host: '...',
... ...
}); });
@ -619,11 +685,11 @@ Include the connector in your package.json dependencies and run `npm install`.
{ {
"dependencies": { "dependencies": {
"asteroid-oracle": "latest" "asteroid-connector-oracle": "latest"
} }
} }
### GeoPoint ### GeoPoint TODO
Embed a latitude / longitude point in a [Model](#model). Embed a latitude / longitude point in a [Model](#model).
@ -681,7 +747,7 @@ Various APIs in Asteroid accept type descriptions (eg. [remote methods](#remote-
- `Array` - JSON array - `Array` - JSON array
- `Date` - a JavaScript date object - `Date` - a JavaScript date object
- `Buffer` - a node.js Buffer object - `Buffer` - a node.js Buffer object
- [GeoPoint](#geopoint) - an asteroid GeoPoint object. - [GeoPoint](#geopoint) - an asteroid GeoPoint object. TODO
### REST Router ### REST Router

View File

@ -5,7 +5,7 @@ app.use(asteroid.rest());
var dataSource = app.dataSource('db', var dataSource = app.dataSource('db',
{ adapter: 'oracle', { adapter: require('asteroid-connector-oracle'),
host: '166.78.158.45', host: '166.78.158.45',
database: 'XE', database: 'XE',
username: 'strongloop', username: 'strongloop',

View File

@ -61,6 +61,7 @@ app._models = [];
app.model = function (Model) { app.model = function (Model) {
this._models.push(Model); this._models.push(Model);
Model.shared = true;
Model.app = this; Model.app = this;
if(Model._remoteHooks) { if(Model._remoteHooks) {
Model._remoteHooks.emit('attached', app); Model._remoteHooks.emit('attached', app);

View File

@ -19,6 +19,6 @@
"supertest": "latest" "supertest": "latest"
}, },
"optionalDependencies": { "optionalDependencies": {
"jugglingdb-oracle": "git+ssh://git@github.com:strongloop/jugglingdb-oracle.git" "asteroid-connector-oracle": "git+ssh://git@github.com:strongloop/asteroid-connector-oracle.git"
} }
} }

View File

@ -34,53 +34,6 @@ describe('DataSource', function() {
}); });
}); });
// describe('dataSource.discover(options, fn)', function() {
// it("Discover an object containing properties and settings for an existing data source.", function(done) {
// /* example -
// oracle.discover({owner: 'MYORG'}, function(err, tables) {
// var productSchema = tables.PRODUCTS;
// var ProductModel = oracle.createModel('product', productSchema.properties, productSchema.settings);
// });
//
// */
// done(new Error('test not implemented'));
// });
// });
//
// describe('dataSource.discoverSync(options)', function() {
// it("Synchronously discover an object containing properties and settings for an existing data source tables or collections.", function(done) {
// /* example -
// var tables = oracle.discover({owner: 'MYORG'});
// var productSchema = tables.PRODUCTS;
// var ProductModel = oracle.createModel('product', productSchema.properties, productSchema.settings);
//
// */
// done(new Error('test not implemented'));
// });
// });
// describe('dataSource.discoverModels(options, fn) ', function() {
// it("Discover a set of models based on tables or collections in a data source.", function(done) {
// /* example -
// oracle.discoverModels({owner: 'MYORG'}, function(err, models) {
// var ProductModel = models.Product;
// });
//
// */
// done(new Error('test not implemented'));
// });
// });
//
// describe('dataSource.discoverModelsSync(options)', function() {
// it("Synchronously Discover a set of models based on tables or collections in a data source.", function(done) {
// /* example -
// var models = oracle.discoverModels({owner: 'MYORG'});
// var ProductModel = models.Product;
// */
// done(new Error('test not implemented'));
// });
// });
describe('dataSource.operations()', function() { describe('dataSource.operations()', function() {
it("List the enabled and disabled operations.", function() { it("List the enabled and disabled operations.", function() {
// assert the defaults // assert the defaults