Giter Club home page Giter Club logo

jugglingdb's Introduction

NPM Version NPM Downloads Build status Test Coverage

About

JugglingDB is cross-db ORM for nodejs, providing common interface to access most popular database formats. Currently supported are: mysql, sqlite3, postgres, mongodb, redis 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.

Jugglingdb also works on client-side (using WebService and Memory adapters), which allows to write rich client-side apps talking to server using JSON API.

Installation

npm install jugglingdb

and you should install appropriate adapter, for example for redis:

npm install jugglingdb-redis-hq

check following list of available adapters

JugglingDB adapters

Database type Package name Maintainer Build status / coverage
ArangoDB ArangoDB jugglingdb-arango Andreas Streichardt Build Status
Firebird Firebird jugglingdb-firebird Henri Gourvest
MongoDB MongoDB jugglingdb-mongodb Anatoliy Chakkaev Build Status Coverage Status
MySQL MySQL jugglingdb-mysql dgsan Build Status Coverage Status
CouchDB CouchDB / nano jugglingdb-nano Nicholas Westlake Build Status
PostgreSQL PostgreSQL jugglingdb-postgres Anatoliy Chakkaev Build Status Coverage Status
Redis Redis jugglingdb-redis-hq Anatoliy Chakkaev Build Status Coverage Status
RethinkDB RethinkDB jugglingdb-rethink Tewi Inaba Build Status
SQLite SQLite jugglingdb-sqlite3 Anatoliy Chakkaev Build Status Coverage Status
WebService built-in Anatoliy Chakkaev n/a
Memory (bogus) built-in Anatoliy Chakkaev n/a
DynamoDB jugglingdb-dynamodb tmpaul Build Status
SQL Server jugglingdb-mssql Quadrus n/a
Azure Table Storage jugglingdb-azure-tablestorage Vadim Kazakov n/a

Participation

If you want to create your own jugglingdb adapter, you should publish your adapter package with name jugglingdb-ADAPTERNAME. Creating adapter is simple, check jugglingdb/redis-adapter for example. JugglingDB core exports common tests each adapter should pass, you could create your adapter in TDD style, check that adapter pass all tests defined in test/common_test.js.

Usage

var Schema = require('jugglingdb').Schema;
var schema = new Schema('redis', {port: 6379}); //port number depends on your configuration
// define models
var Post = schema.define('Post', {
    title:     { type: String, length: 255 },
    content:   { type: Schema.Text },
    date:      { type: Date,    default: function () { return new Date;} },
    timestamp: { type: Number,  default: Date.now },
    published: { type: Boolean, default: false, index: true }
});

// simplier way to describe model
var User = schema.define('User', {
    name:         String,
    bio:          Schema.Text,
    approved:     Boolean,
    joinedAt:     Date,
    age:          Number
}, {
    restPath: '/users' // tell WebService adapter which path use as API endpoint
});

var Group = schema.define('Group', {name: String});

// define any custom method
User.prototype.getNameAndAge = function () {
    return this.name + ', ' + this.age;
};

// models also accessible in schema:
schema.models.User;
schema.models.Post;

SEE schema(3) for details schema usage.

// setup relationships
User.hasMany(Post,   {as: 'posts',  foreignKey: 'userId'});
// creates instance methods:
// user.posts(conds)
// user.posts.build(data) // like new Post({userId: user.id});
// user.posts.create(data) // build and save

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

User.hasAndBelongsToMany('groups');
// user.groups(callback) - get groups of user
// user.groups.create(data, callback) - create new group and connect with user
// user.groups.add(group, callback) - connect existing group with user
// user.groups.remove(group, callback) - remove connection between group and user

schema.automigrate(); // required only for mysql and postgres NOTE: it will drop User and Post tables

// work with models:
var user = new User;
user.save(function (err) {
    var post = user.posts.build({title: 'Hello world'});
    post.save(console.log);
});

// or just call it as function (with the same result):
var user = User();
user.save(...);

// Common API methods
// each method returns promise, or may accept callback as last param

// just instantiate model
new Post({ published: 0, userId: 1 });

// save model (of course async)
Post.create();

// all posts
Post.all();

// all posts by user
Post.all({ where: { userId: user.id }, order: 'id', limit: 10, skip: 20 });

// the same as prev
user.posts(cb)

// get one latest post
Post.findOne({ where: { published: true }, order: 'date DESC' });

// same as new Post({userId: user.id});
user.posts.build({ published: 1 });

// save as Post.create({userId: user.id});
user.posts.create();

// find instance by id
User.find(1);

// find instance by id and reject promise when not found
User.fetch(1)
    .then(user => console.log('found user', user))
    .catch(err => console.error('can not fetch user with id 1:', err));

// count instances
User.count([conditions])

// destroy instance
user.destroy();

// destroy all instances
User.destroyAll();

// update multiple instances (currently only on the sql adapters)
Post.bulkUpdate({ update: { published: 0 }, where: { id: [1, 2, 3] }});

// update single instance
Post.update(1, { published: 1 });

SEE model(3) for more information about jugglingdb Model API. Or man jugglingdb-model in terminal.

// 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'});

user.isValid(function (valid) {
    if (!valid) {
        user.errors // hash of errors {attr: [errmessage, errmessage, ...], attr: ...}    
    }
})

SEE ALSO jugglingdb-validations(3) or man jugglingdb-validations in terminal. Validation tests: ./test/validations.test.js

Hooks

The following hooks supported:

- afterInitialize
- beforeCreate
- afterCreate
- beforeSave
- afterSave
- beforeUpdate
- afterUpdate
- beforeDestroy
- afterDestroy
- beforeValidate
- afterValidate

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).

During beforehooks the next callback accepts one argument, which is used to terminate flow. The argument passed on as the err parameter to the API method callback.

Object lifecycle:

var user = new User;
// afterInitialize
user.save(callback); // If Model.id isn't set, save will invoke Model.create() instead
// beforeValidate
// afterValidate
// beforeSave
// beforeUpdate
// afterUpdate
// afterSave
// callback
user.updateAttribute('email', '[email protected]', callback);
// beforeValidate
// afterValidate
// beforeSave
// beforeUpdate
// afterUpdate
// afterSave
// callback
user.destroy(callback);
// beforeDestroy
// afterDestroy
// callback
User.create(data, callback);
// beforeValidate
// afterValidate
// beforeCreate
// beforeSave
// afterSave
// afterCreate
// callback

SEE jugglingdb-hooks or type this command in your fav terminal: man jugglingdb-hooks. Also check tests for usage examples: ./test/hooks.test.js

Your own database adapter

To use custom adapter, pass it's package name as first argument to Schema constructor:

var mySchema = new Schema('mycouch', {host:.., port:...});

In that case your adapter should be named as 'jugglingdb-mycouch' npm package.

Testing [outdated]

TODO: upd this section

Core of jugglingdb tests only basic features (database-agnostic) like validations, hooks and runs db-specific tests using memory storage. It also exports complete bucket of tests for external running. Each adapter should run this bucket (example from jugglingdb-redis):

var jdb = require('jugglingdb'),
Schema = jdb.Schema,
test = jdb.test;

var schema = new Schema(__dirname + '/..', {host: 'localhost', database: 1});

test(module.exports, schema);

Each adapter could add specific tests to standart bucket:

test.it('should do something special', function (test) {
    test.done();
});

Or it could tell core to skip some test from bucket:

test.skip('name of test case');

To run tests use this command:

npm test

Before running make sure you've installed package (npm install) and if you running some specific adapter tests, ensure you've configured database correctly (host, port, username, password).

Contributing

If you have found a bug please try to write unit test before reporting. Before submit pull request make sure all tests still passed. Check roadmap, github issues if you want to help. Contribution to docs highly appreciated. Contents of man pages and http://1602.github.com/jugglingdb/ generated from md files stored in this repo at ./docs repo

MIT License

Copyright (C) 2011 by Anatoliy Chakkaev <mail [รฅt] anatoliy [dรธt] in>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

Bitdeli Badge

jugglingdb's People

Contributors

1602 avatar absynce avatar alexmingoia avatar athieriot avatar bergie avatar bitdeli-chef avatar craftgear avatar fsateler avatar hbj avatar imothee avatar josephjunker avatar jspies avatar juggy avatar kapouer avatar ktmud avatar making3 avatar mansuleman avatar mhuggins avatar mshick avatar muneebs avatar mypark avatar nashadalam avatar nrw avatar pasindud avatar randunel avatar redvulps avatar saschagehlich avatar scottnonnenberg avatar sdrdis avatar taiyoh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jugglingdb's Issues

Memory Leak - constructor.cache

Items that get stored in constructor.cache do not ever seem to be freed up. Is there a way to make this an LRU cache with a fixed size?

Update attributes and hooks is not working properly

There are really 2 problems right now with the update attribute hooks:

  • There are no "save" hooks called prior to the "update" hooks
  • The attributes changed within the hooks are not saved as part of the update attribute call. This is because update attributes only saves the attributes passed in in the parameters. So changing the model directly (either changed attributes or not) will not change what is saved.

find sometimes returns an object without an id

Hi,

What I have experienced recently is that sometimes after updateAttributes(), find() returns an object by id, but there is no id element in it (so this property is undefined). This ends up interfering with the code, so I ended up assigning id explicitly in the callback:

7 before 'load role', ->
8 console.log "Looking up role id : " + params.id
9 Role.find params.id, (err, role) =>
10 if err
11 redirect path_to.admin_roles
12 else
13 role.id = params.id
14 @ROLE = role
15 console.log "Here it is : "
16 console.log JSON.stringify @ROLE
17 ## also load role privileges
18 role.privileges (err, privileges) =>
19 if err
20 redirect path_to.admin_roles
21 else
22 @roleprivileges = privileges
23 @roleprIDs = privileges.map (el) -> el.id
24 next()
25 , only: ['show', 'edit', 'update', 'destroy']

One scenario when this happens is in the standard crud generation rw g crud post title content --tpl jade, then rw server 8888, then create a post, then click edit, then update post, then edit again.

I do not know why sometimes find does not return id with the object, I am having trouble recreating this in rw console.

Thanks.

how to define a embedded mongodb schema?

friends = {
 tom:{name:'tom',height:180},
 john:{name:'john',height:189},
}

how to define the schema?

like bellow is wrong:

define('Musers', function(){
    property('id', Number);
    property('friends', []); 
});

Save and create callbacks have different behaviors

It seems that create callback is:

User.create({...}, function(err, user){});

and save callback is

User.save(function(err){});

and is not bound to the object.

I would stick with one or the other. My preference is to use an explicit argument like create to pass the object to the callback.

Should be a pretty small change.

Support client pooling

Not using pooling is inefficient since (at least with node-postgres) queries will be executed serially and not concurrently. It also breaks transactions, because different requests could cause commands to mix within a transaction.

New setter/getter issue

Setter does not get called before User.create, it oly gets called on an update.

User.setter.password = function (pwd) {    
    this.salt = salt;
    this._password = calcHash(pwd, salt);
};

function calcHash(pass, salt) {   
    var hash = crypto.createHash('sha256');
    hash.update(pass);
    hash.update(salt);
    return hash.digest('base64');
}

The password setter only gets executed with the update event but not with the create event.

Thank you!
JB

Inheritance

It seems that it is not possible to do a simple inheritance on models. Let's say I have a model called Transaction and want to create a FreeTransaction sub model. Simple prototyping inheritence does not seem to work. I narrowed it down to the use of constructor to store schema dependent object (_validations, schema, modelName, etc).

How would you do this inheritence?

Validation is synchronous

Currently the validation is synchronous and it fails when trying to check against an async resource (most notably the db...).

I was implementing a new uniqueness check and my tests were failing on this. The problem is bigger than it seems because isValid is used liberally throughout the code and mostly in conditions (making it difficult to just add a callback and move the next code within).

Any custom validator accessing an async data will have the same problem and without changing the way validation is handled within juggling it would be difficult to implement.

Add transaction support

This needs issue #65 to be fixed first.

For this to happen we need a client pool that allows clients to be marked as non-reclaimable (node-postgres can do this), and "lock" the client for the duration of the transaction block. This would probably require a way to pass a client instance (which was generated at init-transaction time) to the query functions, and a callback to mark the transaction as done.

Postgres .find doesn't work

Using any of my models, I can use findOne but not find.

Example:

#define
User = pg_db.define('User', {
    name: { type: String, length: 255 }
    username: { type: String, length: 255 }
    token:  { type: String, length: 255 }
    email:  { type: String, length: 255 }
  }, {table: 'users'})


User.find {where: {name: 'name'}},(err,users)->
  if err?
    console.log err

Gives me:

{ [error: syntax error at or near "["]
  length: 83,
  name: 'error',
  severity: 'ERROR',
  code: '42601',
  detail: undefined,
  hint: undefined,
  position: '46',
  internalPosition: undefined,
  internalQuery: undefined,
  where: undefined,
  file: 'scan.l',
  line: '1001',
  routine: 'scanner_yyerror' }

Synchronous Access

Why can't I call a find synchronously?

given the example from the readme:
Post.all({where: {userId: user.id}, order: 'id', limit: 10, skip: 20});

I have
User.all({where: {session: req.session.user_token}})

I get:
DEBUG: cb(err, collection);
^

DEBUG: TypeError: object is not a function
at Object.CALL_NON_FUNCTION (native)

And yes I realize that sync can be a bad idea, but how else am I to render my view? Using express.js as a web server backend.

belongsTo not working properly on mongoose

Database: Mongoose.
Schema has this relationship:
PersonInfo.belongsTo User, {as: 'user', foreignKey: 'personinfoId'}

and this is a code snippet
...
userdata.save () ->
userdata.user user
user.save () ->
promise.fulfill user
...

personinfoId field in User remains empty, and user() getter function does not work. This is remedied by explicitly assigning

userdata.save () ->
user.personinfoId = userdata.id
user.save () ->
promise.fulfill user

but then it seems that user() helper functionality is broken. Thanks.

Tests failing for redis

I got a failed test redis for the string "should find filtered set of records". The complete stack trace is:

AssertionError: false == true
at Object.ok (/usr/local/lib/node_modules/nodeunit/lib/types.js:83:39)
at /projects/jugglingdb/test/common_test.js:324:18
at /projects/jugglingdb/lib/abstract-class.js:214:13
at /projects/jugglingdb/lib/adapters/redis.js:158:13
at /projects/jugglingdb/node_modules/redis/index.js:922:13
at try_callback (/projects/jugglingdb/node_modules/redis/index.js:466:9)
at RedisClient.return_reply (/projects/jugglingdb/node_modules/redis/index.js:503:13)
at RedisReplyParser. (/projects/jugglingdb/node_modules/redis/index.js:259:14)
at RedisReplyParser.emit (events.js:64:17)
at RedisReplyParser.add_multi_bulk_reply (/projects/jugglingdb/node_modules/redis/lib/parser/javascript.js:306:18)

Migrations in Postgres

I'm trying to do a migration for postgres (new or existing table) and it doesn't seem to work. I can run queries fine, just no migration. Code follows:

conString = 'postgres://user:pass@localhost:5432/test'
jugglingdb = require('jugglingdb')
Schema = jugglingdb.Schema
pg_db = new Schema('postgres', { 'url': conString })

# Question model
Question = pg_db.define('Question', {
    text:   { type: String, length: 255 }
}, {table: 'questions'})
Question.validatesPresenceOf('text')

if !pg_db.isActual()
        console.log 'migrating datatables'
        pg_db.autoupdate (err) -> 
            if err?
                console.log 'error during migration '+err
            else
                console.log 'migration successful'

Log output

migrating datatables
DEBUG: TypeError: Object #<Object> has no method 'table'
    at /Users/casey/Documents/siide_learn/node_modules/jugglingdb/lib/adapters/postgres.js:277:176
    at Array.forEach (native)
    at PG.autoupdate (/Users/casey/Documents/siide_learn/node_modules/jugglingdb/lib/adapters/postgres.js:275:31)

Querying multiple tables

JOINs and the like, generating the appropriate objects whenever necessary (ie, querying a Post joining with Author should give me a User object with an author attribute (or whatever is the foreignkey attribute, minus the '_id' part) which contains an Author object).

Query building

Building queries through an interface leads to more portable code, since the interface can abstract all the differences.

Something like

query.select(['id','name']).from('user').where({age: 20}).sql(); // with chaining!

This is similar to what can be found in PHP-land with CodeIgniter or Symfony.

Allow models to explicitly set their table name

Working with legacy data is difficult. I have a 'user' table and want a User model. But there appears to be no way to tell Juggling to map one to the other. It appears currently that the model name is used as the table name.

postgres adapter - queries run multiple times

Consider code:

var jugglingdb = require('jugglingdb')
  , Schema = jugglingdb.Schema
  , accountingUrl = 'tcp://user:password@localhost/database'
  , accountingDb = exports.accountingDb = new Schema('postgres', { 'url': accountingUrl });

var Ledger = exports.Ledger = accountingDb.define('ledger', {
  'id':             { 'type': String, 'length': 32, 'autoIncrement': true },
  'name':           { 'type': String, 'length': 35 },
  'desc':           { 'type': Schema.Text, 'length': 500 },
  'createdOn':      { 'type': Date, 'autoIncrement': true },
});

Ledger.create({name: 'General Ledger' }, function (err) {
  console.log(arguments);
});

For some reason the SQL is cycling twice to the database, and it's three times for .save() I think. The same also applies to .all({}) queries. Not sure what would cause this, but if I run into the cause and I can fix it I'll patch it up.

Documentation Improvement

Heyo,

I just spent some time struggling getting data from my db using jugglingdb, and finally realized that my callback needed to an error param before the data param. I know that many things in node work this way, but I think having a prominent example of a callback in the documentation would be pretty awesome for NOOBs like myself. I would be happy to add it myself if that would be helpful. Let me know.
Best,

Neo4j adapter not finished?

I'm not sure if this is documented somewhere, but it seems that the neo4j adapter is not actually complete yet.

You can call methods on the adapter itself (through the mixin methods) and those actually take advantage of Neo4j's relationship model. However, if you use the hasMany type helpers it doesn't work properly and instead tries to create and query by node attributes such as it would with Mongo or Redis.

I'm not sure if the architecture allows us to customize the way these helpers work so that we can take advantage of Neo4j's strengths?

sequelize (and probably other adapters) not working anymore

Hello,

sequelize currently (version": "1.3.7") doesn't provide a "initialize" function, which leads to the following error:

node.js:201
        throw e; // process.nextTick error, or 'error' event on first tick
              ^
TypeError: Object function (database, username, password, options) {
    this.options = Utils._.extend({
      dialect: 'mysql',
      host: 'localhost',
      port: 3306,
      define: {},
      query: {},
      sync: {}
    }, options || {})

    this.config = {
      database: database,
      username: username,
      password: (( (["", null, false].indexOf(password) > -1) || (typeof password == 'undefined')) ? null : password),
      host    : this.options.host,
      port    : this.options.port
    }

    var ConnectorManager = require("./dialects/" + this.options.dialect + "/connector-manager")

    this.daoFactoryManager     = new DAOFactoryManager(this)
    this.connectorManager = new ConnectorManager(this, this.config)
  } has no method 'initialize'
    at new Schema (MYDEVDIR\node_modules\jugglingdb\lib\schema.js:72:13)
    at Object.<anonymous> (MYDEVDIR\node_modules\jugglingdb\lib\railway.js:21:14)
    at Module._compile (module.js:441:26)
    at Object..js (module.js:459:10)
    at Module.load (module.js:348:31)
    at Function._load (module.js:308:12)
    at Module.require (module.js:354:17)
    at require (module.js:370:17)
    at Object.init (MYDEVDIR\node_modules\jugglingdb\index.js:11:5)
    at MYDEVDIR\node_modules\railway\lib\extensions.js:38:17

My first workaround was to write an adapter for jugglingdb, but i think this is not really what was intended in the example on the website.

The rootcause is to be found in "lib/schema.js" where "adapter.initialize" is called. As this initialization should be done in the custom schema (as this is a custom adapter), i'm a little confused there?

Does this simply not work anymore with sequelize?

Best Regards,
Uli

wrong belongsTo behavior when using with postgresql

I have this schema definition

var Domain = schema.define('domain', {
  name: Number
});

var User = schema.define('user', {
  email: String
});

Domain.belongsTo(User, {as: 'user', foreignKey : 'user_id'});
User.hasMany(Domain, {as : 'domains', foreignKey: 'user_id'});

Then I created some domains and add them to a particular user. I have checked the database and everything is ok.

Then, I do

domain.user(); // It can get the user id

However if I do something like this

domain.user(function(error, user){
  // user should be a user record ?
});

I got this error

TypeError: Object #<Object> has no method 'find'
    at Object.domain (/home/vagrant/lib/node_modules/jugglingdb/lib/abstract-class.js:690:22)
    at ModelConstructor.domain (/home/vagrant/lib/node_modules/jugglingdb/lib/abstract-class.js:705:40)

I am using postgresql 9.1 on Ubuntu 11.10.

Fix results of zero-argument call to hasMany relationship

Currently, an error is thrown ("Method only can be called with one or two arguments") when you try to call a hasMany without arguments. This is quite unintuitive.

If I have a User model that hasMany Post (as 'posts'), calling user.posts() seems like it should return all of the user's posts. My guess is that this is merely a factor of Juggling's newness but it does seem like it should work as expected.

I actually can't figure out how to synchronously load the related posts using user.posts. The posts object/function has the _scope property and there's a find property (that has a find and destroy method...?) but I can get no combination to work.

"greater/less than" queries

More of a discussion topic than an issue.
I notice that there is no support for advanced queries such as filtering where a specific column is greater/less than, and I appreciate your reasoning for this (issue #2 #2).

But this made me curious, is there any way to achieve the same effect without taking a large performance hit?

So let's take a simple django query that gets posts with pub_date >= someDate:
Post.objects.filter(pub_date__gte=someDate)

What would be the most efficient way to achieve the same effect when such queries aren't available?
Or would you tackle this issue in an entirely different manner?
Would needing this simply mean the application calls for a DBMS that supports this type of query?

Sorry if creating an issue is inappropriate for this, let me know if that is the case. Thanks

Howto for hooking beforeUpdate/beforeCreate/beforeSave etc.

Hi,

could you please explain how to use those hooking functionalities?

Do I have to use it like that:

var foo = schema.define('foo', {
  bar: String
});

foo.beforeSave = function(fooInstance) {
  fooInstance.bar = fooInstance.bar + 'foobar';
}

Also I'm interested in hearing how the three mentioned correlate with each other.. Is some e.g. beforeSave also called when updating/creating a row?

Thanks,
Michael

Dirty state overridden by validatesUniquenessOf

The dirty state of the object you are trying to save is overridden when using the validatesUniquenessOf validation. The code queries the DB but the implementation of a trivial identity map is overwriting the previous object data (which is pretty bad because you most likely validate when you are trying to save a dirty state).

From @1602 own comments in AbstractClass.all function:

 // really questionable stuff
 // goal is obvious: to not create different instances for the same object
 // but the way it implemented...
 // we can lost some dirty state of object, for example
 // TODO: think about better implementation, test keeping dirty state

I think it might just be my error right now :P

Redis with Authentication

Trying to connect to redistogo on heroku and I can't seem to get it.

new Schema 'redis', { host: 'guppy.redistogo.com',
port: '9306',
username: 'redistogo',
password: 'pass' }

This gives me:

2012-04-11T20:45:59+00:00 app[web.1]: node.js:201
2012-04-11T20:45:59+00:00 app[web.1]:         throw e; // process.nextTick error, or 'error' event on first tick
2012-04-11T20:45:59+00:00 app[web.1]: Error: Uncaught, unspecified 'error' event.
2012-04-11T20:45:59+00:00 app[web.1]:               ^
2012-04-11T20:45:59+00:00 app[web.1]:     at RedisClient.emit (events.js:50:15)
2012-04-11T20:45:59+00:00 app[web.1]:     at Command.callback (/app/node_modules/redis/index.js:322:14)
2012-04-11T20:45:59+00:00 app[web.1]:     at RedisClient.return_error (/app/node_modules/redis/index.js:446:25)
2012-04-11T20:45:59+00:00 app[web.1]:     at RedisClient.on_info_cmd (/app/node_modules/redis/index.js:271:21)
2012-04-11T20:45:59+00:00 app[web.1]:     at RedisReplyParser.<anonymous> (/app/node_modules/redis/index.js:256:14)
2012-04-11T20:45:59+00:00 app[web.1]:     at RedisReplyParser.emit (events.js:67:17)
2012-04-11T20:45:59+00:00 app[web.1]:     at RedisReplyParser.send_error (/app/node_modules/redis/lib/parser/javascript.js:266:14)
2012-04-11T20:45:59+00:00 app[web.1]:     at RedisReplyParser.execute (/app/node_modules/redis/lib/parser/javascript.js:125:22)
2012-04-11T20:45:59+00:00 app[web.1]:     at RedisClient.on_data (/app/node_modules/redis/index.js:422:27)
2012-04-11T20:45:59+00:00 app[web.1]:     at Socket.<anonymous> (/app/node_modules/redis/index.js:66:14)

And using the url:

new Schema 'redis', { url: 'redis://redistogo:[email protected]:9306/' }

And I get:

Error: Redis connection to 127.0.0.1:6379 failed - connect ECONNREFUSED

Manuals...

Am I missing them or they are non existant?

Model.all() can't return values directly to another function outside scope

Model.all(function(err, objects){
objects.forEach(function(object){
console.log(object.property);
});
});

I can acess object.property inside scope of Model.all(), but to acess value outside scope I need to use a global variable, like this:

value = 0;

Model.all(function(err, objects){
objects.forEach(function(object){
value = object.property;
});
});

function showValue(){
return value;
}

If I try to use Model.all inside a model(instead controller or view), I can't do this:

Model.showValue = function showValue(){
value = 0;
Model.all(function(err, objects){
objects.forEach(function(object){
value = object.property;
});
return value;
});
}

Model.showValue returns always 0, instead object.property.

Maybe Model.all() could return objects values, like this:

var value = Model.all(callback);

Just an idea... probably I'm wrong

mongoose adapter: cannot specify sort direction


MongooseAdapter.prototype.all = function all(model, filter, callback) {
   ...
    if (filter.order) {
        query.asc(filter.order); //direction is hardcoded
    }
    ...
};

is there an easy way to patch this issue and define findOne method?

Thanks

updateAttributes not working properly on Mongoose

There was an issue before about Boolean type not updating properly. In addition to that, even String type does not update consistently.

For example, we want to update one field F1. It is not updated unless in addition to F1 we make a dummy change to at least one another field (for example, F2). For some fields such trick is not necessary, for some you need it.

I am having trouble determining what is the reason behind this kind of behavior. Would be great if you could shed some light on this.

All fields are String, database is Mongoose. Thank you.

multiple namespace/schema support

Some db layouts may require the app to access tables in more than one schema, therefore jugglingdb should support specifying which namespace a model belongs to.

uniqueness validator loses changed properties

Hello.

I encountered a problem when

var Clip = describe('Clip', function () {
    property('name',String,{index:true});
    property('pubdate',Date,{index:true});
});
Clip.validatesPresenceOf('name',{message:'name cannot be blank'});
Clip.validatesUniquenessOf('name',{message:'name must be unique'});

On create, everything works perfectly but on updating pubdate and calling clip.updateAttributes(), juggling fails to update the value in the database.

I am using the mongoose adapter so this might be specific to it, but I strongly suspect it's a more generic issue.

In lib/validatable.js on or about line 76, the uniqueness validator is defined as:

    uniqueness: function (attr, conf, err, done) {
        var cond = {where: {}};
        cond.where[attr] = this[attr];
        this.constructor.all(cond, function (error, found) {
            if (found.length > 1) {
                err();
            } else if (found.length === 1 && found[0].id !== this.id) {
                err();
            }
            done();
        }.bind(this));
    }

The issue occurs when calling this.constructor.all() which appears to overwrite some(?) properties in the validating object; I suspect this is related to database object caching.

I'm sure there's a more node-ish idiom for implementing a fix, but here's my contribution:

uniqueness: function (attr, conf, err, done) { // 20120224 RR
        var orig=this.toObject(), // needed to preserve original props
            cond = {where: {}};
        cond.where[attr] = this[attr];
        this.constructor.all(cond, function (error, found) {
            if (found.length > 1) {
                err();
            } else if (found.length === 1 && found[0].id !== this.id) {
                err();
            }
            for(var k in orig) { // since this.constructor.all() scribbles on this,
                this[k]=orig[k]; // we need to copy back any changed props
            }
            done();

        }.bind(this));
    }

All best.

/rr

'is blank' error message

I am trying to remove the 'is blank' message or at least customize it.

I am having this validation rule

Domain.validatesPresenceOf('name', {
  message : 'Domain name must be provided'
});

But then when doing validation, I got

{ name: [ 'Domain name must be provided', 'is blank' ] }

Is it possible to configure the 'is blank' message ? Or remove it ?

Enhancement: Multiple records on insert()

Basically this is a non-issue, but would be a nice feature. If I could save multiple rows at once via an array (which with any good luck will run as a single transaction, depending on the driver), it would be useful.

Consider code:

var acc = require('./accounting'); //this has all the model stuff in it
acc.Ledger.create({name: 'General Ledger' }, function (err) {
  //debug: console.log(arguments);
  if (!err)
    console.log('Saved General Ledger');
  else if (err.code == '23505')
    console.log('General Ledger already exists');
  else {
    console.log('Error:', err.detail);
    return
  }
  //get general ledger
  acc.Ledger.all({ 'where': { 'name': 'General Ledger' }}, function (err, docs){
    if (err)
      console.log('Error:', err.detail);
    else {
      var genleg = docs[0];
      //this works:
      /*genleg.accounts.create({
          name: 'Assets'
        , baseType: 'Asset'
        , direction: 'debit'
        }, function (err, docs) {
          console.log(arguments);
      });*/
      //this fails:
      genleg.accounts.create(
        [
          {
            name: 'Assets'
          , baseType: 'Asset'
          , direction: 'debit'
          },
          {
            name: 'Liabilities'
          , baseType: 'Liability'
          , direction: 'credit'
          },
          {
            name: 'Equities'
          , baseType: 'Equity'
          , direction: 'credit'
          },
        ],
        function (err, docs) {
          console.log(arguments);
      });
    }
  });
});

The error provided is:

null value in column "name" violates not-null constraint

The error was probably due to the fact that it's looking for array['name'] but it doesn't exist (expected). So in order to permit this, some type of loop must be executed, either to devise multiple queries or to create a compound query, depending on each driver. You can figure out whether you have an array or not this way:

if (typeof objInput == 'object')
  if (objInput instanceof Object)
   //do this
  else if (objInput instanceof Array)
   //do that

After figuring out if it's an array or object, you could do one of two things. Split the code path as in above, or my favorite, force it to become an array and store the non-array in the first index. So:

if (typeof objInput == 'object' && objInput.prototype instanceof Array)
  //if not an array, make it an array
  objInput = [ objInput ];
for (var obj in objInput)
  //either run multiple single queries or
  //formulate a good INSERT ('A','B','C') VALUES( (1,2,3), (2,3,4) ) plan to run the query following the loop

Thanks, but I still haven't looked over the code enough to be comfortable butchering the code. I think you'll find this to be a useful feature as well, although it would probably require changes to every driver :~.

For my purposes of testing, I've been using postgres for this exercise. This may actually already exist in other drivers, as I haven't tested anything other than postgres.

Thanks,
David

CouchDB adapter

Hello everyone, did someone started implementing a couchDB adapter?

recursive belongsTo

Not sure if this should work... but if I want a parent-child relation on the same collection, it seems to generate non-functional convenience methods.

Example:

var Topics = describe('Topic', function () {
property('name', String);
});
Topics.hasMany(Topic, {as: 'subtopic', foreignKey:'topicId'});
Topics.belongsTo(Topic, {as: 'parentTopic', foreignKey:'topicId'});

if eventually I try to do

subtopic.parentTopic() I get nothing in return.

if I try:

topic.subtopics(callback) I get every topic in existence.

Support prepared statements

Escaping user input is error prone and boring. We should just let the database handle those whenever possible.

beforeCreate hooks does not appear to work

This issue is migrated from the Google group....

I have the following in the model/facility.js file:

Facility.beforeCreate = createTimeStamp;

function createTimeStamp(done) {
  this.date_created = (new Date()) - 0;
  this.date_updated = (new Date()) - 0;
  console.log('JKL: Inside createTimeStamp');
  done();

};

I can see that the trigger is fired, i.e. the "JKL: Inside create TimeStamp" is showing in the console. But there is no value in the db table stored when I click on the Create Facility button. But all the other data columns have data except the date_created and date_updated column. So it either appears that the beforeCreate hook is fired, but the data are override in the ORM level.

I have added a console.log message in my sqlite3.js file in the adapter and in the AbstractClass.create() to see the data being passed into these routines and these two columns have no data in both cases.

I am using the scaffolding controller code. So it is using the .create() method to create the data in the database.

My _form.ejs for these two fields are "hidden", i.e. I am using the following:

<div class="controls">
     <%- form.input("date_updated", {type: "hidden"}) %>
</div>

But they exist in the html page generated. I have also tried to display them and in both cases, the date_created and date_updated field in the db have null value in it.

But the beforeUpdate hook works normally.

Let me know if this is something that I miss or something the framework will need to be updated. Thanks.

Natural Keys?

Is there (or could there be) a way to use natural keys instead of whatever the default key is (eg ObjIds for mongo)?

ManyToMany

Hi,

I am working on user authentication code, and the idea is that every user has a role, and every role has privileges. Each role corresponds to a collection of privileges. Each privilege may be in more than one role.

This is a use case of manyToMany I think. Is there a way to implement something like this with jugglingDB?

It seems that jugglingDB now only has oneToOn and oneToMany, and does not have manyToMany. Please let me know if I am not correct. Would be great if you could suggest a way to go about using the relationship.

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.