loopback-datasource-juggler/README.md

223 lines
5.9 KiB
Markdown
Raw Normal View History

2011-10-05 21:18:38 +00:00
## About
2011-10-06 20:21:27 +00:00
JugglingDB is cross-db ORM, providing **common interface** to access most popular database formats.
Currently supported are: mysql, mongodb, redis, neo4j and js-memory-storage (yep,
self-written engine for test-usage only). You can add your favorite database adapter, checkout one of the
existing adapters to learn how, it's super-easy, I guarantee.
2011-10-05 21:18:38 +00:00
## Installation
git clone git://github.com/1602/jugglingdb.git
2012-01-10 16:44:56 +00:00
## Participation
Check status of project on trello board: https://trello.com/board/jugglingdb/4f0a0b1e27d3103c64288388
Feel free to vote and comment on cards (tickets/issues), if you want to join team -- send me a message with your email.
2011-10-05 21:18:38 +00:00
## Usage
```javascript
2011-10-05 21:21:25 +00:00
var Schema = require('./jugglingdb').Schema;
2011-10-05 21:18:38 +00:00
var s = new Schema('redis');
// define models
var Post = schema.define('Post', {
title: { type: String, length: 255 },
content: { type: Schema.Text },
2011-10-11 19:28:27 +00:00
date: { type: Date, default: Date.now },
2011-10-05 21:18:38 +00:00
published: { type: Boolean, default: false }
});
2011-10-06 07:26:26 +00:00
// simplier way to describe model
2011-10-05 21:18:38 +00:00
var User = schema.define('User', {
name: String,
2011-10-06 07:26:26 +00:00
bio: Schema.Text,
2011-10-05 21:18:38 +00:00
approved: Boolean,
joinedAt: Date,
age: Number
});
// setup relationships
User.hasMany(Post, {as: 'posts', foreignKey: 'userId'});
// creates instance methods:
// user.posts(conds)
2011-10-15 15:57:35 +00:00
// user.posts.build(data) // like new Post({userId: user.id});
// user.posts.create(data) // build and save
2011-10-05 21:18:38 +00:00
Post.belongsTo(User, {as: 'author', foreignKey: 'userId'});
// creates instance methods:
// post.author(callback) -- getter when called with function
// post.author() -- sync getter when called without params
// post.author(user) -- setter when called with object
s.automigrate(); // required only for mysql NOTE: it will drop User and Post tables
// work with models:
var user = new User;
user.save(function (err) {
2011-10-15 15:57:35 +00:00
var post = user.posts.build({title: 'Hello world'});
2011-10-05 21:18:38 +00:00
post.save(console.log);
});
// or just call it as function (with the same result):
var user = User();
user.save(...);
2011-10-05 21:18:38 +00:00
// Common API methods
// just instantiate model
new Post
// save model (of course async)
Post.create(cb);
// all posts
Post.all(cb)
// all posts by user
Post.all({where: {userId: user.id}});
2011-10-05 21:18:38 +00:00
// the same as prev
user.posts(cb)
// same as new Post({userId: user.id});
2011-10-15 15:57:35 +00:00
user.posts.build
2011-10-05 21:18:38 +00:00
// save as Post.create({userId: user.id}, cb);
2011-10-15 15:57:35 +00:00
user.posts.create(cb)
2011-10-05 21:18:38 +00:00
// find instance by id
User.find(1, cb)
// count instances
User.count(cb)
// destroy instance
user.destroy(cb);
// destroy all instances
User.destroyAll(cb);
2011-10-10 13:39:10 +00:00
// Setup validations
User.validatesPresenceOf('name', 'email')
User.validatesLengthOf('password', {min: 5, message: {min: 'Password is too short'}});
User.validatesInclusionOf('gender', {in: ['male', 'female']});
User.validatesExclusionOf('domain', {in: ['www', 'billing', 'admin']});
User.validatesNumericalityOf('age', {int: true});
User.validatesUniquenessOf('email', {message: 'email is not unique'});
2011-10-10 13:39:10 +00:00
user.isValid(function (valid) {
if (!valid) {
user.errors // hash of errors {attr: [errmessage, errmessage, ...], attr: ...}
}
})
```
## Callbacks
The following callbacks supported:
- afterInitialize
- beforeCreate
- afterCreate
- beforeSave
- afterSave
- beforeUpdate
- afterUpdate
- beforeDestroy
- afterDestroy
- beforeValidation
- afterValidation
Each callback is class method of the model, it should accept single argument: `next`, this is callback which
should be called after end of the hook. Except `afterInitialize` because this method is syncronous (called after `new Model`).
## Object lifecycle:
```javascript
var user = new User;
// afterInitialize
user.save(callback);
// beforeValidation
// afterValidation
// beforeSave
// beforeCreate
// afterCreate
// afterSave
// callback
user.updateAttribute('email', 'email@example.com', callback);
// beforeValidation
// afterValidation
// beforeUpdate
// afterUpdate
// callback
user.destroy(callback);
// beforeDestroy
// afterDestroy
// callback
User.create(data, callback);
// beforeValidate
// afterValidate
// beforeCreate
// afterCreate
// callback
2011-10-05 21:18:38 +00:00
```
Read the tests for usage examples: ./test/common_test.js
2011-10-10 13:39:10 +00:00
Validations: ./test/validations_test.js
2011-10-05 21:18:38 +00:00
## Your own database adapter
2011-10-06 20:21:27 +00:00
To use custom adapter, pass it's package name as first argument to `Schema` constructor:
2011-10-05 21:18:38 +00:00
mySchema = new Schema('couch-db-adapter', {host:.., port:...});
Make sure, your adapter can be required (just put it into ./node_modules):
require('couch-db-adapter');
## Running tests
2011-10-06 20:21:27 +00:00
All tests are written using nodeunit:
2011-10-05 21:18:38 +00:00
nodeunit test/common_test.js
2011-10-06 20:21:27 +00:00
If you run this line, of course it will fall, because it requres different databases to be up and running,
but you can use js-memory-engine out of box! Specify ONLY env var:
2011-10-05 21:18:38 +00:00
ONLY=memory nodeunit test/common_test.js
of course, if you have redis running, you can run
ONLY=redis nodeunit test/common_test.js
## Package structure
2011-10-10 13:39:10 +00:00
Now all common logic described in `./lib/*.js`, and database-specific stuff in `./lib/adapters/*.js`. It's super-tiny, right?
2011-10-05 21:18:38 +00:00
## Project status
2011-10-06 20:21:27 +00:00
This project was written in one weekend (1,2 oct 2011), and of course does not claim to be production-ready,
but I plan to use this project as default ORM for RailwayJS in nearest future.
So, if you are familiar with some database engines - please help me to improve adapter for that database.
2011-10-05 21:18:38 +00:00
2011-10-06 20:21:27 +00:00
For example, I know, mysql implementation sucks now, 'cause I'm not digging too deep into SequelizeJS code,
and I think it would be better to replace sequelize with something low-level in nearest future, such
as `mysql` package from npm.
2011-10-05 21:18:38 +00:00
## Contributing
If you have found a bug please write unit test, and make sure all other tests still pass before pushing code to repo.
## Roadmap
### Common:
2011-10-06 07:26:26 +00:00
+ transparent interface to APIs
2011-10-05 21:18:38 +00:00
+ -before and -after hooks on save, update, destroy
2011-10-15 15:57:35 +00:00
+ scopes
2011-10-05 21:18:38 +00:00
+ default values
+ more relationships stuff
+ docs
### Databases:
+ riak
+ couchdb
+ low-level mysql
+ postgres
+ sqlite
## License
MIT