diff --git a/Readme.md b/Readme.md
index 06152fa2..606d70fe 100755
--- a/Readme.md
+++ b/Readme.md
@@ -1,830 +1,36 @@
-## Object Relational Mapping
+###Bug-fix patch for [dresende/node-orm2](https://github.com/dresende/node-orm2) v2.1.3
-[](http://travis-ci.org/dresende/node-orm2)
-[](https://npmjs.org/package/orm)
-[](https://gemnasium.com/dresende/node-orm2)
-[](https://flattr.com/submit/auto?user_id=dresende&url=https://github.com/dresende/node-orm2&title=ORM&language=&tags=github&category=software)
+##Details
-## Install
+Mysql only
-```sh
-npm install orm
-```
+Using "unique: true" causes "ER_DUP_KEYNAME" on sync: [here](https://github.com/dresende/node-orm2/issues/326)
-## Node.js Version Support
+I just do this for easier on npm deployment.
-Tests are done using [Travis CI](https://travis-ci.org/) for node versions `0.6.x`, `0.8.x` and `0.10.x`. If you want you can run
-tests locally.
+##Installation
-```sh
-npm test
-```
+ npm install orm-2.1.3
-## DBMS Support
+##License
+The MIT License (MIT)
-- MySQL
-- PostgreSQL
-- Amazon Redshift
-- SQLite
-- MongoDB (beta, missing aggregation for now)
+Copyright (c) 2013 Diogo Resende and other contributors
-## Features
+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:
-- Create Models, sync, drop, bulk create, get, find, remove, count, aggregated functions
-- Create Model associations, find, check, create and remove
-- Define custom validations (several builtin validations, check instance properties before saving - see [enforce](http://github.com/dresende/node-enforce) for details)
-- Model instance caching and integrity (table rows fetched twice are the same object, changes to one change all)
-- Plugins: [MySQL FTS](http://dresende.github.io/node-orm-mysql-fts) , [Pagination](http://dresende.github.io/node-orm-paging) , [Transaction](http://dresende.github.io/node-orm-transaction), [Timestamps](http://github.com/SPARTAN563/node-orm-timestamps), [Migrations](https://github.com/locomote/node-migrate-orm2)
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
-## Introduction
-
-This is a node.js object relational mapping module.
-
-An example:
-
-```js
-var orm = require("orm");
-
-orm.connect("mysql://username:password@host/database", function (err, db) {
- if (err) throw err;
-
- var Person = db.define("person", {
- name : String,
- surname : String,
- age : Number,
- male : Boolean,
- continent : [ "Europe", "America", "Asia", "Africa", "Australia", "Antartica" ], // ENUM type
- photo : Buffer, // BLOB/BINARY
- data : Object // JSON encoded
- }, {
- methods: {
- fullName: function () {
- return this.name + ' ' + this.surname;
- }
- },
- validations: {
- age: orm.enforce.ranges.number(18, undefined, "under-age")
- }
- });
-
- Person.find({ surname: "Doe" }, function (err, people) {
- // SQL: "SELECT * FROM person WHERE surname = 'Doe'"
-
- console.log("People found: %d", people.length);
- console.log("First person: %s, age %d", people[0].fullName(), people[0].age);
-
- people[0].age = 16;
- people[0].save(function (err) {
- // err.msg = "under-age";
- });
- });
-});
-```
-
-## Express
-
-If you're using Express, you might want to use the simple middleware to integrate more easily.
-
-```js
-var express = require('express');
-var orm = require('orm');
-var app = express();
-
-app.use(orm.express("mysql://username:password@host/database", {
- define: function (db, models, next) {
- models.person = db.define("person", { ... });
- next();
- }
-}));
-app.listen(80);
-
-app.get("/", function (req, res) {
- // req.models is a reference to models used above in define()
- req.models.person.find(...);
-});
-```
-
-You can call `orm.express` more than once to have multiple database connections. Models defined across connections
-will be joined together in `req.models`. **Don't forget to use it before `app.use(app.router)`, preferably right after your
-assets public folder(s).**
-
-## Examples
-
-See `examples/anontxt` for an example express based app.
-
-## Documentation
-
-Documentation is moving to the [wiki](https://github.com/dresende/node-orm2/wiki/).
-
-## Settings
-
-See information in the [wiki](https://github.com/dresende/node-orm2/wiki/Settings).
-
-## Connecting
-
-See information in the [wiki](https://github.com/dresende/node-orm2/wiki/Connecting-to-Database).
-
-## Models
-
-A Model is an abstraction over one or more database tables. Models support associations (more below). The name of the model is assumed to match the table name.
-
-Models support behaviours for accessing and manipulating table data.
-
-## Defining Models
-
-See information in the [wiki](https://github.com/dresende/node-orm2/wiki/Defining-Models).
-
-### Properties
-
-See information in the [wiki](https://github.com/dresende/node-orm2/wiki/Model-Properties).
-
-### Instance Methods
-
-Are passed in during model definition.
-
-```js
-var Person = db.define('person', {
- name : String,
- surname : String
-}, {
- methods: {
- fullName: function () {
- return this.name + ' ' + this.surname;
- }
- }
-});
-
-Person.get(4, function(err, person) {
- console.log( person.fullName() );
-})
-```
-
-### Model Methods
-
-Are defined directly on the model.
-
-```js
-var Person = db.define('person', {
- name : String,
- height : { type: 'number', rational: false }
-});
-Person.tallerThan = function(height, callback) {
- this.find({ height: orm.gt(height) }, callback);
-};
-
-Person.tallerThan( 192, function(err, tallPeople) { ... } );
-```
-
-
-## Loading Models
-
-Models can be in separate modules. Simply ensure that the module holding the models uses module.exports to publish a function that accepts the database connection, then load your models however you like.
-
-Note - using this technique you can have cascading loads.
-
-```js
-// your main file (after connecting)
-db.load("./models", function (err) {
- // loaded!
- var Person = db.models.person;
- var Pet = db.models.pet;
-});
-
-// models.js
-module.exports = function (db, cb) {
- db.load("./models-extra", function (err) {
- if (err) {
- return cb(err);
- }
-
- db.define('person', {
- name : String
- });
-
- return cb();
- });
-};
-
-// models-extra.js
-module.exports = function (db, cb) {
- db.define('pet', {
- name : String
- });
-
- return cb();
-};
-```
-
-## Synchronizing Models
-
-See information in the [wiki](https://github.com/dresende/node-orm2/wiki/Synching-and-Dropping-Models).
-
-## Dropping Models
-
-See information in the [wiki](https://github.com/dresende/node-orm2/wiki/Synching-and-Dropping-Models).
-
-## Advanced Options
-
-ORM2 allows you some advanced tweaks on your Model definitions. You can configure these via settings or in the call to `define` when you setup the Model.
-
-For example, each Model instance has a unique ID in the database. This table column is
-by default "id" but you can change it.
-
-```js
-var Person = db.define("person", {
- name : String
-}, {
- id : "person_id"
-});
-
-// or just do it globally..
-db.settings.set("properties.primary_key", "UID");
-
-// ..and then define your Models
-var Pet = db.define("pet", {
- name : String
-});
-```
-
-**Pet** model will have 2 columns, an `UID` and a `name`.
-
-It is also possible to have multiple IDs for a model in the database, this is done by specifying an array of IDs to use.
-
-```js
-var Person = db.define("person", {
- firstname: String,
- lastname: String
-}, {
- id: ['firstname', 'lastname']
-});
-```
-
-Other options:
-
-- `cache` : (default: `true`) Set it to `false` to disable Instance cache ([Singletons](#singleton)) or set a timeout value (in seconds);
-- `autoSave` : (default: `false`) Set it to `true` to save an Instance right after changing any property;
-- `autoFetch` : (default: `false`) Set it to `true` to fetch associations when fetching an instance from the database;
-- `autoFetchLimit` : (default: `1`) If `autoFetch` is enabled this defines how many hoops (associations of associations)
- you want it to automatically fetch.
-
-## Hooks
-
-See information in the [wiki](https://github.com/dresende/node-orm2/wiki/Model-Hooks).
-
-## Finding Items
-
-### Model.get(id, [ options ], cb)
-
-To get a specific element from the database use `Model.get`.
-
-```js
-Person.get(123, function (err, person) {
- // finds person with id = 123
-});
-```
-
-### Model.find([ conditions ] [, options ] [, limit ] [, order ] [, cb ])
-
-Finding one or more elements has more options, each one can be given in no specific parameter order. Only `options` has to be after `conditions` (even if it's an empty object).
-
-```js
-Person.find({ name: "John", surname: "Doe" }, 3, function (err, people) {
- // finds people with name='John' AND surname='Doe' and returns the first 3
-});
-```
-
-If you need to sort the results because you're limiting or just because you want them sorted do:
-
-```js
-Person.find({ surname: "Doe" }, "name", function (err, people) {
- // finds people with surname='Doe' and returns sorted by name ascending
-});
-Person.find({ surname: "Doe" }, [ "name", "Z" ], function (err, people) {
- // finds people with surname='Doe' and returns sorted by name descending
- // ('Z' means DESC; 'A' means ASC - default)
-});
-```
-
-There are more options that you can pass to find something. These options are passed in a second object:
-
-```js
-Person.find({ surname: "Doe" }, { offset: 2 }, function (err, people) {
- // finds people with surname='Doe', skips the first 2 and returns the others
-});
-```
-
-You can also use raw SQL when searching. It's documented in the *Chaining* section below.
-
-### Model.count([ conditions, ] cb)
-
-If you just want to count the number of items that match a condition you can just use `.count()` instead of finding all
-of them and counting. This will actually tell the database server to do a count (it won't be done in the node process itself).
-
-```js
-Person.count({ surname: "Doe" }, function (err, count) {
- console.log("We have %d Does in our db", count);
-});
-```
-
-### Model.exists([ conditions, ] cb)
-
-Similar to `.count()`, this method just checks if the count is greater than zero or not.
-
-```js
-Person.exists({ surname: "Doe" }, function (err, exists) {
- console.log("We %s Does in our db", exists ? "have" : "don't have");
-});
-```
-
-### Aggregating Functions
-
-If you need to get some aggregated values from a Model, you can use `Model.aggregate()`. Here's an example to better
-illustrate:
-
-```js
-Person.aggregate({ surname: "Doe" }).min("age").max("age").get(function (err, min, max) {
- console.log("The youngest Doe guy has %d years, while the oldest is %d", min, max);
-});
-```
-
-An `Array` of properties can be passed to select only a few properties. An `Object` is also accepted to define conditions.
-
-Here's an example to illustrate how to use `.groupBy()`:
-
-```js
-//The same as "select avg(weight), age from person where country='someCountry' group by age;"
-Person.aggregate(["age"], { country: "someCountry" }).avg("weight").groupBy("age").get(function (err, stats) {
- // stats is an Array, each item should have 'age' and 'avg_weight'
-});
-```
-
-### Base `.aggregate()` methods
-
-- `.limit()`: you can pass a number as a limit, or two numbers as offset and limit respectively
-- `.order()`: same as `Model.find().order()`
-
-### Additional `.aggregate()` methods
-
-- `min`
-- `max`
-- `avg`
-- `sum`
-- `count` (there's a shortcut to this - `Model.count`)
-
-There are more aggregate functions depending on the driver (Math functions for example).
-
-#### Chaining
-
-If you prefer less complicated syntax you can chain `.find()` by not giving a callback parameter.
-
-```js
-Person.find({ surname: "Doe" }).limit(3).offset(2).only("name", "surname").run(function (err, people) {
- // finds people with surname='Doe', skips first 2 and limits to 3 elements,
- // returning only 'name' and 'surname' properties
-});
-```
-
-Chaining allows for more complicated queries. For example, we can search by specifying custom SQL:
-```js
-Person.find({ age: 18 }).where("LOWER(surname) LIKE ?", ['dea%']).all( ... );
-```
-It's bad practice to manually escape SQL parameters as it's error prone and exposes your application to SQL injection.
-The `?` syntax takes care of escaping for you, by safely substituting the question mark in the query with the parameters provided.
-You can also chain multiple `where` clauses as needed.
-
-You can also `order` or `orderRaw`:
-```js
-Person.find({ age: 18 }).order('-name').all( ... );
-// see the 'Raw queries' section below for more details
-Person.find({ age: 18 }).orderRaw("?? DESC", ['age']).all( ... );
-```
-
-You can also chain and just get the count in the end. In this case, offset, limit and order are ignored.
-
-```js
-Person.find({ surname: "Doe" }).count(function (err, people) {
- // people = number of people with surname="Doe"
-});
-```
-
-Also available is the option to remove the selected items.
-
-```js
-Person.find({ surname: "Doe" }).remove(function (err) {
- // Does gone..
-});
-```
-
-You can also make modifications to your instances using common Array traversal methods and save everything
-in the end.
-
-```js
-Person.find({ surname: "Doe" }).each(function (person) {
- person.surname = "Dean";
-}).save(function (err) {
- // done!
-});
-
-Person.find({ surname: "Doe" }).each().filter(function (person) {
- return person.age >= 18;
-}).sort(function (person1, person2) {
- return person1.age < person2.age;
-}).get(function (people) {
- // get all people with at least 18 years, sorted by age
-});
-```
-
-Of course you could do this directly on `.find()`, but for some more complicated tasks this can be very usefull.
-
-`Model.find()` does not return an Array so you can't just chain directly. To start chaining you have to call
-`.each()` (with an optional callback if you want to traverse the list). You can then use the common functions
-`.filter()`, `.sort()` and `.forEach()` more than once.
-
-In the end (or during the process..) you can call:
-- `.count()` if you just want to know how many items there are;
-- `.get()` to retrieve the list;
-- `.save()` to save all item changes.
-
-#### Conditions
-
-Conditions are defined as an object where every key is a property (table column). All keys are supposed
-to be concatenated by the logical `AND`. Values are considered to match exactly, unless you're passing
-an `Array`. In this case it is considered a list to compare the property with.
-
-```js
-{ col1: 123, col2: "foo" } // `col1` = 123 AND `col2` = 'foo'
-{ col1: [ 1, 3, 5 ] } // `col1` IN (1, 3, 5)
-```
-
-If you need other comparisons, you have to use a special object created by some helper functions. Here are
-a few examples to describe it:
-
-```js
-{ col1: orm.eq(123) } // `col1` = 123 (default)
-{ col1: orm.ne(123) } // `col1` <> 123
-{ col1: orm.gt(123) } // `col1` > 123
-{ col1: orm.gte(123) } // `col1` >= 123
-{ col1: orm.lt(123) } // `col1` < 123
-{ col1: orm.lte(123) } // `col1` <= 123
-{ col1: orm.between(123, 456) } // `col1` BETWEEN 123 AND 456
-{ col1: orm.not_between(123, 456) } // `col1` NOT BETWEEN 123 AND 456
-{ col1: orm.like(12 + "%") } // `col1` like '12%'
-```
-
-#### Raw queries
-
-```js
-db.driver.execQuery("SELECT id, email FROM user", function (err, data) { ... })
-
-// You can escape identifiers and values.
-// For identifier substitution use: ??
-// For value substitution use: ?
-db.driver.execQuery(
- "SELECT user.??, user.?? FROM user WHERE user.?? LIKE ? AND user.?? > ?",
- ['id', 'name', 'name', 'john', 'id', 55],
- function (err, data) { ... }
-)
-
-// Identifiers don't need to be scaped most of the time
-db.driver.execQuery(
- "SELECT user.id, user.name FROM user WHERE user.name LIKE ? AND user.id > ?",
- ['john', 55],
- function (err, data) { ... }
-)
-```
-
-### Caching & Integrity
-
-Model instances are cached. If multiple different queries will result in the same result, you will
-get the same object. If you have other systems that can change your database (or you're developing and need
-to make some manual changes) you should remove this feature by disabling cache. This can be done when you're
-defining the Model.
-
-```js
-var Person = db.define('person', {
- name : String
-}, {
- cache : false
-});
-```
-
-and also globally:
-
-```js
-orm.connect('...', function(err, db) {
- db.settings.set('instance.cache', false);
-});
-```
-
-The cache can be configured to expire after a period of time by passing in a number instead of a
-boolean. The number will be considered the cache timeout in seconds (you can use floating point).
-
-**Note**: One exception about Caching is that it won't be used if an instance is not saved. For example, if
-you fetch a Person and then change it, while it doesn't get saved it won't be passed from Cache.
-
-## Creating Items
-
-### Model.create(items, cb)
-
-To insert new elements to the database use `Model.create`.
-
-```js
-Person.create([
- {
- name: "John",
- surname: "Doe",
- age: 25,
- male: true
- },
- {
- name: "Liza",
- surname: "Kollan",
- age: 19,
- male: false
- }
-], function (err, items) {
- // err - description of the error or null
- // items - array of inserted items
-});
-```
-
-## Updating Items
-
-Every item returned has the properties that were defined to the Model and also a couple of methods you can
-use to change each item.
-
-```js
-Person.get(1, function (err, John) {
- John.name = "Joe";
- John.surname = "Doe";
- John.save(function (err) {
- console.log("saved!");
- });
-});
-```
-
-Updating and then saving an instance can be done in a single call:
-
-```js
-Person.get(1, function (err, John) {
- John.save({ name: "Joe", surname: "Doe" }, function (err) {
- console.log("saved!");
- });
-});
-```
-
-If you want to remove an instance, just do:
-
-```js
-// you could do this without even fetching it, look at Chaining section above
-Person.get(1, function (err, John) {
- John.remove(function (err) {
- console.log("removed!");
- });
-});
-```
-
-## Validations
-
-See information in the [wiki](https://github.com/dresende/node-orm2/wiki/Model-Validations).
-
-## Associations
-
-An association is a relation between one or more tables.
-
-### hasOne
-
-Is a **many to one** relationship. It's the same as **belongs to.**
-Eg: `Animal.hasOne('owner', Person)`.
-Animal can only have one owner, but Person can have many animals.
-Animal will have the `owner_id` property automatically added.
-
-The following functions will become available:
-```js
-animal.getOwner(function..) // Gets owner
-animal.setOwner(person, function..) // Sets owner_id
-animal.hasOwner(function..) // Checks if owner exists
-animal.removeOwner() // Sets owner_id to 0
-```
-
-**Chain Find**
-
-The hasOne association is also chain find compatible. Using the example above, we can do this to access a new instance of a ChainFind object:
-
-```js
-Animal.findByOwner({ /* options */ })
-```
-
-**Reverse access**
-
-```js
-Animal.hasOne('owner', Person, {reverse: 'pets'})
-```
-
-will add the following:
-
-```js
-// Instance methods
-person.getPets(function..)
-person.setPets(cat, function..)
-
-// Model methods
-Person.findByPets({ /* options */ }) // returns ChainFind object
-```
-
-### hasMany
-
-Is a **many to many** relationship (includes join table).
-Eg: `Patient.hasMany('doctors', Doctor, { why: String }, { reverse: 'patients' })`.
-Patient can have many different doctors. Each doctor can have many different patients.
-
-This will create a join table `patient_doctors` when you call `Patient.sync()`:
-
- column name | type
- :-----------|:--------
- patient_id | Integer
- doctor_id | Integer
- why | varchar(255)
-
-The following functions will be available:
-
-```js
-patient.getDoctors(function..) // List of doctors
-patient.addDoctors(docs, function...) // Adds entries to join table
-patient.setDoctors(docs, function...) // Removes existing entries in join table, adds new ones
-patient.hasDoctors(docs, function...) // Checks if patient is associated to specified doctors
-patient.removeDoctors(docs, function...) // Removes specified doctors from join table
-
-doctor.getPatients(function..)
-etc...
-```
-
-To associate a doctor to a patient:
-
-```js
-patient.addDoctor(surgeon, {why: "remove appendix"}, function(err) { ... } )
-```
-
-which will add `{patient_id: 4, doctor_id: 6, why: "remove appendix"}` to the join table.
-
-#### getAccessor
-
-This accessor in this type of association returns a `ChainFind` if not passing a callback. This means you can
-do things like:
-
-```js
-patient.getDoctors().order("name").offset(1).run(function (err, doctors), {
- // ... all doctors, ordered by name, excluding first one
-});
-```
-
-### extendsTo
-
-If you want to split maybe optional properties into different tables or collections. Every extension will be in a new table,
-where the unique identifier of each row is the main model instance id. For example:
-
-```js
-var Person = db.define("person", {
- name : String
-});
-var PersonAddress = Person.extendsTo("address", {
- street : String,
- number : Number
-});
-```
-
-This will create a table `person` with columns `id` and `name`. The extension will create a table `person_address` with
-columns `person_id`, `street` and `number`. The methods available in the `Person` model are similar to an `hasOne`
-association. In this example you would be able to call `.getAddress(cb)`, `.setAddress(Address, cb)`, ..
-
-**Note:** you don't have to save the result from `Person.extendsTo`. It returns an extended model. You can use it to query
-directly this extended table (and even find the related model) but that's up to you. If you only want to access it using the
-original model you can just discard the return.
-
-### Examples & options
-
-If you have a relation of 1 to n, you should use `hasOne` (belongs to) association.
-
-```js
-var Person = db.define('person', {
- name : String
-});
-var Animal = db.define('animal', {
- name : String
-});
-Animal.hasOne("owner", Person); // creates column 'owner_id' in 'animal' table
-
-// get animal with id = 123
-Animal.get(123, function (err, animal) {
- // animal is the animal model instance, if found
- animal.getOwner(function (err, person) {
- // if animal has really an owner, person points to it
- });
-});
-```
-
-You can mark the `owner_id` field as required in the database by specifying the `required` option:
-```js
-Animal.hasOne("owner", Person, { required: true });
-```
-
-If you prefer to use another name for the field (owner_id) you can change this parameter in the settings.
-
-```js
-db.settings.set("properties.association_key", "{field}_{name}"); // {name} will be replaced by 'owner' and {field} will be replaced by 'id' in this case
-```
-
-**Note: This has to be done before the association is specified.**
-
-The `hasMany` associations can have additional properties in the association table.
-
-```js
-var Person = db.define('person', {
- name : String
-});
-Person.hasMany("friends", {
- rate : Number
-});
-
-Person.get(123, function (err, John) {
- John.getFriends(function (err, friends) {
- // assumes rate is another column on table person_friends
- // you can access it by going to friends[N].extra.rate
- });
-});
-```
-
-If you prefer you can activate `autoFetch`.
-This way associations are automatically fetched when you get or find instances of a model.
-
-```js
-var Person = db.define('person', {
- name : String
-});
-Person.hasMany("friends", {
- rate : Number
-}, {
- autoFetch : true
-});
-
-Person.get(123, function (err, John) {
- // no need to do John.getFriends() , John already has John.friends Array
-});
-```
-
-You can also define this option globally instead of a per association basis.
-
-```js
-var Person = db.define('person', {
- name : String
-}, {
- autoFetch : true
-});
-Person.hasMany("friends", {
- rate : Number
-});
-```
-
-Associations can make calls to the associated Model by using the `reverse` option. For example, if you have an
-association from ModelA to ModelB, you can create an accessor in ModelB to get instances from ModelA.
-Confusing? Look at the next example.
-
-```js
-var Pet = db.define('pet', {
- name : String
-});
-var Person = db.define('person', {
- name : String
-});
-Pet.hasOne("owner", Person, {
- reverse : "pets"
-});
-
-Person(4).getPets(function (err, pets) {
- // although the association was made on Pet,
- // Person will have an accessor (getPets)
- //
- // In this example, ORM will fetch all pets
- // whose owner_id = 4
-});
-```
-
-This makes even more sense when having `hasMany` associations since you can manage the *many to many*
-associations from both sides.
-
-```js
-var Pet = db.define('pet', {
- name : String
-});
-var Person = db.define('person', {
- name : String
-});
-Person.hasMany("pets", Pet, {
- bought : Date
-}, {
- reverse : "owners"
-});
-
-Person(1).getPets(...);
-Pet(2).getOwners(...);
-```
+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.
\ No newline at end of file
diff --git a/examples/anontxt/Readme.md b/examples/anontxt/Readme.md
deleted file mode 100644
index 84c3dec9..00000000
--- a/examples/anontxt/Readme.md
+++ /dev/null
@@ -1,31 +0,0 @@
-# AnonTXT demo app
-
-## Getting started
-
-**Setup node-orm2!**
-
-```bash
-git clone https://github.com/dresende/node-orm2.git
-cd node-orm2
-npm install
-
-# You may work off master, or checkout a different version if master is broken:
-git tag
-git checkout v2.1.3
-```
-
-**Setup AnonTXT**
-
-Edit `anontxt/config/settings.js` to set your database, user & password.
-
-```bash
-cd examples/anontxt
-npm install
-node tasks/reset
-./script/start
-```
-
-And then open up [localhost:3000](http://localhost:3000/)
-
-You can also just run it with `node server.js` however the script launches nodemon which
-automatically restarts the server if you change any code.
diff --git a/examples/anontxt/app/controllers/_helpers.js b/examples/anontxt/app/controllers/_helpers.js
deleted file mode 100644
index 07646636..00000000
--- a/examples/anontxt/app/controllers/_helpers.js
+++ /dev/null
@@ -1,15 +0,0 @@
-
-module.exports = {
- formatErrors: function(errorsIn) {
- var errors = {};
- var a, e;
-
- for(a = 0; a < errorsIn.length; a++) {
- e = errorsIn[a];
-
- errors[e.property] = errors[e.property] || [];
- errors[e.property].push(e.msg);
- }
- return errors;
- }
-};
diff --git a/examples/anontxt/app/controllers/comments_controller.js b/examples/anontxt/app/controllers/comments_controller.js
deleted file mode 100644
index 91e04d17..00000000
--- a/examples/anontxt/app/controllers/comments_controller.js
+++ /dev/null
@@ -1,33 +0,0 @@
-var _ = require('lodash');
-var helpers = require('./_helpers');
-var orm = require('../../../../');
-
-module.exports = {
- create: function (req, res, next) {
- var params = _.pick(req.body, 'author', 'body');
-
- req.models.message.get(req.params.messageId, function (err, message) {
- if (err) {
- if (err.code == orm.ErrorCodes.NOT_FOUND) {
- res.send(404, "Message not found");
- } else {
- return next(err);
- }
- }
-
- params.message_id = message.id;
-
- req.models.comment.create(params, function (err, message) {
- if(err) {
- if(Array.isArray(err)) {
- return res.send(200, { errors: helpers.formatErrors(err) });
- } else {
- return next(err);
- }
- }
-
- return res.send(200, message.serialize());
- });
- });
- }
-};
diff --git a/examples/anontxt/app/controllers/home_controller.js b/examples/anontxt/app/controllers/home_controller.js
deleted file mode 100644
index 31aef457..00000000
--- a/examples/anontxt/app/controllers/home_controller.js
+++ /dev/null
@@ -1,5 +0,0 @@
-var settings = require('../../config/settings');
-
-module.exports = function (req, res, next) {
- res.sendfile(settings.path + '/public/index.html');
-};
diff --git a/examples/anontxt/app/controllers/index.js b/examples/anontxt/app/controllers/index.js
deleted file mode 100644
index 45b77ad8..00000000
--- a/examples/anontxt/app/controllers/index.js
+++ /dev/null
@@ -1,6 +0,0 @@
-
-module.exports = {
- home : require('./home_controller'),
- messages : require('./messages_controller'),
- comments : require('./comments_controller')
-};
diff --git a/examples/anontxt/app/controllers/messages_controller.js b/examples/anontxt/app/controllers/messages_controller.js
deleted file mode 100644
index 80d5801b..00000000
--- a/examples/anontxt/app/controllers/messages_controller.js
+++ /dev/null
@@ -1,35 +0,0 @@
-var _ = require('lodash');
-var helpers = require('./_helpers');
-var orm = require('../../../../');
-
-module.exports = {
- list: function (req, res, next) {
- req.models.message.find().limit(4).order('-id').all(function (err, messages) {
- if (err) return next(err);
-
- var items = messages.map(function (m) {
- return m.serialize();
- });
-
- res.send({ items: items });
- });
- },
- create: function (req, res, next) {
- var params = _.pick(req.body, 'title', 'body');
-
- req.models.message.create(params, function (err, message) {
- if(err) {
- if(Array.isArray(err)) {
- return res.send(200, { errors: helpers.formatErrors(err) });
- } else {
- return next(err);
- }
- }
-
- return res.send(200, message.serialize());
- });
- },
- get: function (req, res, next) {
-
- }
-};
diff --git a/examples/anontxt/app/models/comment.js b/examples/anontxt/app/models/comment.js
deleted file mode 100644
index f83a42a5..00000000
--- a/examples/anontxt/app/models/comment.js
+++ /dev/null
@@ -1,28 +0,0 @@
-var moment = require('moment');
-
-module.exports = function (orm, db) {
- var Comment = db.define('comment', {
- body : { type: 'text', required: true },
- createdAt : { type: 'date', required: true, time: true }
- },
- {
- hooks: {
- beforeValidation: function () {
- this.createdAt = new Date();
- }
- },
- validations: {
- body : orm.enforce.ranges.length(1, 1024)
- },
- methods: {
- serialize: function () {
- return {
- body : this.body,
- createdAt : moment(this.createdAt).fromNow()
- }
- }
- }
- });
-
- Comment.hasOne('message', db.models.message, { required: true, reverse: 'comments', autoFetch: true });
-};
diff --git a/examples/anontxt/app/models/index.js b/examples/anontxt/app/models/index.js
deleted file mode 100644
index b9684f70..00000000
--- a/examples/anontxt/app/models/index.js
+++ /dev/null
@@ -1,22 +0,0 @@
-var orm = require('../../../../');
-var settings = require('../../config/settings');
-
-var connection = null;
-
-function setup(db, cb) {
- require('./message')(orm, db);
- require('./comment')(orm, db);
-
- return cb(null, db);
-}
-
-module.exports = function (cb) {
- if (connection) return cb(null, connection);
-
- orm.connect(settings.database, function (err, db) {
- if (err) return cb(err);
-
- db.settings.set('instance.returnAllErrors', true);
- setup(db, cb);
- });
-};
diff --git a/examples/anontxt/app/models/message.js b/examples/anontxt/app/models/message.js
deleted file mode 100644
index a011f464..00000000
--- a/examples/anontxt/app/models/message.js
+++ /dev/null
@@ -1,45 +0,0 @@
-var moment = require('moment');
-
-module.exports = function (orm, db) {
- var Message = db.define('message', {
- title : { type: 'text', required: true },
- body : { type: 'text', required: true, big: true },
- createdAt : { type: 'date', required: true, time: true }
- },
- {
- hooks: {
- beforeValidation: function () {
- this.createdAt = new Date();
- }
- },
- validations: {
- title: [
- orm.enforce.ranges.length(1, undefined, "must be atleast 1 letter long"),
- orm.enforce.ranges.length(undefined, 96, "cannot be longer than 96 letters")
- ],
- body: [
- orm.enforce.ranges.length(1, undefined, "must be atleast 1 letter long"),
- orm.enforce.ranges.length(undefined, 32768, "cannot be longer than 32768 letters")
- ]
- },
- methods: {
- serialize: function () {
- var comments;
-
- if (this.comments) {
- comments = this.comments.map(function (c) { return c.serialize(); });
- } else {
- comments = [];
- }
-
- return {
- id : this.id,
- title : this.title,
- body : this.body,
- createdAt : moment(this.createdAt).fromNow(),
- comments : comments
- };
- }
- }
- });
-};
diff --git a/examples/anontxt/config/environment.js b/examples/anontxt/config/environment.js
deleted file mode 100644
index 5296603a..00000000
--- a/examples/anontxt/config/environment.js
+++ /dev/null
@@ -1,24 +0,0 @@
-var path = require('path');
-var express = require('express');
-var settings = require('./settings');
-var models = require('../app/models/');
-
-module.exports = function (app) {
- app.configure(function () {
- app.use(express.static(path.join(settings.path, 'public')));
- app.use(express.logger({ format: 'dev' }));
- app.use(express.bodyParser());
- app.use(express.methodOverride());
- app.use(function (req, res, next) {
- models(function (err, db) {
- if (err) return next(err);
-
- req.models = db.models;
- req.db = db;
-
- return next();
- });
- }),
- app.use(app.router);
- });
-};
diff --git a/examples/anontxt/config/routes.js b/examples/anontxt/config/routes.js
deleted file mode 100644
index 10b4464c..00000000
--- a/examples/anontxt/config/routes.js
+++ /dev/null
@@ -1,10 +0,0 @@
-
-var controllers = require('../app/controllers')
-
-module.exports = function (app) {
- app.get( '/' , controllers.home);
- app.get( '/messages' , controllers.messages.list);
- app.post('/messages' , controllers.messages.create);
- app.get( '/message/:id' , controllers.messages.get);
- app.post('/message/:messageId/comments', controllers.comments.create);
-};
diff --git a/examples/anontxt/config/settings.js b/examples/anontxt/config/settings.js
deleted file mode 100644
index d332b285..00000000
--- a/examples/anontxt/config/settings.js
+++ /dev/null
@@ -1,16 +0,0 @@
-var path = require('path');
-
-var settings = {
- path : path.normalize(path.join(__dirname, '..')),
- port : process.env.NODE_PORT || 3000,
- database : {
- protocol : "postgresql", // or "mysql"
- query : { pool: true },
- host : "127.0.0.1",
- database : "anontxt_dev",
- user : "anontxt",
- password : "apassword"
- }
-};
-
-module.exports = settings;
diff --git a/examples/anontxt/package.json b/examples/anontxt/package.json
deleted file mode 100644
index 3b925038..00000000
--- a/examples/anontxt/package.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "AnonTXT",
- "description": "Post text snippets, quickly and easily",
- "version": "0.1.0",
- "repository" : "http://github.com/dresende/node-orm2.git",
- "dependencies": {
- "express": "3.3.*",
- "lodash": "2.3.0",
- "nodemon": "0.7.10",
- "moment": "2.4.0",
- "pg": "2.6.2",
- "colors": "0.6.2"
- },
- "scripts": {
- "start": "script/start",
- "reset": "script/reset"
- }
-}
diff --git a/examples/anontxt/public/app.css b/examples/anontxt/public/app.css
deleted file mode 100644
index 95a31cb7..00000000
--- a/examples/anontxt/public/app.css
+++ /dev/null
@@ -1,128 +0,0 @@
-
-*, *:before, *:after {
- -moz-box-sizing: border-box;
- -webkit-box-sizing: border-box;
- box-sizing: border-box;
-}
-
-body {
- background: #eee;
- font-family: "Segoe UI", Frutiger, "Frutiger Linotype", "Dejavu Sans", "Helvetica Neue", Arial, sans-serif;
- font-height: 17px;
-}
-
-#container {
- width: 980px;
- margin: 0 auto;
- background: #fff;
- border-radius: 4px;
-}
-
-#header {
- padding: 2em;
-}
-#header h1 {
- margin: 0;
- font-size: 5em;
-}
-#header h1 em {
- color: #ed5;
-}
-
-#main {
- padding: 0 2em 2em 2em;
-}
-#main section {
- margin-bottom: 2em;
-}
-#main h3 {
- margin-top: 0;
-}
-#main form .entry {
- margin-bottom: 1em;
- line-height: 1.5em;
-}
-#main form .entry input,
-#main form .entry textarea {
- padding: 0.3em;
-}
-#main form .entry label {
- display: block;
-}
-#main form .entry label .title {
- display: block;
-}
-
-#main .new form .entry.title input {
- width: 50em;
-}
-#main .new form .entry.body textarea {
- width: 50em;
- height: 10em;
-}
-#main .new form button {
- font-size: 1.5em;
- padding: 0.3em 1em;
- border-radius: 0.4em;
-}
-#main .alerts {
- display: none;
-}
-#main .alerts > div {
- padding: 0 0 1em 0;
-}
-#main .alerts .error {
- color: red;
-}
-#main .alerts .info {
- color: #6d6;
-}
-#main .latest .texts .message {
- margin: 1em 0;
- padding-bottom: 0.7em;
- border: 1px solid #ddd;
-}
-#main .latest .texts .message:nth-child(n+5) {
- display: none;
-}
-#main .latest .texts .message > h4 {
- margin: 0;
- padding: 0.4em;
- background: #eee;
- border-bottom: 1px solid #ddd;
-}
-#main .latest .texts .message .meta {
- float: right;
- padding: 0.4em 0.4em 0 0;
- color: #777;
-}
-#main .latest .texts .message p {
- margin: 0.5em;
-}
-#main .latest .texts .message .comments {
- width: 500px;
- margin-left: 2em;
- font-size: 85%;
-}
-#main .latest .texts .message .comments h4 {
- margin: 0;
- padding: 0.4em;
-}
-#main .latest .texts .message .comments .comment {
- border-top: 1px dotted #aaa;
-}
-#main .latest .texts .message .comments .new-comment .entry {
- margin-bottom: 0;
-}
-#main .latest .texts .message .comments .new-comment textarea {
- width: 20em;
- height: 4em;
-}
-
-#footer {
- margin-top: 2em;
- padding: 0.5em;
- background: #9b9;
- color: #fff;
- text-align: center;
-}
diff --git a/examples/anontxt/public/app.js b/examples/anontxt/public/app.js
deleted file mode 100644
index 2f4880c6..00000000
--- a/examples/anontxt/public/app.js
+++ /dev/null
@@ -1,162 +0,0 @@
-
-var entityMap = {
- "&": "&",
- "<": "<",
- ">": ">",
- '"': '"',
- "'": ''',
- "/": '/'
-};
-
-function escapeHtml(string) {
- return String(string).replace(/[&<>"'\/]/g, function (s) {
- return entityMap[s];
- });
-}
-
-$(document).ready(function () {
- var $alerts = $('#main .alerts');
- var $texts = $('#main section.latest .texts');
- var $newMessageForm = $('#main section.new form');
-
- function showAlert(type, content) {
- $alerts.hide(100, function () {
- $alerts.html(
- '
' + content + '
'
- ).show(250);
- });
- }
-
- function renderComment(com) {
- var html = '';
- html += '';
- return html;
- }
-
- function renderComments(comments) {
- var html = '';
- html += '';
- return html;
- }
-
- function renderMessage(msg) {
- var html = '';
- html += ''
- html += '
' + msg.createdAt + '
';
- html += '
' + escapeHtml(msg.title) + ' ';
- html += '
' + escapeHtml(msg.body).replace(/\n/g, ' ') + '
';
- html += renderComments(msg.comments);
- html += '
'
- return html;
- }
-
- function renderErrors(errors) {
- var key, value;
- var html = '';
-
- html += '';
- for (key in errors) {
- value = errors[key];
- html += '' + key + ': ' + value.join(', ') + ' ';
- }
- html += ' ';
-
- return html;
- }
-
- function enhanceMessage($msg) {
- $msg.find('.comments .new-comment form').submit(function (e) {
- var $form = $(e.target);
- var $msg = $form.parents('.message:first');
- var msgId = $msg.data('id')
-
- e.preventDefault();
-
- $.ajax({
- url : '/message/' + msgId + '/comments',
- method : 'post',
- data : $form.serialize()
- }).done(function (data) {
- if ('errors' in data) {
- showAlert(
- "error",
- "Errors occurred whilst adding comment" +
- renderErrors(data.errors)
- );
- } else {
- $(renderComment(data)).insertBefore($msg.find('.new-comment'));
- showAlert("info", "Comment saved!");
- }
- $form[0].reset();
- }).fail(function (xhr, err, status) {
- showAlert('error', xhr.status + ', ' + xhr.responseText);
- });
- });
- }
-
- function loadMessages() {
- $.ajax({
- url: '/messages'
- }).done(function (data) {
- var html = '';
- for (var a = 0; a < data.items.length; a++) {
- html += renderMessage(data.items[a]);
- }
- $texts.html(html);
- $texts.find('.message').each(function (i, msg) {
- enhanceMessage($(msg));
- });
- }).fail(function (xhr, err, status) {
- showAlert('error', xhr.status + ', ' + xhr.responseText);
- });
- }
-
- $newMessageForm.submit(function (e) {
- e.preventDefault();
-
- $.ajax({
- url : $newMessageForm.attr('action'),
- method : 'post',
- data : $newMessageForm.serialize()
- }).done(function (data) {
- var $msg;
-
- if ('errors' in data) {
- showAlert(
- "error",
- "Errors occurred whilst saving" +
- renderErrors(data.errors)
- );
- } else {
- $msg = $($.parseHTML(renderMessage(data)));
- $texts.prepend($msg);
- enhanceMessage($msg);
-
- showAlert("info", "TeXT saved!");
- }
- $newMessageForm[0].reset();
- }).fail(function (xhr, err, status) {
- showAlert('error', xhr.status + ', ' + xhr.responseText);
- });
- });
-
- loadMessages();
-});
-
diff --git a/examples/anontxt/public/index.html b/examples/anontxt/public/index.html
deleted file mode 100644
index f70b1376..00000000
--- a/examples/anontxt/public/index.html
+++ /dev/null
@@ -1,47 +0,0 @@
-
-
-
-
- AnonTXT
-
-
-
-
-
-
-
-
-
-
- Latest txts:
- Loading..
-
-
-
-
-
-
-
diff --git a/examples/anontxt/script/start b/examples/anontxt/script/start
deleted file mode 100644
index e672ef12..00000000
--- a/examples/anontxt/script/start
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/usr/bin/env bash
-
-items="app config ../../node_modules/sql-query ../../lib server.js"
-
-watch=""
-for i in $items; do
- watch="$watch --watch $i"
-done
-
-nodemon $watch server.js
diff --git a/examples/anontxt/server.js b/examples/anontxt/server.js
deleted file mode 100644
index f543bde9..00000000
--- a/examples/anontxt/server.js
+++ /dev/null
@@ -1,34 +0,0 @@
-var path = require('path');
-var express = require('express');
-var colors = require('colors')
-var settings = require('./config/settings');
-var environment = require('./config/environment');
-var routes = require('./config/routes');
-var models = require('./app/models/');
-
-module.exports.start = function (done) {
- var app = express();
-
- environment(app);
- routes(app);
-
- app.listen(settings.port, function () {
- console.log( ("Listening on port " + settings.port).green );
-
- if (done) {
- return done(null, app, server);
- }
- }).on('error', function (e) {
- if (e.code == 'EADDRINUSE') {
- console.log('Address in use. Is the server already running?'.red);
- }
- if (done) {
- return done(e);
- }
- });
-}
-
-// If someone ran: "node server.js" then automatically start the server
-if (path.basename(process.argv[1],'.js') == path.basename(__filename,'.js')) {
- module.exports.start()
-}
diff --git a/examples/anontxt/tasks/reset.js b/examples/anontxt/tasks/reset.js
deleted file mode 100644
index 866d08f0..00000000
--- a/examples/anontxt/tasks/reset.js
+++ /dev/null
@@ -1,22 +0,0 @@
-var models = require('../app/models/');
-
-models(function (err, db) {
- if (err) throw err;
-
- db.drop(function (err) {
- if (err) throw err;
-
- db.sync(function (err) {
- if (err) throw err;
-
- db.models.message.create({
- title: "Hello world", body: "Testing testing 1 2 3"
- }, function (err, message) {
- if (err) throw err;
-
- db.close()
- console.log("Done!");
- });
- });
- });
-});
diff --git a/lib/AggregateFunctions.js b/lib/AggregateFunctions.js
index da8544c1..c8d5a882 100644
--- a/lib/AggregateFunctions.js
+++ b/lib/AggregateFunctions.js
@@ -1,14 +1,14 @@
-var ORMError = require("./Error");
+var ErrorCodes = require("./ErrorCodes");
var Utilities = require("./Utilities");
module.exports = AggregateFunctions;
function AggregateFunctions(opts) {
if (typeof opts.driver.getQuery !== "function") {
- throw new ORMError('NO_SUPPORT', "This driver does not support aggregate functions");
+ throw ErrorCodes.generateError(ErrorCodes.NO_SUPPORT, "This driver does not support aggregate functions");
}
if (!Array.isArray(opts.driver.aggregate_functions)) {
- throw new ORMError('NO_SUPPORT', "This driver does not support aggregate functions");
+ throw ErrorCodes.generateError(ErrorCodes.NO_SUPPORT, "This driver does not support aggregate functions");
}
var aggregates = [ [] ];
@@ -52,18 +52,16 @@ function AggregateFunctions(opts) {
},
select: function () {
if (arguments.length === 0) {
- throw new ORMError('PARAM_MISMATCH', "When using append you must at least define one property");
- }
- if (Array.isArray(arguments[0])) {
- opts.properties = opts.properties.concat(arguments[0]);
- } else {
- opts.properties = opts.properties.concat(Array.prototype.slice.apply(arguments));
+ throw ErrorCodes.generateError(ErrorCodes.PARAM_MISMATCH, "When using append you must at least define one property");
}
+ opts.properties = opts.properties.concat(Array.isArray(arguments[0]) ?
+ arguments[0] :
+ Array.prototype.slice.apply(arguments));
return this;
},
as: function (alias) {
if (aggregates.length === 0 || (aggregates.length === 1 && aggregates[0].length === 0)) {
- throw new ORMError('PARAM_MISMATCH', "No aggregate functions defined yet");
+ throw ErrorCodes.generateError(ErrorCodes.PARAM_MISMATCH, "No aggregate functions defined yet");
}
var len = aggregates.length;
@@ -88,13 +86,13 @@ function AggregateFunctions(opts) {
},
get: function (cb) {
if (typeof cb !== "function") {
- throw new ORMError('MISSING_CALLBACK', "You must pass a callback to Model.aggregate().get()");
+ throw ErrorCodes.generateError(ErrorCodes.MISSING_CALLBACK, "You must pass a callback to Model.aggregate().get()");
}
if (aggregates[aggregates.length - 1].length === 0) {
aggregates.length -= 1;
}
if (aggregates.length === 0) {
- throw new ORMError('PARAM_MISMATCH', "Missing aggregate functions");
+ throw ErrorCodes.generateError(ErrorCodes.PARAM_MISMATCH, "Missing aggregate functions");
}
var query = opts.driver.getQuery().select().from(opts.table).select(opts.properties);
diff --git a/lib/Associations/Extend.js b/lib/Associations/Extend.js
index d9ff80aa..3df3c291 100644
--- a/lib/Associations/Extend.js
+++ b/lib/Associations/Extend.js
@@ -1,5 +1,5 @@
var _ = require('lodash');
-var ORMError = require("../Error");
+var ErrorCodes = require("../ErrorCodes");
var Settings = require("../Settings");
var Singleton = require("../Singleton");
var util = require("../Utilities");
@@ -59,7 +59,7 @@ exports.prepare = function (db, Model, associations, association_properties, mod
}
if (conditions === null) {
- throw new ORMError(".findBy(" + assocName + ") is missing a conditions object", 'PARAM_MISMATCH');
+ throw ErrorCodes.generateError(ErrorCodes.PARAM_MISMATCH, ".findBy(" + assocName + ") is missing a conditions object");
}
options.__merge = {
@@ -109,7 +109,7 @@ function extendInstance(Model, Instance, Driver, association, opts) {
Object.defineProperty(Instance, association.hasAccessor, {
value : function (cb) {
if (!Instance[Model.id]) {
- cb(new ORMError("Instance not saved, cannot get extension", 'NOT_DEFINED', { model: Model.table }));
+ cb(ErrorCodes.generateError(ErrorCodes.NOT_DEFINED, "Instance not saved, cannot get extension", { model: Model.table }));
} else {
association.model.get(util.values(Instance, Model.id), function (err, extension) {
return cb(err, !err && extension ? true : false);
@@ -127,7 +127,7 @@ function extendInstance(Model, Instance, Driver, association, opts) {
}
if (!Instance[Model.id]) {
- cb(new ORMError("Instance not saved, cannot get extension", 'NOT_DEFINED', { model: Model.table }));
+ cb(ErrorCodes.generateError(ErrorCodes.NOT_DEFINED, "Instance not saved, cannot get extension", { model: Model.table }));
} else {
association.model.get(util.values(Instance, Model.id), opts, cb);
}
@@ -167,7 +167,7 @@ function extendInstance(Model, Instance, Driver, association, opts) {
Object.defineProperty(Instance, association.delAccessor, {
value : function (cb) {
if (!Instance[Model.id]) {
- cb(new ORMError("Instance not saved, cannot get extension", 'NOT_DEFINED', { model: Model.table }));
+ cb(ErrorCodes.generateError(ErrorCodes.NOT_DEFINED, "Instance not saved, cannot get extension", { model: Model.table }));
} else {
var conditions = {};
var fields = Object.keys(association.field);
diff --git a/lib/Associations/Many.js b/lib/Associations/Many.js
index cc9c996e..53b46a55 100644
--- a/lib/Associations/Many.js
+++ b/lib/Associations/Many.js
@@ -3,7 +3,7 @@ var InstanceConstructor = require("../Instance").Instance;
var Hook = require("../Hook");
var Settings = require("../Settings");
var Property = require("../Property");
-var ORMError = require("../Error");
+var ErrorCodes = require("../ErrorCodes");
var util = require("../Utilities");
exports.prepare = function (Model, associations) {
@@ -155,8 +155,7 @@ function extendInstance(Model, Instance, Driver, association, opts, createInstan
});
return this;
},
- enumerable: false,
- writable: true
+ enumerable: false
});
Object.defineProperty(Instance, association.getAccessor, {
value: function () {
@@ -229,28 +228,35 @@ function extendInstance(Model, Instance, Driver, association, opts, createInstan
association.model.find(conditions, options, cb);
return this;
},
- enumerable: false,
- writable: true
+ enumerable: false
});
Object.defineProperty(Instance, association.setAccessor, {
value: function () {
- var items = _.flatten(arguments);
- var cb = _.last(items) instanceof Function ? items.pop() : noOperation;
+ var Instances = Array.prototype.slice.apply(arguments);
+ var cb = (Instances.length &&
+ typeof Instances[Instances.length - 1] == "function" ? Instances.pop() : noOperation);
- Instance[association.delAccessor](function (err) {
- if (err) return cb(err);
+ if (Instances.length === 0) {
+ throw ErrorCodes.generateError(ErrorCodes.PARAM_MISMATCH, "No associations defined", { model: Model.name });
+ }
+
+ if (Array.isArray(Instances[0])) {
+ // clone is used or else Instances will be just a reference
+ // to the array and the Instances.push(cb) a few lines ahead
+ // would actually change the user Array passed to the function
+ Instances = _.clone(Instances[0]);
+ }
- if (items.length) {
- Instance[association.addAccessor](items, cb);
- } else {
- cb(null);
+ Instance[association.delAccessor](function (err) {
+ if (err) {
+ return cb(err);
}
+ Instances.push(cb);
+ Instance[association.addAccessor].apply(Instance, Instances);
});
-
return this;
},
- enumerable: false,
- writable: true
+ enumerable: false
});
Object.defineProperty(Instance, association.delAccessor, {
value: function () {
@@ -302,8 +308,7 @@ function extendInstance(Model, Instance, Driver, association, opts, createInstan
}
return this;
},
- enumerable: false,
- writable: true
+ enumerable: false
});
Object.defineProperty(Instance, association.addAccessor, {
value: function () {
@@ -311,7 +316,8 @@ function extendInstance(Model, Instance, Driver, association, opts, createInstan
var opts = {};
var cb = noOperation;
var run = function () {
- var savedAssociations = [];
+ var savedAssociations = [];
+
var saveNextAssociation = function () {
if (Associations.length === 0) {
return cb(null, savedAssociations);
@@ -389,7 +395,7 @@ function extendInstance(Model, Instance, Driver, association, opts, createInstan
}
if (Associations.length === 0) {
- throw new ORMError("No associations defined", 'PARAM_MISMATCH', { model: Model.name });
+ throw ErrorCodes.generateError(ErrorCodes.PARAM_MISMATCH, "No associations defined", { model: Model.name });
}
if (this.saved()) {
@@ -406,8 +412,7 @@ function extendInstance(Model, Instance, Driver, association, opts, createInstan
return this;
},
- enumerable: false,
- writable: true
+ enumerable: false
});
}
diff --git a/lib/Associations/One.js b/lib/Associations/One.js
index 63cda40a..ce71ccd3 100644
--- a/lib/Associations/One.js
+++ b/lib/Associations/One.js
@@ -1,7 +1,7 @@
-var _ = require("lodash");
-var util = require("../Utilities");
-var ORMError = require("../Error");
-var Accessors = { "get": "get", "set": "set", "has": "has", "del": "remove" };
+var _ = require("lodash");
+var Settings = require("../Settings");
+var util = require("../Utilities");
+var Accessors = { "get": "get", "set": "set", "has": "has", "del": "remove" };
exports.prepare = function (Model, associations, association_properties, model_fields) {
Model.hasOne = function () {
@@ -49,9 +49,6 @@ exports.prepare = function (Model, associations, association_properties, model_f
associations.push(association);
for (k in association.field) {
- if (!association.field.hasOwnProperty(k)) {
- continue;
- }
association_properties.push(k);
if (!association.reversed) {
Model.allProperties[k] = _.omit(association.field[k], 'klass');
@@ -90,7 +87,7 @@ exports.prepare = function (Model, associations, association_properties, model_f
}
if (conditions === null) {
- throw new ORMError(".findBy(" + assocName + ") is missing a conditions object", 'PARAM_MISMATCH');
+ throw ErrorCodes.generateError(ErrorCodes.PARAM_MISMATCH, ".findBy(" + assocName + ") is missing a conditions object");
}
options.__merge = {
@@ -101,7 +98,7 @@ exports.prepare = function (Model, associations, association_properties, model_f
};
options.extra = [];
- if (typeof cb === "function") {
+ if (typeof cb == "function") {
return Model.find({}, options, cb);
}
return Model.find({}, options);
@@ -111,9 +108,9 @@ exports.prepare = function (Model, associations, association_properties, model_f
};
};
-exports.extend = function (Model, Instance, Driver, associations) {
+exports.extend = function (Model, Instance, Driver, associations, opts) {
for (var i = 0; i < associations.length; i++) {
- extendInstance(Model, Instance, Driver, associations[i]);
+ extendInstance(Model, Instance, Driver, associations[i], opts);
}
};
@@ -136,10 +133,10 @@ exports.autoFetch = function (Instance, associations, opts, cb) {
}
};
-function extendInstance(Model, Instance, Driver, association) {
+function extendInstance(Model, Instance, Driver, association, opts) {
Object.defineProperty(Instance, association.hasAccessor, {
value: function (opts, cb) {
- if (typeof opts === "function") {
+ if (typeof opts == "function") {
cb = opts;
opts = {};
}
@@ -154,12 +151,11 @@ function extendInstance(Model, Instance, Driver, association) {
return this;
},
- enumerable: false,
- writable: true
+ enumerable: false
});
Object.defineProperty(Instance, association.getAccessor, {
value: function (opts, cb) {
- if (typeof opts === "function") {
+ if (typeof opts == "function") {
cb = opts;
opts = {};
}
@@ -174,9 +170,6 @@ function extendInstance(Model, Instance, Driver, association) {
if (association.reversed) {
if (util.hasValues(Instance, Model.id)) {
- if (typeof cb !== "function") {
- return association.model.find(util.getConditions(Model, Object.keys(association.field), Instance), opts);
- }
association.model.find(util.getConditions(Model, Object.keys(association.field), Instance), opts, saveAndReturn);
} else {
cb(null);
@@ -198,8 +191,7 @@ function extendInstance(Model, Instance, Driver, association) {
return this;
},
- enumerable: false,
- writable: true
+ enumerable: false
});
Object.defineProperty(Instance, association.setAccessor, {
value: function (OtherInstance, cb) {
@@ -253,16 +245,13 @@ function extendInstance(Model, Instance, Driver, association) {
return this;
},
- enumerable: false,
- writable: true
+ enumerable: false
});
if (!association.reversed) {
Object.defineProperty(Instance, association.delAccessor, {
value: function (cb) {
for (var k in association.field) {
- if (association.field.hasOwnProperty(k)) {
- Instance[k] = null;
- }
+ Instance[k] = null;
}
Instance.save({}, { saveAssociations: false }, function (err) {
if (!err) {
@@ -274,8 +263,7 @@ function extendInstance(Model, Instance, Driver, association) {
return this;
},
- enumerable: false,
- writable: true
+ enumerable: false
});
}
}
@@ -285,7 +273,7 @@ function autoFetchInstance(Instance, association, opts, cb) {
return cb();
}
- if (!opts.hasOwnProperty("autoFetchLimit") || typeof opts.autoFetchLimit === "undefined") {
+ if (!opts.hasOwnProperty("autoFetchLimit") || typeof opts.autoFetchLimit == "undefined") {
opts.autoFetchLimit = association.autoFetchLimit;
}
diff --git a/lib/ChainFind.js b/lib/ChainFind.js
index a6e6f66d..0dc86229 100644
--- a/lib/ChainFind.js
+++ b/lib/ChainFind.js
@@ -1,6 +1,7 @@
-var _ = require("lodash");
-var ChainInstance = require("./ChainInstance");
-var Promise = require("./Promise").Promise;
+var _ = require("lodash");
+var Singleton = require("./Singleton");
+var ChainInstance = require("./ChainInstance");
+var Promise = require("./Promise").Promise;
module.exports = ChainFind;
@@ -13,14 +14,14 @@ function ChainFind(Model, opts) {
var args = Array.prototype.slice.call(arguments);
opts.conditions = opts.conditions || {};
- if (typeof _.last(args) === "function") {
+ if (typeof _.last(args) === 'function') {
cb = args.pop();
}
- if (typeof args[0] === "object") {
- _.extend(opts.conditions, args[0]);
- } else if (typeof args[0] === "string") {
- opts.conditions.__sql = opts.conditions.__sql || [];
+ if (typeof args[0] === 'object') {
+ _.extend(opts.conditions, args[0]);
+ } else if (typeof args[0] === 'string') {
+ opts.conditions.__sql = opts.conditions.__sql || [];
opts.conditions.__sql.push(args);
}
@@ -91,22 +92,13 @@ function ChainFind(Model, opts) {
}
var ids = [], conditions = {};
- var or;
-
- if (!Array.isArray(opts.id)) {
- opts.id = [ opts.id ];
- }
-
- conditions.or = [];
for (var i = 0; i < data.length; i++) {
- or = {};
- for (var j = 0; j < opts.id.length; j++) {
- or[opts.id[j]] = data[i][opts.id[j]];
- }
- conditions.or.push(or);
+ ids.push(data[i][opts.id]);
}
+ conditions[opts.id] = ids;
+
return opts.driver.remove(opts.table, conditions, cb);
});
return this;
@@ -141,21 +133,6 @@ function ChainFind(Model, opts) {
}
return promise.fail(cb);
},
- eager: function () {
- // This will allow params such as ("abc", "def") or (["abc", "def"])
- var associations = _.flatten(arguments);
-
- // TODO: Implement eager loading for Mongo and delete this.
- if (opts.driver.config.protocol == "mongodb:") {
- throw new Error("MongoDB does not currently support eager loading");
- }
-
- opts.__eager = _.filter(opts.associations, function (association) {
- return ~associations.indexOf(association.name);
- });
-
- return this;
- },
all: function (cb) {
opts.driver.find(opts.only, opts.table, opts.conditions, {
limit : opts.limit,
@@ -173,43 +150,13 @@ function ChainFind(Model, opts) {
var pending = data.length;
var createInstance = function (idx) {
- opts.newInstance(data[idx], function (err, instance) {
- data[idx] = instance;
+ opts.newInstance(data[idx], function (err, instance) {
+ data[idx] = instance;
- if (--pending === 0) {
- return (opts.__eager && opts.__eager.length ? eagerLoading : cb)(null, data);
- }
- });
- };
-
- var eagerLoading = function (err, data) {
- var pending = opts.__eager.length;
- var idMap = {};
- var count = 0;
-
- var ids = _.map(data, function (instance) {
- var id = instance[opts.id[0]];
- // Create the association arrays
- for (var i = 0, association; association = opts.__eager[i]; i++) {
- instance[association.name] = [];
- }
-
- idMap[id] = count++;
- return id;
- });
-
- _.map(opts.__eager, function (association) {
- opts.driver.eagerQuery(association, opts, ids, function (err, instances) {
- for (var i = 0, instance; instance = instances[i]; i++) {
- // Perform a parent lookup with $p, and initialize it as an instance.
- data[idMap[instance.$p]][association.name].push(association.model(instance));
- }
-
- if (--pending === 0) {
- return cb(null, data);
- }
- });
- });
+ if (--pending === 0) {
+ return cb(null, data);
+ }
+ });
};
for (var i = 0; i < data.length; i++) {
@@ -227,16 +174,10 @@ function ChainFind(Model, opts) {
}
}
for (var k in Model) {
- if ([
- "hasOne", "hasMany",
- "drop", "sync", "get", "find", "all", "count", "clear", "create",
- "exists", "settings", "aggregate"
- ].indexOf(k) >= 0) {
- continue;
- }
- if (typeof Model[k] !== "function") {
- continue;
- }
+ if ([ "hasOne", "hasMany",
+ "drop", "sync", "get", "find", "all", "count", "clear", "create",
+ "exists", "settings", "aggregate" ].indexOf(k) >= 0) continue;
+ if (typeof Model[k] !== "function") continue;
chain[k] = Model[k];
}
@@ -256,23 +197,22 @@ function addChainMethod(chain, association, opts) {
var assocIds = Object.keys(association.mergeAssocId);
var ids = association.model.id;
function mergeConditions(source) {
- for (var i = 0; i < assocIds.length; i++) {
- if (typeof conditions[assocIds[i]] === "undefined") {
- conditions[assocIds[i]] = source[ids[i]];
- } else if (Array.isArray(conditions[assocIds[i]])) {
- conditions[assocIds[i]].push(source[ids[i]]);
- } else {
- conditions[assocIds[i]] = [ conditions[assocIds[i]], source[ids[i]] ];
- }
- }
+ for (var i = 0; i < assocIds.length; i++) {
+ if (typeof conditions[assocIds[i]] === 'undefined')
+ conditions[assocIds[i]] = source[ids[i]];
+ else if(Array.isArray(conditions[assocIds[i]]))
+ conditions[assocIds[i]].push(source[ids[i]]);
+ else
+ conditions[assocIds[i]] = [conditions[assocIds[i]], source[ids[i]]];
+ }
}
if (Array.isArray(value)) {
- for (var i = 0; i < value.length; i++) {
- mergeConditions(value[i]);
- }
+ for (var i = 0; i < value.length; i++) {
+ mergeConditions(value[i]);
+ }
} else {
- mergeConditions(value);
+ mergeConditions(value);
}
opts.exists.push({
diff --git a/lib/Drivers/DDL/SQL.js b/lib/Drivers/DDL/SQL.js
deleted file mode 100644
index 38202c40..00000000
--- a/lib/Drivers/DDL/SQL.js
+++ /dev/null
@@ -1,67 +0,0 @@
-var _ = require("lodash");
-var Sync = require("sql-ddl-sync").Sync;
-
-exports.sync = function (opts, cb) {
- var sync = new Sync({
- driver : this,
- debug : false//function (text) { console.log(text); }
- });
-
- var setIndex = function (p, v, k) {
- v.index = true;
- p[k] = v;
- };
- var props = {};
-
- if (this.customTypes) {
- for (var k in this.customTypes) {
- sync.defineType(k, this.customTypes[k]);
- }
- }
- for (var k in opts.allProperties) {
- if (typeof opts.id == "string" && opts.id == k) {
- opts.allProperties[k].index = [ opts.table + "_pkey" ];
- } else if (Array.isArray(opts.id) && opts.id.indexOf(k) >= 0) {
- opts.allProperties[k].index = [ opts.table + "_pkey" ];
- }
- }
-
- sync.defineCollection(opts.table, opts.allProperties);
-
- for (i = 0; i < opts.many_associations.length; i++) {
- props = {};
-
- _.merge(props, opts.many_associations[i].mergeId);
- _.merge(props, opts.many_associations[i].mergeAssocId);
- props = _.transform(props, setIndex);
- _.merge(props, opts.many_associations[i].props);
-
- sync.defineCollection(opts.many_associations[i].mergeTable, props);
- }
-
- sync.sync(cb);
-
- return this;
-};
-
-exports.drop = function (opts, cb) {
- var i, queries = [], pending;
-
- queries.push("DROP TABLE IF EXISTS " + this.query.escapeId(opts.table));
-
- for (i = 0; i < opts.many_associations.length; i++) {
- queries.push("DROP TABLE IF EXISTS " + this.query.escapeId(opts.many_associations[i].mergeTable));
- }
-
- pending = queries.length;
-
- for (i = 0; i < queries.length; i++) {
- this.execQuery(queries[i], function (err) {
- if (--pending === 0) {
- return cb(err);
- }
- });
- }
-
- return this;
-};
diff --git a/lib/Drivers/DDL/mysql.js b/lib/Drivers/DDL/mysql.js
new file mode 100755
index 00000000..a8e655c0
--- /dev/null
+++ b/lib/Drivers/DDL/mysql.js
@@ -0,0 +1,192 @@
+var ErrorCodes = require("../../ErrorCodes");
+
+exports.drop = function (driver, opts, cb) {
+ var i, queries = [], pending;
+
+ queries.push("DROP TABLE IF EXISTS " + driver.query.escapeId(opts.table));
+
+ for (i = 0; i < opts.many_associations.length; i++) {
+ queries.push("DROP TABLE IF EXISTS " + driver.query.escapeId(opts.many_associations[i].mergeTable));
+ }
+
+ pending = queries.length;
+
+ for (i = 0; i < queries.length; i++) {
+ driver.execQuery(queries[i], function (err) {
+ if (--pending === 0) {
+ return cb(err);
+ }
+ });
+ }
+};
+
+exports.sync = function (driver, opts, cb) {
+ var queries = [];
+ var definitions = [];
+ var k, i, pending, prop;
+ var primary_keys = opts.id.map(function (k) { return driver.query.escapeId(k); });
+ var keys = [];
+
+ for (k in opts.allProperties) {
+ prop = opts.allProperties[k];
+ definitions.push(buildColumnDefinition(driver, k, prop));
+ }
+
+ for (k in opts.allProperties) {
+ prop = opts.allProperties[k];
+ if (prop.unique === true) {
+ definitions.push("UNIQUE (" + driver.query.escapeId(k) + ")");
+ } else if (prop.index) {
+ definitions.push("INDEX (" + driver.query.escapeId(k) + ")");
+ }
+ }
+/*
+ for (k in opts.allProperties) {
+ prop = opts.allProperties[k];
+ if (prop.unique === true) {
+ definitions.push("UNIQUE KEY " + driver.query.escapeId(k) + " (" + driver.query.escapeId(k) + ")");
+ } else if (prop.index) {
+ definitions.push("INDEX (" + driver.query.escapeId(k) + ")");
+ }
+ }
+*/
+ for (i = 0; i < opts.one_associations.length; i++) {
+ if (opts.one_associations[i].extension) continue;
+ if (opts.one_associations[i].reversed) continue;
+ for (k in opts.one_associations[i].field) {
+ definitions.push("INDEX (" + driver.query.escapeId(k) + ")");
+ }
+ }
+
+ for (i = 0; i < opts.indexes.length; i++) {
+ definitions.push("INDEX (" + opts.indexes[i].split(/[,;]+/).map(function (el) {
+ return driver.query.escapeId(el);
+ }).join(", ") + ")");
+ }
+
+ definitions.push("PRIMARY KEY (" + primary_keys.join(", ") + ")");
+
+ queries.push(
+ "CREATE TABLE IF NOT EXISTS " + driver.query.escapeId(opts.table) +
+ " (" + definitions.join(", ") + ")"
+ );
+
+ for (i = 0; i < opts.many_associations.length; i++) {
+ definitions = [];
+
+ for (k in opts.many_associations[i].mergeId) {
+ definitions.push(buildColumnDefinition(driver, k, opts.many_associations[i].mergeId[k]));
+ }
+
+ for (k in opts.many_associations[i].mergeAssocId) {
+ definitions.push(buildColumnDefinition(driver, k, opts.many_associations[i].mergeAssocId[k]));
+ }
+
+ for (k in opts.many_associations[i].props) {
+ definitions.push(buildColumnDefinition(driver, k, opts.many_associations[i].props[k]));
+ }
+
+ var index = null;
+ for (k in opts.many_associations[i].mergeId) {
+ if (index == null) index = driver.query.escapeId(k);
+ else index += ", " + driver.query.escapeId(k);
+ }
+
+ for (k in opts.many_associations[i].mergeAssocId) {
+ if (index == null) index = driver.query.escapeId(k);
+ else index += ", " + driver.query.escapeId(k);
+ }
+
+
+ definitions.push("INDEX (" + index + ")");
+ queries.push(
+ "CREATE TABLE IF NOT EXISTS " + driver.query.escapeId(opts.many_associations[i].mergeTable) +
+ " (" + definitions.join(", ") + ")"
+ );
+ }
+
+ pending = queries.length;
+
+ for (i = 0; i < queries.length; i++) {
+ driver.execQuery(queries[i], function (err) {
+ if (--pending === 0) {
+ return cb(err);
+ }
+ });
+ }
+};
+
+var colTypes = {
+ integer: { 2: 'SMALLINT', 4: 'INTEGER', 8: 'BIGINT' },
+ floating: { 4: 'FLOAT', 8: 'DOUBLE' }
+};
+
+function buildColumnDefinition(driver, name, prop) {
+ var def = driver.query.escapeId(name);
+ var customType;
+
+ switch (prop.type) {
+ case "text":
+ if (prop.big === true) {
+ def += " LONGTEXT";
+ } else {
+ def += " VARCHAR(" + Math.min(Math.max(parseInt(prop.size, 10) || 255, 1), 65535) + ")";
+ }
+ break;
+ case "serial":
+ def += " INT(10) UNSIGNED NOT NULL AUTO_INCREMENT";
+ break;
+ case "number":
+ if (prop.rational === false) {
+ def += " " + colTypes.integer[prop.size || 4];
+ } else {
+ def += " " + colTypes.floating[prop.size || 4];
+ }
+ if (prop.unsigned === true) {
+ def += " UNSIGNED";
+ }
+ break;
+ case "boolean":
+ def += " BOOLEAN";
+ break;
+ case "date":
+ if (prop.time === false) {
+ def += " DATE";
+ } else {
+ def += " DATETIME";
+ }
+ break;
+ case "binary":
+ case "object":
+ if (prop.big === true) {
+ def += " LONGBLOB";
+ } else {
+ def += " BLOB";
+ }
+ break;
+ case "enum":
+ def += " ENUM (" +
+ prop.values.map(driver.query.escapeVal.bind(driver.query)) +
+ ")";
+ break;
+ case "point":
+ def += " POINT";
+ break;
+ default:
+ customType = driver.customTypes[prop.type];
+ if (customType) {
+ def += " " + customType.datastoreType(prop);
+ } else {
+ throw ErrorCodes.generateError(ErrorCodes.NO_SUPPORT, "Unknown property type: '" + prop.type + "'", {
+ property : prop
+ });
+ }
+ }
+ if (prop.required === true) {
+ def += " NOT NULL";
+ }
+ if (prop.hasOwnProperty("defaultValue")) {
+ def += " DEFAULT " + driver.query.escapeVal(prop.defaultValue);
+ }
+ return def;
+}
diff --git a/lib/Drivers/DDL/postgres.js b/lib/Drivers/DDL/postgres.js
new file mode 100755
index 00000000..860772f6
--- /dev/null
+++ b/lib/Drivers/DDL/postgres.js
@@ -0,0 +1,239 @@
+var ErrorCodes = require("../../ErrorCodes");
+
+exports.drop = function (driver, opts, cb) {
+ var i, queries = [], pending;
+
+ queries.push("DROP TABLE IF EXISTS " + driver.query.escapeId(opts.table));
+
+ for (i = 0; i < opts.many_associations.length; i++) {
+ queries.push("DROP TABLE IF EXISTS " + driver.query.escapeId(opts.many_associations[i].mergeTable));
+ }
+
+ pending = queries.length;
+ for (i = 0; i < queries.length; i++) {
+ driver.execQuery(queries[i], function (err) {
+ if (--pending === 0) {
+ return cb(err);
+ }
+ });
+ }
+};
+
+exports.sync = function (driver, opts, cb) {
+ var tables = [];
+ var subqueries = [];
+ var typequeries = [];
+ var definitions = [];
+ var k, i, pending, prop;
+ var primary_keys = opts.id.map(function (k) { return driver.query.escapeId(k); });
+ var keys = [];
+
+ for (k in opts.allProperties) {
+ prop = opts.allProperties[k];
+ definitions.push(buildColumnDefinition(driver, opts.table, k, prop));
+
+ if (prop.type == "enum") {
+ typequeries.push(
+ "CREATE TYPE " + driver.query.escapeId("enum_" + opts.table + "_" + k) + " AS ENUM (" +
+ prop.values.map(driver.query.escapeVal.bind(driver)) + ")"
+ );
+ }
+ }
+
+ for (k in opts.allProperties) {
+ prop = opts.allProperties[k];
+ if (prop.unique === true) {
+ definitions.push("UNIQUE (" + driver.query.escapeId(k) + ")");
+ } else if (prop.index) {
+ definitions.push("INDEX (" + driver.query.escapeId(k) + ")");
+ }
+ }
+
+ definitions.push("PRIMARY KEY (" + primary_keys.join(", ") + ")");
+
+ tables.push({
+ name : opts.table,
+ query : "CREATE TABLE " + driver.query.escapeId(opts.table) +
+ " (" + definitions.join(", ") + ")",
+ typequeries: typequeries,
+ subqueries : subqueries
+ });
+
+ for (i = 0; i < opts.one_associations.length; i++) {
+ if (opts.one_associations[i].extension) continue;
+ if (opts.one_associations[i].reversed) continue;
+ for (k in opts.one_associations[i].field) {
+ tables[tables.length - 1].subqueries.push(
+ "CREATE INDEX ON " + driver.query.escapeId(opts.table) +
+ " (" + driver.query.escapeId(k) + ")"
+ );
+ }
+ }
+
+ for (i = 0; i < opts.indexes.length; i++) {
+ tables[tables.length - 1].subqueries.push(
+ "CREATE INDEX ON " + driver.query.escapeId(opts.table) +
+ " (" + opts.indexes[i].split(/[,;]+/).map(function (el) {
+ return driver.query.escapeId(el);
+ }).join(", ") + ")"
+ );
+ }
+
+ for (i = 0; i < opts.many_associations.length; i++) {
+ definitions = [];
+ typequeries = [];
+
+ for (k in opts.many_associations[i].mergeId) {
+ definitions.push(buildColumnDefinition(driver, opts.many_associations[i].mergeTable, k, opts.many_associations[i].mergeId[k]));
+ }
+
+ for (k in opts.many_associations[i].mergeAssocId) {
+ definitions.push(buildColumnDefinition(driver, opts.many_associations[i].mergeTable, k, opts.many_associations[i].mergeAssocId[k]));
+ }
+
+ for (k in opts.many_associations[i].props) {
+ definitions.push(buildColumnDefinition(driver, opts.many_associations[i].mergeTable,
+ k, opts.many_associations[i].props[k]));
+ if (opts.many_associations[i].props[k].type == "enum") {
+ typequeries.push(
+ "CREATE TYPE " + driver.query.escapeId("enum_" + opts.many_associations[i].mergeTable + "_" + k) + " AS ENUM (" +
+ opts.many_associations[i].props[k].values.map(driver.query.escapeVal.bind(driver)) + ")"
+ );
+ }
+ }
+
+ var index = null;
+ for (k in opts.many_associations[i].mergeId) {
+ if (index == null) index = driver.query.escapeId(k);
+ else index += ", " + driver.query.escapeId(k);
+ }
+
+ for (k in opts.many_associations[i].mergeAssocId) {
+ if (index == null) index = driver.query.escapeId(k);
+ else index += ", " + driver.query.escapeId(k);
+ }
+
+ tables.push({
+ name : opts.many_associations[i].mergeTable,
+ query : "CREATE TABLE IF NOT EXISTS " + driver.query.escapeId(opts.many_associations[i].mergeTable) +
+ " (" + definitions.join(", ") + ")",
+ typequeries: typequeries,
+ subqueries : []
+ });
+ tables[tables.length - 1].subqueries.push(
+ "CREATE INDEX ON " + driver.query.escapeId(opts.many_associations[i].mergeTable) +
+ " (" + index + ")"
+ );
+ }
+
+ pending = tables.length;
+
+ for (i = 0; i < tables.length; i++) {
+ createTableSchema(driver, tables[i], function (err) {
+ if (--pending === 0) {
+ // this will bring trouble in the future...
+ // some errors are not avoided (like ENUM types already defined, etc..)
+ return cb(err);
+ }
+ });
+ }
+};
+
+function createTableSchema(driver, table, cb) {
+ var pending = table.typequeries.length;
+ var createTable = function () {
+ driver.execQuery(table.query, function (err) {
+ if (err || table.subqueries.length === 0) {
+ return cb(err);
+ }
+
+ var pending = table.subqueries.length;
+
+ for (var i = 0; i < table.subqueries.length; i++) {
+ driver.execQuery(table.subqueries[i], function (err) {
+ if (--pending === 0) {
+ return cb();
+ }
+ });
+ }
+ });
+ };
+
+ if (pending === 0) {
+ return createTable();
+ }
+
+ for (var i = 0; i < table.typequeries.length; i++) {
+ driver.execQuery(table.typequeries[i], function (err) {
+ if (--pending === 0) {
+ return createTable();
+ }
+ });
+ }
+}
+
+var colTypes = {
+ integer: { 2: 'SMALLINT', 4: 'INTEGER', 8: 'BIGINT' },
+ floating: { 4: 'REAL', 8: 'DOUBLE PRECISION' }
+};
+
+function buildColumnDefinition(driver, table, name, prop) {
+ var def = driver.query.escapeId(name);
+ var customType;
+
+ switch (prop.type) {
+ case "text":
+ if (prop.big === true) {
+ def += " TEXT";
+ } else {
+ def += " VARCHAR(" + Math.max(parseInt(prop.size, 10) || 255, 1) + ")";
+ }
+ break;
+ case "serial":
+ def += " SERIAL";
+ break;
+ case "number":
+ if (prop.rational === false) {
+ def += " " + colTypes.integer[prop.size || 4];
+ } else {
+ def += " " + colTypes.floating[prop.size || 4];
+ }
+ break;
+ case "boolean":
+ def += " BOOLEAN";
+ break;
+ case "date":
+ if (prop.time === false) {
+ def += " DATE";
+ } else {
+ def += " TIMESTAMP WITHOUT TIME ZONE";
+ }
+ break;
+ case "binary":
+ case "object":
+ def += " BYTEA";
+ break;
+ case "enum":
+ def += " " + driver.query.escapeId("enum_" + table + "_" + name);
+ break;
+ case "point":
+ def += " POINT";
+ break;
+ default:
+ customType = driver.customTypes[prop.type];
+ if (customType) {
+ def += " " + customType.datastoreType(prop);
+ } else {
+ throw ErrorCodes.generateError(ErrorCodes.NO_SUPPORT, "Unknown property type: '" + prop.type + "'", {
+ property : prop
+ });
+ }
+ }
+ if (prop.required === true) {
+ def += " NOT NULL";
+ }
+ if (prop.hasOwnProperty("defaultValue")) {
+ def += " DEFAULT " + driver.query.escapeVal(prop.defaultValue);
+ }
+ return def;
+}
diff --git a/lib/Drivers/DDL/sqlite.js b/lib/Drivers/DDL/sqlite.js
new file mode 100644
index 00000000..08c5a9cd
--- /dev/null
+++ b/lib/Drivers/DDL/sqlite.js
@@ -0,0 +1,176 @@
+var ErrorCodes = require("../../ErrorCodes");
+
+exports.drop = function (driver, opts, cb) {
+ var i, queries = [], pending;
+
+ queries.push("DROP TABLE IF EXISTS " + driver.query.escapeId(opts.table));
+
+ for (i = 0; i < opts.many_associations.length; i++) {
+ queries.push("DROP TABLE IF EXISTS " + driver.query.escapeId(opts.many_associations[i].mergeTable));
+ }
+
+ pending = queries.length;
+ for (i = 0; i < queries.length; i++) {
+ driver.db.all(queries[i], function (err) {
+ if (--pending === 0) {
+ return cb(err);
+ }
+ });
+ }
+};
+
+exports.sync = function (driver, opts, cb) {
+ var queries = [];
+ var definitions = [];
+ var k, i, pending, prop;
+ var primary_keys = opts.id.map(function (k) { return driver.query.escapeId(k); });
+ var keys = [];
+
+ for (k in opts.allProperties) {
+ prop = opts.allProperties[k];
+ definitions.push(buildColumnDefinition(driver, k, prop));
+ }
+
+ if (keys.length > 1) {
+ definitions.push("PRIMARY KEY (" + primary_keys.join(", ") + ")");
+ }
+
+ queries.push(
+ "CREATE TABLE IF NOT EXISTS " + driver.query.escapeId(opts.table) +
+ " (" + definitions.join(", ") + ")"
+ );
+ for (k in opts.properties) {
+ if (opts.properties[k].unique === true) {
+ queries.push(
+ "CREATE UNIQUE INDEX IF NOT EXISTS " + driver.query.escapeId(k) +
+ " ON " + driver.query.escapeId(opts.table) +
+ " (" + driver.query.escapeId(k) + ")"
+ );
+ } else if (opts.properties[k].index) {
+ queries.push(
+ "CREATE INDEX IF NOT EXISTS " + driver.query.escapeId(k) +
+ " ON " + driver.query.escapeId(opts.table) +
+ " (" + driver.query.escapeId(k) + ")"
+ );
+ }
+ }
+
+ for (i = 0; i < opts.one_associations.length; i++) {
+ if (opts.one_associations[i].extension) continue;
+ if (opts.one_associations[i].reversed) continue;
+ for (k in opts.one_associations[i].field) {
+ queries.push(
+ "CREATE INDEX IF NOT EXISTS " + driver.query.escapeId(opts.table + "_" + k) +
+ " ON " + driver.query.escapeId(opts.table) +
+ " (" + driver.query.escapeId(k) + ")"
+ );
+ }
+ }
+
+ for (i = 0; i < opts.indexes.length; i++) {
+ queries.push(
+ "CREATE INDEX IF NOT EXISTS " + driver.query.escapeId(opts.table + "_index" + i) +
+ " ON " + driver.query.escapeId(opts.table) +
+ " (" + opts.indexes[i].split(/[,;]+/).map(function (el) {
+ return driver.query.escapeId(el);
+ }).join(", ") + ")"
+ );
+ }
+
+ for (i = 0; i < opts.many_associations.length; i++) {
+ definitions = [];
+
+ for (k in opts.many_associations[i].mergeId) {
+ definitions.push(buildColumnDefinition(driver, k, opts.many_associations[i].mergeId[k]));
+ }
+
+ for (k in opts.many_associations[i].mergeAssocId) {
+ definitions.push(buildColumnDefinition(driver, k, opts.many_associations[i].mergeAssocId[k]));
+ }
+
+ for (k in opts.many_associations[i].props) {
+ definitions.push(buildColumnDefinition(driver, k, opts.many_associations[i].props[k]));
+ }
+
+ var index = null;
+ for (k in opts.many_associations[i].mergeId) {
+ if (index == null) index = driver.query.escapeId(k);
+ else index += ", " + driver.query.escapeId(k);
+ }
+
+ for (k in opts.many_associations[i].mergeAssocId) {
+ if (index == null) index = driver.query.escapeId(k);
+ else index += ", " + driver.query.escapeId(k);
+ }
+
+ queries.push(
+ "CREATE TABLE IF NOT EXISTS " + driver.query.escapeId(opts.many_associations[i].mergeTable) +
+ " (" + definitions.join(", ") + ")"
+ );
+ queries.push(
+ "CREATE INDEX IF NOT EXISTS " + driver.query.escapeId(opts.many_associations[i].mergeTable) +
+ " ON " + driver.query.escapeId(opts.table) +
+ " (" + index + ")"
+ );
+ }
+
+ pending = queries.length;
+ for (i = 0; i < queries.length; i++) {
+ driver.db.all(queries[i], function (err) {
+ // if (err) console.log(err);
+ if (--pending === 0) {
+ return cb(err);
+ }
+ });
+ }
+};
+
+function buildColumnDefinition(driver, name, prop) {
+ var def = driver.query.escapeId(name);
+ var customType;
+
+ switch (prop.type) {
+ case "text":
+ def += " TEXT";
+ break;
+ case "serial":
+ def += " INTEGER PRIMARY KEY AUTOINCREMENT";
+ break;
+ case "number":
+ if (prop.rational === false) {
+ def += " INTEGER";
+ } else {
+ def += " REAL";
+ }
+ break;
+ case "boolean":
+ def += " INTEGER UNSIGNED";
+ break;
+ case "date":
+ def += " DATETIME";
+ break;
+ case "binary":
+ case "object":
+ def += " BLOB";
+ break;
+ case "enum":
+ def += " INTEGER";
+ break;
+ default:
+ customType = driver.customTypes[prop.type];
+ if (customType) {
+ def += " " + customType.datastoreType(prop);
+ } else {
+ throw ErrorCodes.generateError(ErrorCodes.NO_SUPPORT, "Unknown property type: '" + prop.type + "'", {
+ property : prop
+ });
+ }
+ }
+ if (prop.required === true) {
+ def += " NOT NULL";
+ }
+ if (prop.hasOwnProperty("defaultValue")) {
+ def += " DEFAULT " + driver.query.escapeVal(prop.defaultValue);
+ }
+ return def;
+}
diff --git a/lib/Drivers/DML/mongodb.js b/lib/Drivers/DML/mongodb.js
index 45fc3657..5b15f30c 100644
--- a/lib/Drivers/DML/mongodb.js
+++ b/lib/Drivers/DML/mongodb.js
@@ -353,15 +353,7 @@ Driver.prototype.clear = function (table, cb) {
function convertToDB(obj, timeZone) {
for (var k in obj) {
- if ([ 'and', 'or', 'not' ].indexOf(k) >= 0) {
- for (var j = 0; j < obj[k].length; j++) {
- convertToDB(obj[k][j], timeZone);
- }
- obj['$' + k] = obj[k];
- delete obj[k];
- continue;
- }
- if (Array.isArray(obj[k]) && k[0] != '$') {
+ if (Array.isArray(obj[k])) {
for (var i = 0; i < obj[k].length; i++) {
obj[k][i] = convertToDBVal(k, obj[k][i], timeZone);
}
@@ -389,7 +381,7 @@ function convertFromDB(obj, timezone) {
function convertToDBVal(key, value, timezone) {
if (value && typeof value.sql_comparator == "function") {
- var val = (key != "_id" ? value : new mongodb.ObjectID(value));
+ var val = (key != "_id" ? value.val : new mongodb.ObjectID(value.val));
var comp = value.sql_comparator();
var condition = {};
@@ -399,10 +391,10 @@ function convertToDBVal(key, value, timezone) {
case "lt":
case "lte":
case "ne":
- condition["$" + comp] = val.val;
+ condition["$" + comp] = val;
break;
case "eq":
- condition = val.val;
+ condition = val;
break;
case "between":
condition["$min"] = val.from;
diff --git a/lib/Drivers/DML/mysql.js b/lib/Drivers/DML/mysql.js
old mode 100644
new mode 100755
index e00679a6..d73b5d08
--- a/lib/Drivers/DML/mysql.js
+++ b/lib/Drivers/DML/mysql.js
@@ -1,13 +1,11 @@
var _ = require("lodash");
var mysql = require("mysql");
var Query = require("sql-query").Query;
-var shared = require("./_shared");
-var DDL = require("../DDL/SQL");
+var helpers = require("../helpers");
exports.Driver = Driver;
function Driver(config, connection, opts) {
- this.dialect = 'mysql';
this.config = config || {};
this.opts = opts || {};
this.customTypes = {};
@@ -15,7 +13,7 @@ function Driver(config, connection, opts) {
if (!this.config.timezone) {
this.config.timezone = "local";
}
- this.query = new Query({ dialect: this.dialect, timezone: this.config.timezone });
+ this.query = new Query({ dialect: "mysql", timezone: config.timezone });
this.reconnect(null, connection);
@@ -28,7 +26,15 @@ function Driver(config, connection, opts) {
"DISTINCT"];
}
-_.extend(Driver.prototype, shared, DDL);
+_.extend(Driver.prototype, helpers.sql);
+
+Driver.prototype.sync = function (opts, cb) {
+ return require("../DDL/mysql").sync(this, opts, cb);
+};
+
+Driver.prototype.drop = function (opts, cb) {
+ return require("../DDL/mysql").drop(this, opts, cb);
+};
Driver.prototype.ping = function (cb) {
this.db.ping(cb);
@@ -133,24 +139,6 @@ Driver.prototype.find = function (fields, table, conditions, opts, cb) {
this.execSimpleQuery(q, cb);
};
-Driver.prototype.eagerQuery = function (association, opts, ids, cb) {
- var desiredKey = Object.keys(association.field);
- var assocKey = Object.keys(association.mergeAssocId);
-
- var where = {};
- where[desiredKey] = ids;
-
- var query = this.query.select()
- .from(association.model.table)
- .select(opts.only)
- .from(association.mergeTable, assocKey, opts.id)
- .select(desiredKey).as("$p")
- .where(association.mergeTable, where)
- .build();
-
- this.execSimpleQuery(query, cb);
-};
-
Driver.prototype.count = function (table, conditions, opts, cb) {
var q = this.query.select()
.from(table)
@@ -279,9 +267,7 @@ Driver.prototype.propertyToValue = function (value, property) {
value = (value) ? 1 : 0;
break;
case "object":
- if (value !== null) {
- value = JSON.stringify(value);
- }
+ value = JSON.stringify(value);
break;
case "point":
return function() { return 'POINT(' + value.x + ', ' + value.y + ')'; };
diff --git a/lib/Drivers/DML/postgres.js b/lib/Drivers/DML/postgres.js
index 874df631..12f13d74 100644
--- a/lib/Drivers/DML/postgres.js
+++ b/lib/Drivers/DML/postgres.js
@@ -1,18 +1,59 @@
var _ = require("lodash");
var pg = require("pg");
var Query = require("sql-query").Query;
-var shared = require("./_shared");
-var DDL = require("../DDL/SQL");
+var helpers = require("../helpers");
exports.Driver = Driver;
+function Driver(config, connection, opts) {
+ var functions = switchableFunctions.client;
+ this.config = config || {};
+ this.opts = opts || {};
+
+ if (!this.config.timezone) {
+ this.config.timezone = "local";
+ }
+
+ this.query = new Query({ dialect: "postgresql", timezone: this.config.timezone });
+ this.customTypes = {};
+
+ if (connection) {
+ this.db = connection;
+ } else {
+ if (this.config.query && this.config.query.ssl) {
+ config.ssl = true;
+ this.config = _.extend(this.config, config);
+ // } else {
+ // this.config = _.extend(this.config, config);
+ // this.config = config.href || config;
+ }
+
+ pg.types.setTypeParser(20, Number);
+
+ if (opts.pool) {
+ functions = switchableFunctions.pool;
+ this.db = pg;
+ } else {
+ this.db = new pg.Client(this.config);
+ }
+ }
+
+ _.extend(this.constructor.prototype, functions);
+
+ this.aggregate_functions = [ "ABS", "CEIL", "FLOOR", "ROUND",
+ "AVG", "MIN", "MAX",
+ "LOG", "EXP", "POWER",
+ "ACOS", "ASIN", "ATAN", "COS", "SIN", "TAN",
+ "RANDOM", "RADIANS", "DEGREES",
+ "SUM", "COUNT",
+ "DISTINCT" ];
+}
+
var switchableFunctions = {
pool: {
connect: function (cb) {
this.db.connect(this.config, function (err, client, done) {
- if (!err) {
- done();
- }
+ if (!err) done();
cb(err);
});
},
@@ -21,9 +62,7 @@ var switchableFunctions = {
require("../../Debug").sql('postgres', query);
}
this.db.connect(this.config, function (err, client, done) {
- if (err) {
- return cb(err);
- }
+ if (err) return cb(err);
client.query(query, function (err, result) {
done();
@@ -69,55 +108,15 @@ var switchableFunctions = {
}
};
-function Driver(config, connection, opts) {
- var functions = switchableFunctions.client;
-
- this.dialect = 'postgresql';
- this.config = config || {};
- this.opts = opts || {};
+_.extend(Driver.prototype, helpers.sql);
- if (!this.config.timezone) {
- this.config.timezone = "local";
- }
-
- this.query = new Query({ dialect: this.dialect, timezone: this.config.timezone });
- this.customTypes = {};
-
- if (connection) {
- this.db = connection;
- } else {
- if (this.config.query && this.config.query.ssl) {
- config.ssl = true;
- this.config = _.extend(this.config, config);
- // } else {
- // this.config = _.extend(this.config, config);
- // this.config = config.href || config;
- }
-
- pg.types.setTypeParser(20, Number);
-
- if (opts.pool) {
- functions = switchableFunctions.pool;
- this.db = pg;
- } else {
- this.db = new pg.Client(this.config);
- }
- }
-
- _.extend(this.constructor.prototype, functions);
-
- this.aggregate_functions = [
- "ABS", "CEIL", "FLOOR", "ROUND",
- "AVG", "MIN", "MAX",
- "LOG", "EXP", "POWER",
- "ACOS", "ASIN", "ATAN", "COS", "SIN", "TAN",
- "RANDOM", "RADIANS", "DEGREES",
- "SUM", "COUNT",
- "DISTINCT"
- ];
-}
+Driver.prototype.sync = function (opts, cb) {
+ return require("../DDL/postgres").sync(this, opts, cb);
+};
-_.extend(Driver.prototype, shared, DDL);
+Driver.prototype.drop = function (opts, cb) {
+ return require("../DDL/postgres").drop(this, opts, cb);
+};
Driver.prototype.ping = function (cb) {
this.execSimpleQuery("SELECT * FROM pg_stat_activity LIMIT 1", function () {
@@ -139,7 +138,8 @@ Driver.prototype.getQuery = function () {
};
Driver.prototype.find = function (fields, table, conditions, opts, cb) {
- var q = this.query.select().from(table).select(fields);
+ var q = this.query.select()
+ .from(table).select(fields);
if (opts.offset) {
q.offset(opts.offset);
@@ -175,26 +175,10 @@ Driver.prototype.find = function (fields, table, conditions, opts, cb) {
this.execSimpleQuery(q, cb);
};
-Driver.prototype.eagerQuery = function (association, opts, ids, cb) {
- var desiredKey = Object.keys(association.field);
- var assocKey = Object.keys(association.mergeAssocId);
-
- var where = {};
- where[desiredKey] = ids;
-
- var query = this.query.select()
- .from(association.model.table)
- .select(opts.only)
- .from(association.mergeTable, assocKey, opts.id)
- .select(desiredKey).as("$p")
- .where(association.mergeTable, where)
- .build();
-
- this.execSimpleQuery(query, cb);
-};
-
Driver.prototype.count = function (table, conditions, opts, cb) {
- var q = this.query.select().from(table).count(null, 'c');
+ var q = this.query.select()
+ .from(table)
+ .count(null, 'c');
if (opts.merge) {
q.from(opts.merge.from.table, opts.merge.from.field, opts.merge.to.field);
@@ -219,7 +203,10 @@ Driver.prototype.count = function (table, conditions, opts, cb) {
};
Driver.prototype.insert = function (table, data, id_prop, cb) {
- var q = this.query.insert().into(table).set(data).build();
+ var q = this.query.insert()
+ .into(table)
+ .set(data)
+ .build();
this.execSimpleQuery(q + " RETURNING *", function (err, results) {
if (err) {
@@ -239,13 +226,20 @@ Driver.prototype.insert = function (table, data, id_prop, cb) {
};
Driver.prototype.update = function (table, changes, conditions, cb) {
- var q = this.query.update().into(table).set(changes).where(conditions).build();
+ var q = this.query.update()
+ .into(table)
+ .set(changes)
+ .where(conditions)
+ .build();
this.execSimpleQuery(q, cb);
};
Driver.prototype.remove = function (table, conditions, cb) {
- var q = this.query.remove().from(table).where(conditions).build();
+ var q = this.query.remove()
+ .from(table)
+ .where(conditions)
+ .build();
this.execSimpleQuery(q, cb);
};
@@ -273,7 +267,6 @@ Driver.prototype.valueToProperty = function (value, property) {
case "point":
if (typeof value == "string") {
var m = value.match(/\((\-?[\d\.]+)[\s,]+(\-?[\d\.]+)\)/);
-
if (m) {
value = { x : parseFloat(m[1], 10) , y : parseFloat(m[2], 10) };
}
@@ -294,15 +287,12 @@ Driver.prototype.valueToProperty = function (value, property) {
case "number":
if (typeof value != 'number' && value !== null) {
v = Number(value);
- if (!isNaN(v)) {
- value = v;
- }
+ if (!isNaN(v)) value = v;
}
break;
default:
customType = this.customTypes[property.type];
-
- if (customType && 'valueToProperty' in customType) {
+ if(customType && 'valueToProperty' in customType) {
value = customType.valueToProperty(value);
}
}
@@ -314,9 +304,7 @@ Driver.prototype.propertyToValue = function (value, property) {
switch (property.type) {
case "object":
- if (value !== null && !Buffer.isBuffer(value)) {
- value = new Buffer(JSON.stringify(value));
- }
+ value = JSON.stringify(value);
break;
case "date":
if (this.config.timezone && this.config.timezone != 'local') {
@@ -337,8 +325,7 @@ Driver.prototype.propertyToValue = function (value, property) {
break;
default:
customType = this.customTypes[property.type];
-
- if (customType && 'propertyToValue' in customType) {
+ if(customType && 'propertyToValue' in customType) {
value = customType.propertyToValue(value);
}
}
@@ -350,12 +337,9 @@ Object.defineProperty(Driver.prototype, "isSql", {
});
function convertTimezone(tz) {
- if (tz == "Z") {
- return 0;
- }
+ if (tz == "Z") return 0;
var m = tz.match(/([\+\-\s])(\d\d):?(\d\d)?/);
-
if (m) {
return (m[1] == '-' ? -1 : 1) * (parseInt(m[2], 10) + ((m[3] ? parseInt(m[3], 10) : 0) / 60)) * 60;
}
diff --git a/lib/Drivers/DML/sqlite.js b/lib/Drivers/DML/sqlite.js
index 63b6a043..023ffecf 100644
--- a/lib/Drivers/DML/sqlite.js
+++ b/lib/Drivers/DML/sqlite.js
@@ -2,13 +2,11 @@ var _ = require("lodash");
var util = require("util");
var sqlite3 = require("sqlite3");
var Query = require("sql-query").Query;
-var shared = require("./_shared");
-var DDL = require("../DDL/SQL");
+var helpers = require("../helpers");
exports.Driver = Driver;
function Driver(config, connection, opts) {
- this.dialect = 'sqlite';
this.config = config || {};
this.opts = opts || {};
@@ -16,7 +14,7 @@ function Driver(config, connection, opts) {
this.config.timezone = "local";
}
- this.query = new Query({ dialect: this.dialect, timezone: this.config.timezone });
+ this.query = new Query({ dialect: "sqlite", timezone: this.config.timezone });
this.customTypes = {};
if (connection) {
@@ -25,7 +23,7 @@ function Driver(config, connection, opts) {
// on Windows, paths have a drive letter which is parsed by
// url.parse() as the hostname. If host is defined, assume
// it's the drive letter and add ":"
- if (process.platform == "win32" && config.host && config.host.match(/^[a-z]$/i)) {
+ if (process.platform == "win32" && config.host.match(/^[a-z]$/i)) {
this.db = new sqlite3.Database(((config.host ? config.host + ":" : "") + (config.pathname || "")) || ':memory:');
} else {
this.db = new sqlite3.Database(((config.host ? config.host : "") + (config.pathname || "")) || ':memory:');
@@ -39,7 +37,15 @@ function Driver(config, connection, opts) {
"DISTINCT" ];
}
-_.extend(Driver.prototype, shared, DDL);
+_.extend(Driver.prototype, helpers.sql);
+
+Driver.prototype.sync = function (opts, cb) {
+ return require("../DDL/sqlite").sync(this, opts, cb);
+};
+
+Driver.prototype.drop = function (opts, cb) {
+ return require("../DDL/sqlite").drop(this, opts, cb);
+};
Driver.prototype.ping = function (cb) {
process.nextTick(cb);
@@ -68,7 +74,7 @@ Driver.prototype.getQuery = function () {
Driver.prototype.execSimpleQuery = function (query, cb) {
if (this.opts.debug) {
- require("../../Debug").sql('sqlite', query);
+ require("../../Debug").sql('mysql', query);
}
this.db.all(query, cb);
};
@@ -117,24 +123,6 @@ Driver.prototype.find = function (fields, table, conditions, opts, cb) {
this.db.all(q, cb);
};
-Driver.prototype.eagerQuery = function (association, opts, ids, cb) {
- var desiredKey = Object.keys(association.field);
- var assocKey = Object.keys(association.mergeAssocId);
-
- var where = {};
- where[desiredKey] = ids;
-
- var query = this.query.select()
- .from(association.model.table)
- .select(opts.only)
- .from(association.mergeTable, assocKey, opts.id)
- .select(desiredKey).as("$p")
- .where(association.mergeTable, where)
- .build();
-
- this.execSimpleQuery(query, cb);
-};
-
Driver.prototype.count = function (table, conditions, opts, cb) {
var q = this.query.select()
.from(table)
@@ -285,9 +273,7 @@ Driver.prototype.propertyToValue = function (value, property) {
value = (value) ? 1 : 0;
break;
case "object":
- if (value !== null) {
- value = JSON.stringify(value);
- }
+ value = JSON.stringify(value);
break;
case "date":
if (this.config.query && this.config.query.strdates) {
diff --git a/lib/Drivers/DML/_shared.js b/lib/Drivers/helpers.js
similarity index 92%
rename from lib/Drivers/DML/_shared.js
rename to lib/Drivers/helpers.js
index fcc20f00..dce8a0e3 100644
--- a/lib/Drivers/DML/_shared.js
+++ b/lib/Drivers/helpers.js
@@ -1,5 +1,5 @@
-module.exports = {
+module.exports.sql = {
execQuery: function () {
if (arguments.length == 2) {
var query = arguments[0];
@@ -10,4 +10,4 @@ module.exports = {
}
return this.execSimpleQuery(query, cb);
}
-};
+}
diff --git a/lib/Error.js b/lib/Error.js
deleted file mode 100644
index b1013811..00000000
--- a/lib/Error.js
+++ /dev/null
@@ -1,39 +0,0 @@
-var codes = {
- QUERY_ERROR : 1,
- NOT_FOUND : 2,
- NOT_DEFINED : 3,
- NO_SUPPORT : 4,
- MISSING_CALLBACK : 5,
- PARAM_MISMATCH : 6,
- CONNECTION_LOST : 10
-}
-
-function ORMError(message, code, extras) {
- Error.call(this);
- Error.captureStackTrace(this, this.constructor);
-
- this.message = message;
- if (code) {
- this.code = codes[code];
- this.literalCode = code;
- if (!this.code) {
- throw new Error("Invalid error code: " + code);
- }
- }
- if (extras) {
- for(var k in extras) {
- this[k] = extras[k];
- }
- }
-}
-
-ORMError.prototype = Object.create(Error.prototype);
-ORMError.prototype.constructor = ORMError;
-ORMError.prototype.name = 'ORMError';
-ORMError.prototype.toString = function () {
- return '[ORMError ' + this.literalCode + ': ' + this.message + ']';
-}
-
-ORMError.codes = codes;
-
-module.exports = ORMError;
diff --git a/lib/ErrorCodes.js b/lib/ErrorCodes.js
index e3ed8d8d..5df4fbeb 100644
--- a/lib/ErrorCodes.js
+++ b/lib/ErrorCodes.js
@@ -1,2 +1,32 @@
-// Moved to 'Error.js'
-module.exports = require('./error').codes;
+exports.QUERY_ERROR = 1;
+exports.NOT_FOUND = 2;
+exports.NOT_DEFINED = 3;
+exports.NO_SUPPORT = 4;
+exports.MISSING_CALLBACK = 5;
+exports.PARAM_MISMATCH = 6;
+
+exports.CONNECTION_LOST = 10;
+
+// Deprecated, remove on next major release.
+Object.defineProperty(exports, "PARAM_MISSMATCH", {
+ enumerable: true, get: function () {
+ console.log("PARAM_MISSMATCH spelling is deprecated. Use PARAM_MISMATCH instead");
+ return exports.PARAM_MISMATCH;
+ }
+});
+
+Object.defineProperty(exports, "generateError", {
+ value: function (code, message, extra) {
+ var err = new Error(message);
+ err.code = code;
+
+ if (extra) {
+ for (var k in extra) {
+ err[k] = extra[k];
+ }
+ }
+
+ return err;
+ },
+ enumerable : false
+});
diff --git a/lib/Express.js b/lib/Express.js
index 8851d796..37bad496 100644
--- a/lib/Express.js
+++ b/lib/Express.js
@@ -47,11 +47,6 @@ module.exports = function (uri, opts) {
req.db = _db;
}
- if (next === undefined && typeof res === 'function')
- {
- next = res;
- }
-
if (_pending > 0) {
_queue.push(next);
return;
diff --git a/lib/Instance.js b/lib/Instance.js
index be1682ab..68f624b8 100755
--- a/lib/Instance.js
+++ b/lib/Instance.js
@@ -97,7 +97,7 @@ function Instance(Model, opts) {
cb(err, instance);
}
};
- var saveInstance = function (saveOptions, cb) {
+ var saveInstance = function (cb, saveOptions) {
// what this condition means:
// - If the instance is in state mode
// - AND it's not an association that is asking it to save
@@ -118,7 +118,7 @@ function Instance(Model, opts) {
return saveError(cb, err);
}
- return saveNew(saveOptions, getInstanceData(), cb);
+ return saveNew(cb, saveOptions, getInstanceData());
});
} else {
waitHooks([ "beforeSave" ], function (err) {
@@ -126,12 +126,21 @@ function Instance(Model, opts) {
return saveError(cb, err);
}
- return savePersisted(saveOptions, getInstanceData(), cb);
+ if (opts.changes.length === 0) {
+ if (saveOptions.saveAssociations === false) {
+ return saveInstanceExtra(cb);
+ }
+ return saveAssociations(function (err) {
+ return afterSave(cb, false, err);
+ });
+ }
+
+ return savePersisted(cb, saveOptions, getInstanceData());
});
}
});
};
- var runAfterSaveActions = function (cb, create, err) {
+ var afterSave = function (cb, create, err) {
instance_saving = false;
emitEvent("save", err, instance);
@@ -141,7 +150,9 @@ function Instance(Model, opts) {
}
Hook.trigger(instance, opts.hooks.afterSave, !err);
- cb();
+ if (!err) {
+ saveInstanceExtra(cb);
+ }
};
var getInstanceData = function () {
var data = {}, prop;
@@ -179,13 +190,8 @@ function Instance(Model, opts) {
return nextHook();
};
- var saveNew = function (saveOptions, data, cb) {
- var finish = function (err) {
- runAfterSaveActions(function () {
- if (err) return cb(err);
- saveInstanceExtra(cb);
- }, true);
- }
+ var saveNew = function (cb, saveOptions, data) {
+ var next = afterSave.bind(this, cb, true);
opts.driver.insert(opts.table, data, opts.id, function (save_err, info) {
if (save_err) {
@@ -199,56 +205,36 @@ function Instance(Model, opts) {
opts.is_new = false;
if (saveOptions.saveAssociations === false) {
- return finish();
+ return next();
}
- return saveAssociations(finish);
+ return saveAssociations(next);
});
};
- var savePersisted = function (saveOptions, data, cb) {
+ var savePersisted = function (cb, saveOptions, data) {
+ var next = afterSave.bind(this, cb, false);
var changes = {}, conditions = {};
- var next = function (saved) {
- var finish = function () {
- saveInstanceExtra(cb);
- }
-
- if(!saved && saveOptions.saveAssociations === false) {
- finish();
- } else {
- if (saveOptions.saveAssociations === false) {
- runAfterSaveActions(function () {
- finish();
- }, false);
- } else {
- saveAssociations(function (err) {
- runAfterSaveActions(function () {
- if (err) return cb(err);
- finish();
- }, false, err);
- });
- }
- }
+ for (var i = 0; i < opts.changes.length; i++) {
+ changes[opts.changes[i]] = data[opts.changes[i]];
+ }
+ for (i = 0; i < opts.id.length; i++) {
+ conditions[opts.id[i]] = data[opts.id[i]];
}
- if (opts.changes.length === 0) {
- next(false);
- } else {
- for (var i = 0; i < opts.changes.length; i++) {
- changes[opts.changes[i]] = data[opts.changes[i]];
+ opts.driver.update(opts.table, changes, conditions, function (save_err) {
+ if (save_err) {
+ return saveError(cb, save_err);
}
- for (i = 0; i < opts.id.length; i++) {
- conditions[opts.id[i]] = data[opts.id[i]];
+
+ opts.changes.length = 0;
+
+ if (saveOptions.saveAssociations === false) {
+ return next();
}
- opts.driver.update(opts.table, changes, conditions, function (err) {
- if (err) {
- return saveError(cb, err);
- }
- opts.changes.length = 0;
- next(true);
- });
- }
+ return saveAssociations(next);
+ });
};
var saveAssociations = function (cb) {
var pending = 1, errored = false, i, j;
@@ -270,45 +256,45 @@ function Instance(Model, opts) {
};
var _saveOneAssociation = function (assoc) {
- if (!instance[assoc.name] || typeof instance[assoc.name] !== "object") return;
- if (assoc.reversed) {
- // reversed hasOne associations should behave like hasMany
- if (!Array.isArray(instance[assoc.name])) {
- instance[assoc.name] = [ instance[assoc.name] ];
- }
- for (var i = 0; i < instance[assoc.name].length; i++) {
- if (!instance[assoc.name][i].isInstance) {
- instance[assoc.name][i] = new assoc.model(instance[assoc.name][i]);
- }
- saveAssociation(assoc.setAccessor, instance[assoc.name][i]);
- }
- return;
- }
- if (!instance[assoc.name].isInstance) {
- instance[assoc.name] = new assoc.model(instance[assoc.name]);
- }
+ if (!instance[assoc.name] || typeof instance[assoc.name] !== "object") return;
+ if (assoc.reversed) {
+ // reversed hasOne associations should behave like hasMany
+ if (!Array.isArray(instance[assoc.name])) {
+ instance[assoc.name] = [ instance[assoc.name] ];
+ }
+ for (var i = 0; i < instance[assoc.name].length; i++) {
+ if (!instance[assoc.name][i].isInstance) {
+ instance[assoc.name][i] = new assoc.model(instance[assoc.name][i]);
+ }
+ saveAssociation(assoc.setAccessor, instance[assoc.name][i]);
+ }
+ return;
+ }
+ if (!instance[assoc.name].isInstance) {
+ instance[assoc.name] = new assoc.model(instance[assoc.name]);
+ }
- saveAssociation(assoc.setAccessor, instance[assoc.name]);
+ saveAssociation(assoc.setAccessor, instance[assoc.name]);
};
for (i = 0; i < opts.one_associations.length; i++) {
- _saveOneAssociation(opts.one_associations[i]);
+ _saveOneAssociation(opts.one_associations[i]);
}
var _saveManyAssociation = function (assoc) {
- if (!instance.hasOwnProperty(assoc.name)) return;
- if (!Array.isArray(instance[assoc.name])) {
- instance[assoc.name] = [ instance[assoc.name] ];
- }
+ if (!instance.hasOwnProperty(assoc.name)) return;
+ if (!Array.isArray(instance[assoc.name])) {
+ instance[assoc.name] = [ instance[assoc.name] ];
+ }
- for (j = 0; j < instance[assoc.name].length; j++) {
- if (!instance[assoc.name][j].isInstance) {
- instance[assoc.name][j] = new assoc.model(instance[assoc.name][j]);
- }
- }
+ for (j = 0; j < instance[assoc.name].length; j++) {
+ if (!instance[assoc.name][j].isInstance) {
+ instance[assoc.name][j] = new assoc.model(instance[assoc.name][j]);
+ }
+ }
- return saveAssociation(assoc.setAccessor, instance[assoc.name]);
+ return saveAssociation(assoc.setAccessor, instance[assoc.name]);
};
for (i = 0; i < opts.many_associations.length; i++) {
@@ -342,12 +328,12 @@ function Instance(Model, opts) {
}
for (i = 0; i < opts.extra_info.id.length; i++) {
- conditions[opts.extra_info.id_prop[i]] = opts.extra_info.id[i];
- conditions[opts.extra_info.assoc_prop[i]] = opts.data[opts.id[i]];
+ conditions[opts.extra_info.id_prop[i]] = opts.extra_info.id[i];
+ conditions[opts.extra_info.assoc_prop[i]] = opts.data[opts.id[i]];
}
opts.driver.update(opts.extra_info.table, data, conditions, function (err) {
- return cb(err);
+ if (cb) return cb(err, instance);
});
};
var removeInstance = function (cb) {
@@ -503,7 +489,7 @@ function Instance(Model, opts) {
Object.defineProperty(instance, k, {
value : opts.methods[k].bind(instance),
enumerable : false,
- writable : true
+ writeable : true
});
}
@@ -520,13 +506,12 @@ function Instance(Model, opts) {
return this;
},
- enumerable: false,
- writable: true
+ enumerable: false
});
Object.defineProperty(instance, "save", {
value: function () {
var arg = null, objCount = 0;
- var data = {}, saveOptions = {}, cb = null;
+ var data = {}, saveOptions = {}, callback = null;
while (arguments.length > 0) {
arg = Array.prototype.shift.call(arguments);
@@ -544,7 +529,7 @@ function Instance(Model, opts) {
objCount++;
break;
case 'function':
- cb = arg;
+ callback = arg;
break;
default:
var err = new Error("Unknown parameter type '" + (typeof arg) + "' in Instance.save()");
@@ -559,24 +544,17 @@ function Instance(Model, opts) {
}
}
- saveInstance(saveOptions, function (err) {
- if (!cb) return;
- if (err) return cb(err);
-
- return cb(null, instance);
- });
+ saveInstance(callback, saveOptions);
return this;
},
- enumerable: false,
- writable: true
+ enumerable: false
});
Object.defineProperty(instance, "saved", {
value: function () {
return opts.changes.length === 0;
},
- enumerable: false,
- writable: true
+ enumerable: false
});
Object.defineProperty(instance, "remove", {
value: function (cb) {
@@ -584,8 +562,7 @@ function Instance(Model, opts) {
return this;
},
- enumerable: false,
- writable: true
+ enumerable: false
});
Object.defineProperty(instance, "isInstance", {
value: true,
@@ -595,8 +572,7 @@ function Instance(Model, opts) {
value: function () {
return !opts.is_new;
},
- enumerable: false,
- writable: true
+ enumerable: false
});
Object.defineProperty(instance, "isShell", {
value: function () {
@@ -610,8 +586,7 @@ function Instance(Model, opts) {
cb(null, errors || false);
});
},
- enumerable: false,
- writable: true
+ enumerable: false
});
Object.defineProperty(instance, "__singleton_uid", {
value: function (cb) {
diff --git a/lib/Model.js b/lib/Model.js
index feab1488..188ba3a9 100644
--- a/lib/Model.js
+++ b/lib/Model.js
@@ -8,7 +8,7 @@ var Property = require("./Property");
var Singleton = require("./Singleton");
var Utilities = require("./Utilities");
var Validators = require("./Validators");
-var ORMError = require("./Error");
+var ErrorCodes = require("./ErrorCodes");
var Hook = require("./Hook");
var AvailableHooks = [
"beforeCreate", "afterCreate",
@@ -206,7 +206,7 @@ function Model(opts) {
return this;
}
- return cb(new ORMError("Driver does not support Model.drop()", 'NO_SUPPORT', { model: opts.table }));
+ return cb(ErrorCodes.generateError(ErrorCodes.NO_SUPPORT, "Driver does not support Model.drop()", { model: opts.table }));
};
model.sync = function (cb) {
@@ -234,7 +234,7 @@ function Model(opts) {
return this;
}
- return cb(new ORMError("Driver does not support Model.sync()", 'NO_SUPPORT', { model: opts.table }));
+ return cb(ErrorCodes.generateError(ErrorCodes.NO_SUPPORT, "Driver does not support Model.sync()", { model: opts.table }));
};
model.get = function () {
@@ -244,7 +244,7 @@ function Model(opts) {
var cb = ids.pop();
if (typeof cb !== "function") {
- throw new ORMError("Missing Model.get() callback", 'MISSING_CALLBACK', { model: opts.table });
+ throw ErrorCodes.generateError(ErrorCodes.MISSING_CALLBACK, "Missing Model.get() callback", { model: opts.table });
}
if (typeof ids[ids.length - 1] === "object" && !Array.isArray(ids[ids.length - 1])) {
@@ -256,7 +256,7 @@ function Model(opts) {
}
if (ids.length !== opts.id.length) {
- throw new ORMError("Model.get() IDs number mismatch (" + opts.id.length + " needed, " + ids.length + " passed)", 'PARAM_MISMATCH', { model: opts.table });
+ throw ErrorCodes.generateError(ErrorCodes.PARAM_MISMATCH, "Model.get() IDs number mismatch (" + opts.id.length + " needed, " + ids.length + " passed)", { model: opts.table });
}
for (var i = 0; i < opts.id.length; i++) {
@@ -275,10 +275,10 @@ function Model(opts) {
opts.driver.find(model_fields, opts.table, conditions, { limit: 1 }, function (err, data) {
if (err) {
- return cb(new ORMError(err.message, 'QUERY_ERROR', { originalCode: err.code }));
+ return cb(ErrorCodes.generateError(ErrorCodes.QUERY_ERROR, err.message, { originalCode: err.code }));
}
if (data.length === 0) {
- return cb(new ORMError("Not found", 'NOT_FOUND', { model: opts.table }));
+ return cb(ErrorCodes.generateError(ErrorCodes.NOT_FOUND, "Not found", { model: opts.table }));
}
var uid = opts.driver.uid + "/" + opts.table + "/" + ids.join("/");
@@ -426,7 +426,7 @@ function Model(opts) {
}
if (cb === null) {
- throw new ORMError("Missing Model.one() callback", 'MISSING_CALLBACK', { model: opts.table });
+ throw ErrorCodes.generateError(ErrorCodes.MISSING_CALLBACK, "Missing Model.one() callback", { model: opts.table });
}
// add limit 1
@@ -457,7 +457,7 @@ function Model(opts) {
}
if (typeof cb !== "function") {
- throw new ORMError('MISSING_CALLBACK', "Missing Model.count() callback", { model: opts.table });
+ throw ErrorCodes.generateError(ErrorCodes.MISSING_CALLBACK, "Missing Model.count() callback", { model: opts.table });
}
if (conditions) {
@@ -505,7 +505,7 @@ function Model(opts) {
var cb = ids.pop();
if (typeof cb !== "function") {
- throw new ORMError("Missing Model.exists() callback", 'MISSING_CALLBACK', { model: opts.table });
+ throw ErrorCodes.generateError(ErrorCodes.MISSING_CALLBACK, "Missing Model.exists() callback", { model: opts.table });
}
var conditions = {}, i;
diff --git a/lib/ORM.js b/lib/ORM.js
index c303c477..fff4dd7a 100644
--- a/lib/ORM.js
+++ b/lib/ORM.js
@@ -10,7 +10,7 @@ var Model = require("./Model").Model;
var DriverAliases = require("./Drivers/aliases");
var Settings = require("./Settings");
var Singleton = require("./Singleton");
-var ORMError = require("./Error");
+var ErrorCodes = require("./ErrorCodes");
var Utilities = require("./Utilities");
// Deprecated, use enforce
@@ -27,7 +27,7 @@ exports.settings = new Settings.Container(Settings.defaults());
exports.Property = require("./Property");
exports.Settings = Settings;
-exports.ErrorCodes = ORMError.codes;
+exports.ErrorCodes = ErrorCodes;
exports.Text = Query.Text;
for (var k in Query.Comparators) {
@@ -63,11 +63,11 @@ exports.use = function (connection, proto, opts, cb) {
exports.connect = function (opts, cb) {
if (arguments.length === 0 || !opts) {
- return ORM_Error(new ORMError("CONNECTION_URL_EMPTY", 'PARAM_MISMATCH'), cb);
+ return ORM_Error(ErrorCodes.generateError(ErrorCodes.PARAM_MISMATCH, "CONNECTION_URL_EMPTY"), cb);
}
if (typeof opts === "string") {
if (opts.replace(/\s+/, "").length === 0) {
- return ORM_Error(new ORMError("CONNECTION_URL_EMPTY", 'PARAM_MISMATCH'), cb);
+ return ORM_Error(ErrorCodes.generateError(ErrorCodes.PARAM_MISMATCH, "CONNECTION_URL_EMPTY"), cb);
}
opts = url.parse(opts, true);
for(var k in opts.query) {
@@ -81,7 +81,7 @@ exports.connect = function (opts, cb) {
opts.database = (opts.pathname ? opts.pathname.substr(1) : "");
}
if (!opts.protocol) {
- return ORM_Error(new ORMError("CONNECTION_URL_NO_PROTOCOL", 'PARAM_MISMATCH'), cb);
+ return ORM_Error(ErrorCodes.generateError(ErrorCodes.PARAM_MISMATCH, "CONNECTION_URL_NO_PROTOCOL"), cb);
}
// if (!opts.host) {
// opts.host = opts.hostname = "localhost";
@@ -112,8 +112,8 @@ exports.connect = function (opts, cb) {
var debug = extractOption(opts, "debug");
var pool = extractOption(opts, "pool");
var driver = new Driver(opts, null, {
- debug : (debug !== null ? ((debug === "false" || debug === "0") ? false : true) : settings.get("connection.debug")),
- pool : (pool !== null ? ((pool === "false" || pool === "0") ? false : true) : settings.get("connection.pool")),
+ debug : (debug !== null ? Boolean(debug) : settings.get("connection.debug")),
+ pool : (pool !== null ? Boolean(pool) : settings.get("connection.pool")),
settings : settings
});
@@ -132,7 +132,7 @@ exports.connect = function (opts, cb) {
});
} catch (ex) {
if (ex.code === "MODULE_NOT_FOUND" || ex.message.indexOf('find module')) {
- return ORM_Error(new ORMError("Connection protocol not supported - have you installed the database driver for " + proto + "?", 'NO_SUPPORT'), cb);
+ return ORM_Error(ErrorCodes.generateError(ErrorCodes.NO_SUPPORT, "CONNECTION_PROTOCOL_NOT_SUPPORTED"), cb);
}
return ORM_Error(ex, cb);
}
@@ -161,7 +161,7 @@ function ORM(driver_name, driver, settings) {
var onError = function (err) {
if (this.settings.get("connection.reconnect")) {
if (typeof this.driver.reconnect === "undefined") {
- return this.emit("error", new ORMError("Connection lost - driver does not support reconnection", 'CONNECTION_LOST'));
+ return this.emit("error", ErrorCodes.generateError(ErrorCodes.CONNECTION_LOST, "Connection lost - driver does not support reconnection"));
}
this.driver.reconnect(function () {
this.driver.on("error", onError);
diff --git a/lib/Property.js b/lib/Property.js
index a859f68e..e8a00933 100644
--- a/lib/Property.js
+++ b/lib/Property.js
@@ -1,4 +1,4 @@
-var ORMError = require("./Error");
+var ErrorCodes = require("./ErrorCodes");
exports.normalize = function (prop, customTypes, Settings) {
if (typeof prop === "function") {
@@ -32,7 +32,7 @@ exports.normalize = function (prop, customTypes, Settings) {
if ([ "text", "number", "boolean", "date", "enum", "object", "binary", "point" ].indexOf(prop.type) === -1) {
if (!(prop.type in customTypes)) {
- throw new ORMError("Unknown property type: " + prop.type, 'NO_SUPPORT');
+ throw ErrorCodes.generateError(ErrorCodes.NO_SUPPORT, "Unknown property type: " + prop.type);
}
}
@@ -40,10 +40,6 @@ exports.normalize = function (prop, customTypes, Settings) {
prop.required = true;
}
- if (prop.type == "number" && !prop.hasOwnProperty("rational")) {
- prop.rational = true;
- }
-
return prop;
};
diff --git a/lib/Settings.js b/lib/Settings.js
index 47aeaee1..5737f948 100644
--- a/lib/Settings.js
+++ b/lib/Settings.js
@@ -16,7 +16,7 @@ var default_settings = {
},
connection : {
reconnect : true,
- pool : false,
+ poll : false,
debug : false
}
};
diff --git a/lib/TypeScript/orm.d.ts b/lib/TypeScript/orm.d.ts
index 7ad22f86..5b65f94a 100644
--- a/lib/TypeScript/orm.d.ts
+++ b/lib/TypeScript/orm.d.ts
@@ -1,275 +1,240 @@
-///
-
-declare module "orm" {
-
- import events = require('events');
- import sqlquery = require('sqlquery');
-
- module orm {
-
- /**
- * Parameter Type Interfaces
- **/
-
- export interface Model {
- (): Instance;
- (...ids: any[]): Instance;
-
- properties: { [property: string]: Property };
- settings: Settings;
-
- drop(callback?: (err: Error) => void): Model;
- sync(callback?: (err: Error) => void): Model;
- get(...args: any[]): Model;
- find(conditions: { [property: string]: any }, callback: (err: Error, results: Instance[]) => void): Model;
- find(conditions: { [property: string]: any }, options: {
- limit?: number;
- order?: any;
- }, callback: (err: Error, results: Instance[]) => void): Model;
- find(conditions: { [property: string]: any }, limit: number, order: string[], callback: (err: Error, results: Instance[]) => void): Model;
- find(conditions: { [property: string]: any }): IChainFind;
-
- all(conditions: { [property: string]: any }, callback: (err: Error, results: Instance[]) => void): Model;
- all(conditions: { [property: string]: any }, options: {
- limit?: number;
- order?: any;
- }, callback: (err: Error, results: Instance[]) => void): Model;
- all(conditions: { [property: string]: any }, limit: number, order: string[], callback: (err: Error, results: Instance[]) => void): Model;
-
- one(conditions: { [property: string]: any }, callback: (err: Error, result: Instance) => void): Model;
- one(conditions: { [property: string]: any }, options: {
- limit?: number;
- order?: any;
- }, callback: (err: Error, result: Instance) => void): Model;
- one(conditions: { [property: string]: any }, limit: number, order: string[], callback: (err: Error, result: Instance) => void): Model;
-
- count(callback: (err: Error, count: number) => void): Model;
- count(conditions: { [property: string]: any }, callback: (err: Error, count: number) => void): Model;
-
- aggregate(conditions: { [property: string]: any }): IAggregated;
- aggregate(properties: string[]): IAggregated;
- aggregate(conditions: { [property: string]: any }, properties: string[]): IAggregated;
-
- exists(id: any, callback: (err: Error, exists: boolean) => void): Model;
- exists(...args: any[]): Model;
-
- create(data: { [property: string]: any; }, callback: (err: Error, instance: Instance) => void): Model;
- create(...args: any[]): Model;
-
- clear(): Model;
-
- table: string;
- id: string[];
-
- [property: string]: any;
- }
-
- export interface Instance {
- on(event: string, callback): Instance;
- save(): Instance;
- save(data: { [property: string]: any; }, callback: (err: Error) => void): Instance;
- save(data: { [property: string]: any; }, options: any, callback: (err: Error) => void): Instance;
- saved: boolean;
- remove(callback: (err: Error) => void): Instance;
- isInstance: boolean;
- isPersisted: boolean;
- isShell: boolean;
- validate(callback: (errors: Error[]) => void);
- model: Model;
-
- [property: string]: any;
- }
-
- export interface ModelOptions {
- id?: string[];
- autoFetch?: boolean;
- autoFetchLimit?: number;
- cacheFetch?: boolean;
- hooks?: { [property: string]: Hooks };
- methods?: { [name: string]: Function };
- }
-
- export interface Hooks {
- beforeValidation?: (next?) => void;
- beforeCreate?: (next?) => void;
- afterCreate?: (next?) => void;
- beforeSave?: (next?) => void;
- afterSave?: (next?) => void;
- afterLoad?: (next?) => void;
- afterAutoFetch?: (next?) => void;
- beforeRemove?: (next?) => void;
- afterRemove?: (next?) => void;
- }
-
- export interface IConnectionOptions {
- protocol: string;
- host?: string;
- port?: number;
- auth?: string;
- username?: string;
- password?: string;
- database?: string;
- pool?: boolean;
- debug?: boolean;
- }
-
- export interface IAggregated {
- groupBy(...columns: string[]): IAggregated;
- limit(limit: number): IAggregated;
- limit(offset: number, limit: number): IAggregated;
- order(...order: string[]): IAggregated;
- select(columns: string[]): IAggregated;
- select(...columns: string[]): IAggregated;
- as(alias: string): IAggregated;
- call(fun: string, args: any[]): IAggregated;
- get(callback: (err: Error, instance: Instance) => void);
- }
-
- export interface IChainFind {
- find(conditions: { [property: string]: any }): IChainFind;
- only(...args: string[]): IChainFind;
- limit(limit: number): IChainFind;
- offset(offset: number): IChainFind;
- run(callback: (err: Error, results: Instance[]) => void): void;
- count(callback: (err: Error, count: number) => void): void;
- remove(callback: (err: Error) => void): void;
- save(callback: (err: Error) => void): void;
- each(callback: (result: Instance) => void): void;
- each(): IChainFind;
- filter(callback: (result: Instance) => boolean): IChainFind;
- sort(callback: (a: Instance, b: Instance) => boolean): IChainFind;
- get(callback: (results: Instance[]) => void): IChainFind;
- }
-
- /*
- * Classes
- */
-
- export class ORM extends events.EventEmitter {
- validators: enforce;
- enforce: enforce;
- settings: Settings;
- driver_name: string;
- driver: any;
- tools: any;
- models: { [key: string]: Model };
- plugins: Plugin[];
-
- use(plugin: string, options?: any): ORM;
- use(plugin: Plugin, options?: any): ORM;
-
- define(name: string, properties: { [key: string]: Property }, opts?: ModelOptions): Model;
- ping(callback: (err: Error) => void): ORM;
- close(callback: (err: Error) => void): ORM;
- load(file: string, callback: (err: Error) => void): any;
- sync(callback: (err: Error) => void): ORM;
- drop(callback: (err: Error) => void): ORM;
- }
-
- export class enforce {
- static required(message?: string);
- static notEmptyString(message?: string);
- static rangeNumber(min: number, max: number, message?: string);
- static rangeLength(min: number, max: number, message?: string);
- static insideList(inside: string[], message?: string);
- static insideList(inside: number[], message?: string);
- static outsideList(outside: string[], message?: string);
- static outsideList(outside: number[], message?: string);
- static password(conditions?: string, message?: string);
- static patterns(expr: RegExp, message?: string);
- static patterns(expr: string, flags: string, message?: string);
- static equalToProperty(name: string, message?: string);
- static unique(message?: string);
- static unique(opts: { ignoreCase: boolean }, message?: string);
- }
-
- export function equalToProperty(name: string, message?: string);
- export function unique(message?: string);
- export function unique(opts: { ignoreCase: boolean }, message?: string);
-
- export class singleton {
- static clear(key?: string): singleton;
- static get(key, opts: {
- cache?: any;
- save_check?: boolean;
- }, createCb: Function, returnCb: Function);
- }
-
- export class Settings {
- static Container: any;
-
- static defaults(): {
- properties: {
- primary_key: string;
- association_key: string;
- required: boolean;
- };
-
- instance: {
- cache: boolean;
- cacheSaveCheck: boolean;
- autoSave: boolean;
- autoFetch: boolean;
- autoFetchLimit: number;
- cascadeRemove: boolean;
- returnAllErrors: boolean;
- };
-
- connection: {
- reconnect: boolean;
- poll: boolean;
- debug: boolean;
- };
+///
+///
+
+import http = require('http');
+
+declare module orm {
+ export class ORM extends EventEmitter {
+ validators: enforce;
+ enforce: enforce;
+ settings: Settings;
+ driver_name: string;
+ driver: any;
+ tools: any;
+ models: { [key: string]: Model };
+ plugins: Plugin[];
+
+ use(plugin: string, options?: any): ORM;
+ use(plugin: Plugin, options?: any): ORM;
+
+ define(name: string, properties: { [key: string]: Property }, opts?: ModelOptions): Model;
+ ping(callback: (err: Error) => void): ORM;
+ close(callback: (err: Error) => void): ORM;
+ load(file: string, callback: (err: Error) => void): any;
+ sync(callback: (err: Error) => void): ORM;
+ drop(callback: (err: Error) => void): ORM;
+ }
+
+ export class enforce {
+ static required(message?: string);
+ static notEmptyString(message?: string);
+ static rangeNumber(min: number, max: number, message?: string);
+ static rangeLength(min: number, max: number, message?: string);
+ static insideList(inside: string[], message?: string);
+ static insideList(inside: number[], message?: string);
+ static outsideList(outside: string[], message?: string);
+ static outsideList(outside: number[], message?: string);
+ static password(conditions?: string, message?: string);
+ static patterns(expr: RegExp, message?: string);
+ static patterns(expr: string, flags: string, message?: string);
+ static equalToProperty(name: string, message?: string);
+ static unique(message?: string);
+ static unique(opts: { ignoreCase: boolean }, message?: string);
+ }
+
+ export function equalToProperty(name: string, message?: string);
+ export function unique(message?: string);
+ export function unique(opts: { ignoreCase: boolean }, message?: string);
+
+ export class singleton {
+ static clear(key?: string): singleton;
+ static get(key, opts: {
+ cache?: any;
+ save_check?: boolean;
+ }, createCb: Function, returnCb: Function);
+ }
+
+ export class Settings {
+ static Container: any;
+
+ static defaults(): {
+ properties: {
+ primary_key: string;
+ association_key: string;
+ required: boolean;
+ };
+
+ instance: {
+ cache: boolean;
+ cacheSaveCheck: boolean;
+ autoSave: boolean;
+ autoFetch: boolean;
+ autoFetchLimit: number;
+ cascadeRemove: boolean;
+ returnAllErrors: boolean;
+ };
+
+ connection: {
+ reconnect: boolean;
+ poll: boolean;
+ debug: boolean;
};
+ };
+
+ constructor(settings: any);
+
+ //[key: string]: {
+ // get: (key, def) => any;
+ // set: (key, value) => Settings;
+ // unset: (...keys: string[]) => Settings;
+ //}
+
+ }
+
+ export var settings: Settings;
- constructor(settings: any);
-
- //[key: string]: {
- // get: (key, def) => any;
- // set: (key, value) => Settings;
- // unset: (...keys: string[]) => Settings;
- //}
-
- }
-
- export var settings: Settings;
-
- export class Property {
- static normalize(property: string, settings: Settings): any;
- static validate(value: any, property: string): any;
- }
-
- export interface ErrorCodes {
- QUERY_ERROR: number;
- NOT_FOUND: number;
- NOT_DEFINED: number;
- NO_SUPPORT: number;
- MISSING_CALLBACK: number;
- PARAM_MISMATCH: number;
- CONNECTION_LOST: number;
-
- generateError(code: number, message: string, extra: any): Error;
- }
-
- export function Text(type: string): sqlquery.TextQuery;
- export function eq(value: any): sqlquery.Comparator;
- export function ne(value: any): sqlquery.Comparator;
- export function gt(value: any): sqlquery.Comparator;
- export function gte(value: any): sqlquery.Comparator;
- export function lt(value: any): sqlquery.Comparator;
- export function lte(value: any): sqlquery.Comparator;
- export function like(value: string): sqlquery.Comparator;
- export function between(a: number, b: number): sqlquery.Comparator;
- export function not_between(a: number, b: number): sqlquery.Comparator;
- export function express(uri: string, handlers: {
- define(db: ORM, models: { [key: string]: Model });
- }): (req, res, next) => void;
- export function use(connection, protocol: string, options, callback: (err: Error, db?: ORM) => void);
- export function connect(uri: string): ORM;
- export function connect(uri: string, callback: (err: Error, db: ORM) => void);
- export function connect(options: IConnectionOptions): ORM;
- export function connect(options: IConnectionOptions, callback: (err: Error, db: ORM) => void);
+ export class Property {
+ static normalize(property: string, settings: Settings): any;
+ static validate(value: any, property: string): any;
}
- export = orm;
+ export interface ErrorCodes {
+ QUERY_ERROR: number;
+ NOT_FOUND: number;
+ NOT_DEFINED: number;
+ NO_SUPPORT: number;
+ MISSING_CALLBACK: number;
+ PARAM_MISMATCH: number;
+ CONNECTION_LOST: number;
+
+ generateError(code: number, message: string, extra: any): Error;
+ }
+
+ export function Text(type: string): sqlquery.TextQuery;
+ export function express(uri: string, handlers: {
+ define(db: ORM, models: { [key: string]: Model });
+ }): (req, res, next) => void;
+ export function use(connection, protocol: string, options, callback: (err: Error, db?: ORM) => void);
+ export function connect(uri: string): ORM;
+ export function connect(uri: string, callback: (err: Error, db: ORM) => void);
+ export function connect(options: IConnectionOptions): ORM;
+ export function connect(options: IConnectionOptions, callback: (err: Error, db: ORM) => void);
+
+
+ /**
+ * Parameter Type Interfaces
+ */
+
+ export interface Model {
+ (): Instance;
+ (...ids: any[]): Instance;
+
+ properties: { [property: string]: Property };
+ settings: Settings;
+
+ drop(callback?: (err: Error) => void): Model;
+ sync(callback?: (err: Error) => void): Model;
+ get(...args: any[]): Model;
+ find(conditions: { [property: string]: any }, callback: (err: Error, results: Instance[]) => void): Model;
+ find(conditions: { [property: string]: any }, options: {
+ limit?: number;
+ order?: any;
+ }, callback: (err: Error, results: Instance[]) => void): Model;
+ find(conditions: { [property: string]: any }, limit: number, order: string[], callback: (err: Error, results: Instance[]) => void): Model;
+
+ all(conditions: { [property: string]: any }, callback: (err: Error, results: Instance[]) => void): Model;
+ all(conditions: { [property: string]: any }, options: {
+ limit?: number;
+ order?: any;
+ }, callback: (err: Error, results: Instance[]) => void): Model;
+ all(conditions: { [property: string]: any }, limit: number, order: string[], callback: (err: Error, results: Instance[]) => void): Model;
+
+ one(conditions: { [property: string]: any }, callback: (err: Error, result: Instance) => void): Model;
+ one(conditions: { [property: string]: any }, options: {
+ limit?: number;
+ order?: any;
+ }, callback: (err: Error, result: Instance) => void): Model;
+ one(conditions: { [property: string]: any }, limit: number, order: string[], callback: (err: Error, result: Instance) => void): Model;
+
+ count(callback: (err: Error, count: number) => void): Model;
+ count(conditions: { [property: string]: any }, callback: (err: Error, count: number) => void): Model;
+
+ aggregate(conditions: { [property: string]: any }): IAggregated;
+ aggregate(properties: string[]): IAggregated;
+ aggregate(conditions: { [property: string]: any }, properties: string[]): IAggregated;
+
+ exists(id: any, callback: (err: Error, exists: boolean) => void): Model;
+ exists(...args: any[]): Model;
+
+ create(data: { [property: string]: any; }, callback: (err: Error, instance: Instance) => void): Model;
+ create(...args: any[]): Model;
+
+ clear(): Model;
+
+ table: string;
+ id: string[];
+
+ [property: string]: any;
+ }
+
+ export interface Instance {
+ on(event: string, callback): Instance;
+ save(): Instance;
+ save(data: { [property: string]: any; }, callback: (err: Error) => void): Instance;
+ save(data: { [property: string]: any; }, options: any, callback: (err: Error) => void): Instance;
+ saved: boolean;
+ remove(callback: (err: Error) => void): Instance;
+ isInstance: boolean;
+ isPersisted: boolean;
+ isShell: boolean;
+ validate(callback: (errors: Error[]) => void);
+ model: Model;
+
+ [property: string]: any;
+ }
+
+ export interface ModelOptions {
+ id?: string[];
+ autoFetch?: boolean;
+ autoFetchLimit?: number;
+ cacheFetch?: boolean;
+ hooks?: { [property: string]: Hooks };
+ methods?: { [name: string]: Function };
+ }
+
+ export interface Hooks {
+ beforeValidation?: (next?) => void;
+ beforeCreate?: (next?) => void;
+ afterCreate?: (next?) => void;
+ beforeSave?: (next?) => void;
+ afterSave?: (next?) => void;
+ afterLoad?: (next?) => void;
+ afterAutoFetch?: (next?) => void;
+ beforeRemove?: (next?) => void;
+ afterRemove?: (next?) => void;
+ }
+
+ export interface IConnectionOptions {
+ protocol: string;
+ host?: string;
+ port?: number;
+ auth?: string;
+ username?: string;
+ password?: string;
+ database?: string;
+ pool?: boolean;
+ debug?: boolean;
+ }
+
+ export interface IAggregated {
+ groupBy(...columns: string[]): IAggregated;
+ limit(limit: number): IAggregated;
+ limit(offset: number, limit: number): IAggregated;
+ order(...order: string[]): IAggregated;
+ select(columns: string[]): IAggregated;
+ select(...columns: string[]): IAggregated;
+ as(alias: string): IAggregated;
+ call(fun: string, args: any[]): IAggregated;
+ get(callback: (err: Error, instance: Instance) => void);
+ }
}
\ No newline at end of file
diff --git a/lib/TypeScript/sql-query.d.ts b/lib/TypeScript/sql-query.d.ts
index fe9fa7ad..8f18734a 100644
--- a/lib/TypeScript/sql-query.d.ts
+++ b/lib/TypeScript/sql-query.d.ts
@@ -1,79 +1,76 @@
-declare module "sqlquery" {
- module sqlquery {
- export class Query {
- constructor(dialect: string);
- constructor(options: {
- dialect: string;
- });
- static Text(type: string): TextQuery;
+declare module sqlquery {
+ export class Query {
+ constructor(dialect: string);
+ constructor(options: {
+ dialect: string;
+ });
+ static Text(type: string): TextQuery;
- static Comparators: string[];
- static between(a: number, b: number): Comparator;
- static not_between(a: number, b: number): Comparator;
- static like(expression: string): Comparator;
- static eq(value: any): Comparator;
- static ne(value: any): Comparator;
- static gt(value: any): Comparator;
- static gte(value: any): Comparator;
- static lt(value: any): Comparator;
- static lte(value: any): Comparator;
+ static Comparators: string[];
+ static between(a: number, b: number): Comparator;
+ static not_between(a: number, b: number): Comparator;
+ static like(expression: string): Comparator;
+ static eq(value: any): Comparator;
+ static ne(value: any): Comparator;
+ static gt(value: any): Comparator;
+ static gte(value: any): Comparator;
+ static lt(value: any): Comparator;
+ static lte(value: any): Comparator;
- escapeId(id: string): string;
- escapeId(id: string, table: string): string;
- escapeVal(value: any): string;
- select(): SelectQuery;
- insert(): InsertQuery;
- update(): UpdateQuery;
- remove(): RemoveQuery;
- }
+ escapeId(id: string): string;
+ escapeId(id: string, table: string): string;
+ escapeVal(value: any): string;
+ select(): SelectQuery;
+ insert(): InsertQuery;
+ update(): UpdateQuery;
+ remove(): RemoveQuery;
+ }
- export interface Comparator {
- sql_comparator(): string;
- from?: any;
- to?: any;
- expr?: string;
- value?: any;
- }
+ export interface Comparator {
+ sql_comparator(): string;
+ from?: any;
+ to?: any;
+ expr?: string;
+ value?: any;
+ }
- export interface TextQuery {
- data: any;
- type: string;
- }
+ export interface TextQuery {
+ data: any;
+ type: string;
+ }
- export interface SelectQuery {
- select(fields: string): SelectQuery;
- calculateFoundRows: SelectQuery;
- as(alias: string): SelectQuery;
- fun(fun: string, column: string, alias: string): SelectQuery;
- from(table: string, from_id: string, to_id: string): SelectQuery;
- from(table: string, from_id: string, to_table: string, to_id: string): SelectQuery;
- where(...args: any[]): SelectQuery;
- whereExists(table: string, table_link: string, link: string, conditions: { [column: string]: any }): SelectQuery;
- groupBy(...columns: string[]): SelectQuery;
- offset(offset: number): SelectQuery;
- limit(limit: number): SelectQuery;
- order(column: string, direction: string): SelectQuery;
- build(): string;
- }
+ export interface SelectQuery {
+ select(fields: string): SelectQuery;
+ calculateFoundRows: SelectQuery;
+ as(alias: string): SelectQuery;
+ fun(fun: string, column: string, alias: string): SelectQuery;
+ from(table: string, from_id: string, to_id: string): SelectQuery;
+ from(table: string, from_id: string, to_table: string, to_id: string): SelectQuery;
+ where(...args: any[]): SelectQuery;
+ whereExists(table: string, table_link: string, link: string, conditions: { [column: string]: any }): SelectQuery;
+ groupBy(...columns: string[]): SelectQuery;
+ offset(offset: number): SelectQuery;
+ limit(limit: number): SelectQuery;
+ order(column: string, direction: string): SelectQuery;
+ build(): string;
+ }
- export interface InsertQuery {
- into(table: string): InsertQuery;
- set(values: { [key: string]: any }[]): InsertQuery;
- build(): string;
- }
+ export interface InsertQuery {
+ into(table: string): InsertQuery;
+ set(values: { [key: string]: any }[]): InsertQuery;
+ build(): string;
+ }
- export interface UpdateQuery {
- into(table: string): UpdateQuery;
- set(values: { [column: string]: any }): UpdateQuery;
- where(...conditions: { [column: string]: any }[]): UpdateQuery;
- build(): string;
- }
+ export interface UpdateQuery {
+ into(table: string): UpdateQuery;
+ set(values: { [column: string]: any }): UpdateQuery;
+ where(...conditions: { [column: string]: any }[]): UpdateQuery;
+ build(): string;
+ }
- export interface RemoveQuery {
- from(table: string): RemoveQuery;
- where(...conditions: { [column: string]: any }[]): RemoveQuery;
- build(): string;
- }
+ export interface RemoveQuery {
+ from(table: string): RemoveQuery;
+ where(...conditions: { [column: string]: any }[]): RemoveQuery;
+ build(): string;
}
- export = sqlquery;
}
diff --git a/lib/Validators.js b/lib/Validators.js
index f7d51084..563c3c19 100644
--- a/lib/Validators.js
+++ b/lib/Validators.js
@@ -23,10 +23,8 @@ var validators = {
* checking).
**/
validators.equalToProperty = function (name, msg) {
- return function (v, next) {
- if (v === this[name]) {
- return next();
- }
+ return function (v, next, ctx) {
+ if (v === this[name]) return next();
return next(msg || 'not-equal-to-property');
};
};
@@ -51,24 +49,17 @@ validators.unique = function () {
for (k in arguments) {
arg = arguments[k];
- if (typeof arg === "string") {
- msg = arg;
- } else if (typeof arg === "object") {
- opts = arg;
- }
+ if (typeof arg === 'string') msg = arg;
+ else if (typeof arg === 'object') opts = arg;
}
return function (v, next, ctx) {
- var s, scopeProp;
+ var s, scopeProp;
- if (typeof v === "undefined" || v === null) {
- return next();
- }
+ if (typeof v === 'undefined' || v === null) return next();
- //Cannot process on database engines which don't support SQL syntax
- if (!ctx.driver.isSql) {
- return next('not-supported');
- }
+ //Cannot process on database engines which don't support SQL syntax
+ if (!ctx.driver.isSql) return next('not-supported');
var chain = ctx.model.find();
diff --git a/package.json b/package.json
index 8100d1ad..3486432d 100644
--- a/package.json
+++ b/package.json
@@ -1,56 +1,53 @@
{
- "author" : "Diogo Resende ",
- "name" : "orm",
- "description" : "NodeJS Object-relational mapping",
- "keywords" : [
- "orm",
- "odm",
- "database",
- "mysql",
- "postgres",
- "redshift",
- "sqlite",
- "mongodb"
- ],
- "version" : "2.1.4",
- "license" : "MIT",
- "homepage" : "http://dresende.github.io/node-orm2",
- "repository" : "http://github.com/dresende/node-orm2.git",
- "contributors": [
- { "name" : "Bramus Van Damme", "email" : "bramus@bram.us" },
- { "name" : "Lorien Gamaroff", "email" : "lorien@gamaroff.org" },
- { "name" : "preslavrachev" },
- { "name" : "Chris Cowan", "email" : "me@chriscowan.us" },
- { "name" : "Paul Dixon", "email" : "paul.dixon@mintbridge.co.uk" },
- { "name" : "David Kosub" },
- { "name" : "Arek W", "email" : "arek01@gmail.com" },
- { "name" : "Joseph Gilley", "email" : "joe.gilley@gmail.com" },
- { "name" : "Benjamin Pannell", "email" : "admin@sierrasoftworks.com" }
- ],
- "main" : "./lib/ORM",
- "scripts" : {
- "test" : "make test"
- },
- "engines" : {
- "node" : "*"
- },
- "analyse" : false,
- "dependencies": {
- "enforce" : "0.1.2",
- "sql-query" : "0.1.16",
- "sql-ddl-sync" : "git://github.com/dresende/node-sql-ddl-sync.git#v0.2.0",
- "hat" : "0.0.3",
- "lodash" : "2.4.1"
- },
- "devDependencies": {
- "mysql" : "2.0.0-alpha9",
- "pg" : "2.6.2",
- "sqlite3" : "2.1.7",
- "async" : "*",
- "mocha" : "1.13.0",
- "should" : "1.2.2",
- "mongodb" : "1.3.19",
- "glob" : "3.2.8"
- },
- "optionalDependencies": {}
-}
+ "author" : "Diogo Resende ",
+ "name" : "orm-2.1.3",
+ "description" : "NodeJS Object-relational mapping",
+ "keywords" : [
+ "orm",
+ "odm",
+ "database",
+ "mysql",
+ "postgres",
+ "redshift",
+ "sqlite",
+ "mongodb"
+ ],
+ "version" : "2.1.3",
+ "license" : "MIT",
+ "repository" : "https://ddo@github.com/ddo/node-orm2.git",
+ "contributors": [
+ { "name" : "Bramus Van Damme", "email" : "bramus@bram.us" },
+ { "name" : "Lorien Gamaroff", "email" : "lorien@gamaroff.org" },
+ { "name" : "preslavrachev" },
+ { "name" : "Chris Cowan", "email" : "me@chriscowan.us" },
+ { "name" : "Paul Dixon", "email" : "paul.dixon@mintbridge.co.uk" },
+ { "name" : "David Kosub" },
+ { "name" : "Arek W", "email" : "arek01@gmail.com" },
+ { "name" : "Joseph Gilley", "email" : "joe.gilley@gmail.com" },
+ { "name" : "Benjamin Pannell", "email" : "admin@sierrasoftworks.com" }
+ ],
+ "main" : "./lib/ORM",
+ "scripts" : {
+ "test" : "make test"
+ },
+ "engines" : {
+ "node" : "*"
+ },
+ "analyse" : false,
+ "dependencies": {
+ "enforce" : "0.1.2",
+ "sql-query" : "0.1.15",
+ "hat" : "0.0.3",
+ "lodash" : "2.0.0"
+ },
+ "devDependencies": {
+ "mysql" : "2.0.0-alpha9",
+ "pg" : "2.6.2",
+ "sqlite3" : "2.1.7",
+ "async" : "*",
+ "mocha" : "1.12.1",
+ "should" : "1.2.2",
+ "mongodb" : "1.3.19"
+ },
+ "optionalDependencies": {}
+}
\ No newline at end of file
diff --git a/test/integration/association-hasmany.js b/test/integration/association-hasmany.js
index 737bda21..5dbc076d 100644
--- a/test/integration/association-hasmany.js
+++ b/test/integration/association-hasmany.js
@@ -1,4 +1,3 @@
-var _ = require('lodash');
var should = require('should');
var helper = require('../support/spec_helper');
var ORM = require('../../');
@@ -19,11 +18,11 @@ describe("hasMany", function () {
name : String,
surname : String,
age : Number
- });
+ }, opts);
Pet = db.define('pet', {
name : String
});
- Person.hasMany('pets', Pet, {}, { autoFetch: opts.autoFetchPets });
+ Person.hasMany('pets', Pet);
return helper.dropSync([ Person, Pet ], function () {
/**
@@ -292,59 +291,61 @@ describe("hasMany", function () {
describe("addAccessor", function () {
before(setup());
- if (common.protocol() != "mongodb") {
- it("might add duplicates", function (done) {
- Pet.find({ name: "Mutt" }, function (err, pets) {
- Person.find({ name: "Jane" }, function (err, people) {
+ if (common.protocol() == "mongodb") return;
+
+ it("might add duplicates", function (done) {
+ Pet.find({ name: "Mutt" }, function (err, pets) {
+ Person.find({ name: "Jane" }, function (err, people) {
+ should.equal(err, null);
+
+ people[0].addPets(pets[0], function (err) {
should.equal(err, null);
- people[0].addPets(pets[0], function (err) {
+ people[0].getPets("name", function (err, pets) {
should.equal(err, null);
- people[0].getPets("name", function (err, pets) {
- should.equal(err, null);
-
- should(Array.isArray(pets));
- pets.length.should.equal(2);
- pets[0].name.should.equal("Mutt");
- pets[1].name.should.equal("Mutt");
+ should(Array.isArray(pets));
+ pets.length.should.equal(2);
+ pets[0].name.should.equal("Mutt");
+ pets[1].name.should.equal("Mutt");
- return done();
- });
+ return done();
});
});
});
});
- }
+ });
+ });
+
+ describe("addAccessor", function () {
+ before(setup());
it("should keep associations and add new ones", function (done) {
Pet.find({ name: "Deco" }).first(function (err, Deco) {
Person.find({ name: "Jane" }).first(function (err, Jane) {
should.equal(err, null);
- Jane.getPets(function (err, janesPets) {
- should.not.exist(err);
-
- var petsAtStart = janesPets.length;
+ Jane.addPets(Deco, function (err) {
+ should.equal(err, null);
- Jane.addPets(Deco, function (err) {
+ Jane.getPets("name", function (err, pets) {
should.equal(err, null);
- Jane.getPets("name", function (err, pets) {
- should.equal(err, null);
-
- should(Array.isArray(pets));
- pets.length.should.equal(petsAtStart + 1);
- pets[0].name.should.equal("Deco");
- pets[1].name.should.equal("Mutt");
+ should(Array.isArray(pets));
+ pets.length.should.equal(2);
+ pets[0].name.should.equal("Deco");
+ pets[1].name.should.equal("Mutt");
- return done();
- });
+ return done();
});
});
});
});
});
+ });
+
+ describe("addAccessor", function () {
+ before(setup());
it("should accept several arguments as associations", function (done) {
Pet.find(function (err, pets) {
@@ -366,44 +367,65 @@ describe("hasMany", function () {
});
});
});
+ });
+
+ describe("addAccessor", function () {
+ before(setup());
it("should accept array as list of associations", function (done) {
- Pet.create([{ name: 'Ruff' }, { name: 'Spotty' }],function (err, pets) {
+ Pet.find(function (err, pets) {
Person.find({ name: "Justin" }).first(function (err, Justin) {
should.equal(err, null);
- Justin.getPets(function (err, justinsPets) {
+ Justin.addPets(pets, function (err) {
should.equal(err, null);
- var petCount = justinsPets.length;
-
- Justin.addPets(pets, function (err) {
+ Justin.getPets(function (err, all_pets) {
should.equal(err, null);
- Justin.getPets(function (err, justinsPets) {
- should.equal(err, null);
-
- should(Array.isArray(justinsPets));
- // Mongo doesn't like adding duplicates here, so we add new ones.
- should.equal(justinsPets.length, petCount + 2);
+ should(Array.isArray(all_pets));
+ all_pets.length.should.equal(pets.length);
- return done();
- });
+ return done();
});
});
});
});
});
+ });
- it("should throw if no items passed", function (done) {
- Person.one(function (err, person) {
- should.equal(err, null);
+ describe("setAccessor", function () {
+ before(setup());
- (function () {
- person.addPets(function () {});
- }).should.throw();
+ it("clears current associations", function (done) {
+ Pet.find({ name: "Deco" }, function (err, pets) {
+ var Deco = pets[0];
- return done();
+ Person.find({ name: "Jane" }).first(function (err, Jane) {
+ should.equal(err, null);
+
+ Jane.getPets(function (err, pets) {
+ should.equal(err, null);
+
+ should(Array.isArray(pets));
+ pets.length.should.equal(1);
+ pets[0].name.should.equal("Mutt");
+
+ Jane.setPets(Deco, function (err) {
+ should.equal(err, null);
+
+ Jane.getPets(function (err, pets) {
+ should.equal(err, null);
+
+ should(Array.isArray(pets));
+ pets.length.should.equal(1);
+ pets[0].name.should.equal(Deco.name);
+
+ return done();
+ });
+ });
+ });
+ });
});
});
});
@@ -453,63 +475,22 @@ describe("hasMany", function () {
});
});
- it("should remove all associations if an empty array is passed", function (done) {
- Person.find({ name: "Justin" }).first(function (err, Justin) {
+ it("should throw if no items passed", function (done) {
+ Person.one(function (err, person) {
should.equal(err, null);
- Justin.getPets(function (err, pets) {
- should.equal(err, null);
- should.equal(pets.length, 2);
- Justin.setPets([], function (err) {
- should.equal(err, null);
-
- Justin.getPets(function (err, pets) {
- should.equal(err, null);
- should.equal(pets.length, 0);
-
- return done();
- });
- });
- });
- });
- });
-
- it("clears current associations", function (done) {
- Pet.find({ name: "Deco" }, function (err, pets) {
- var Deco = pets[0];
-
- Person.find({ name: "Jane" }).first(function (err, Jane) {
- should.equal(err, null);
-
- Jane.getPets(function (err, pets) {
- should.equal(err, null);
-
- should(Array.isArray(pets));
- pets.length.should.equal(1);
- pets[0].name.should.equal("Mutt");
-
- Jane.setPets(Deco, function (err) {
- should.equal(err, null);
-
- Jane.getPets(function (err, pets) {
- should.equal(err, null);
-
- should(Array.isArray(pets));
- pets.length.should.equal(1);
- pets[0].name.should.equal(Deco.name);
+ (function () {
+ person.addPets(function () {});
+ }).should.throw();
- return done();
- });
- });
- });
- });
+ return done();
});
});
});
describe("with autoFetch turned on", function () {
before(setup({
- autoFetchPets : true
+ autoFetch : true
}));
it("should fetch associations", function (done) {
@@ -523,23 +504,5 @@ describe("hasMany", function () {
return done();
});
});
-
- it("should save existing", function (done) {
- Person.create({ name: 'Bishan' }, function (err) {
- should.not.exist(err);
-
- Person.one({ name: 'Bishan' }, function (err, person) {
- should.not.exist(err);
-
- person.surname = 'Dominar';
-
- person.save(function (err) {
- should.not.exist(err);
-
- done();
- });
- });
- });
- });
});
});
diff --git a/test/integration/drivers/postgres_spec.js b/test/integration/drivers/postgres_spec.js
deleted file mode 100644
index 337e6c97..00000000
--- a/test/integration/drivers/postgres_spec.js
+++ /dev/null
@@ -1,115 +0,0 @@
-var _ = require('lodash');
-var should = require('should');
-var Driver = require('../../../lib/Drivers/DML/postgres').Driver;
-var helper = require('../../support/spec_helper');
-var common = require('../../common');
-
-if (common.protocol() == "mongodb") return;
-
-describe("Postgres driver", function() {
- describe("#propertyToValue", function () {
- describe("type object", function () {
- function evaluate (input) {
- var driver = new Driver({}, {}, {});
- return driver.propertyToValue(input, { type: 'object' });
- }
-
- it("should not change null", function () {
- should.strictEqual(evaluate(null), null);
- });
-
- it("should not change buffer", function () {
- var b = new Buffer('abc');
- should.strictEqual(evaluate(b), b);
- });
-
- it("should encode everything else as a Buffer", function () {
- var input = { abc: 123 };
- var out = evaluate(input);
-
- should(out instanceof Buffer);
- should.equal(JSON.stringify(input), out.toString());
- });
- });
-
- describe("date", function () {
- function evaluate (input, opts) {
- if (!opts) opts = {};
- var driver = new Driver(opts.config, {}, {});
- return driver.propertyToValue(input, { type: 'date' });
- }
-
- it("should do nothing when timezone isn't configured", function () {
- var input = new Date();
- var inputStr = input.toString();
- var out = evaluate(input);
-
- should.strictEqual(input, out);
- should.equal(inputStr, out.toString());
- });
-
- it("should offset time by specified timezone amount for + timezones");
-
- it("should offset time by specified timezone amount for + timezones");
- });
-
- describe("type point", function () {
- function evaluate (input) {
- var driver = new Driver({}, {}, {});
- return driver.propertyToValue(input, { type: 'point' });
- }
-
- it("should encode correctly", function () {
- var out = evaluate({ x: 5, y: 7 });
-
- should(out instanceof Function);
- should.equal(out(), "POINT(5, 7)");
- });
- });
-
- describe("custom type", function () {
- var customType = {
- propertyToValue: function (input) {
- return input + ' QWERTY';
- }
- };
-
- function evaluate (input, customTypes) {
- var driver = new Driver({}, {}, {});
- if (customType) {
- for (var k in customTypes) {
- driver.customTypes[k] = customTypes[k];
- }
- }
- return driver.propertyToValue(input, { type: 'qwerty' });
- }
-
- it("should do custom type conversion if provided", function () {
- var opts = { qwerty: customType };
- var out = evaluate('f', opts);
-
- should.equal(out, 'f QWERTY');
- });
-
- it("should not do custom type conversion if not provided", function () {
- var opts = { qwerty: {} };
- var out = evaluate('f', opts);
-
- should.equal(out, 'f');
- });
- });
-
- it("should do nothing for other types", function () {
- function evaluate (input, type) {
- var driver = new Driver({}, {}, {});
- return driver.propertyToValue(input, { type: type });
- }
-
- should.strictEqual(evaluate('abc', { type: 'string' }), 'abc');
- should.strictEqual(evaluate(42, { type: 'number' }), 42);
- should.strictEqual(evaluate(undefined, { type: 'bleh' }), undefined);
- });
-
- });
-
-});
diff --git a/test/integration/error_spec.js b/test/integration/error_spec.js
deleted file mode 100644
index eab26890..00000000
--- a/test/integration/error_spec.js
+++ /dev/null
@@ -1,56 +0,0 @@
-var should = require('should');
-var ORMError = require('../../lib/Error');
-
-describe("Error", function () {
- describe("constructor", function () {
- it("should inherit from native Error", function () {
- var e = new ORMError("Test message", 'PARAM_MISMATCH');
- should(e instanceof Error);
- });
-
- it("should have a valid stack", function () {
- var e = new ORMError("Test message", 'PARAM_MISMATCH');
- var stackArr = e.stack.split('\n');
- // [0] is ''
- should(stackArr[1].indexOf('test/integration/error_spec.js') > 0);
- });
-
- it("should have the right name", function () {
- var e = new ORMError("Test message", 'PARAM_MISMATCH');
- should.equal(e.name, 'ORMError');
- });
-
- it("should throw on invalid code", function () {
- (function () {
- var e = new ORMError("Test message", 'FLYING_SQUIRRELS');
- }).should.throw("Invalid error code: FLYING_SQUIRRELS");
- });
-
- it("should assign the code", function () {
- var e = new ORMError("Test message", 'PARAM_MISMATCH');
- should.equal(e.code, 6);
- });
-
- it("should assign literal code", function () {
- var e = new ORMError("Test message", 'PARAM_MISMATCH');
- should.equal(e.literalCode, 'PARAM_MISMATCH');
- });
-
- it("should assign extra params", function () {
- var e = new ORMError("Test message", 'PARAM_MISMATCH', { details: "something" });
- should.equal(e.details, "something");
- });
-
- it("should stringify nicely", function () {
- var e = new ORMError("Test message", 'PARAM_MISMATCH');
- should.equal(e.toString(), "[ORMError PARAM_MISMATCH: Test message]");
- });
- });
-
- describe("codes", function () {
- it("should be exposed", function () {
- should.exist(ORMError.codes);
- should.equal(ORMError.codes['NOT_FOUND'], 2);
- });
- });
-});
diff --git a/test/integration/event.js b/test/integration/event.js
index f14c4830..8ade7b5f 100644
--- a/test/integration/event.js
+++ b/test/integration/event.js
@@ -79,19 +79,5 @@ describe("Event", function() {
return done();
});
});
-
- it("should be writable for mocking", function (done) {
- var triggered = false;
- var John = new Person();
-
- John.on = function(event, cb) {
- triggered = true;
- };
- triggered.should.be.false;
-
- John.on("mocked", function (err) {} );
- triggered.should.be.true;
- done();
- });
});
});
diff --git a/test/integration/hook.js b/test/integration/hook.js
index 2db7299b..a1e1bc68 100644
--- a/test/integration/hook.js
+++ b/test/integration/hook.js
@@ -354,7 +354,7 @@ describe("Hook", function() {
});
describe("afterSave", function () {
- beforeEach(setup());
+ before(setup());
it("should trigger after saving an instance", function (done) {
Person.create([{ name: "John Doe" }], function () {
@@ -365,19 +365,6 @@ describe("Hook", function() {
return done();
});
});
-
- it("should not trigger after saving an unchanged instance", function (done) {
- Person.create({ name: "Edger" }, function (err, edger) {
- should.not.exist(err);
-
- triggeredHooks = {};
- edger.save(function (err) {
- should.not.exist(err);
- should.not.exist(triggeredHooks.afterSave);
- done();
- });
- });
- });
});
describe("beforeValidation", function () {
diff --git a/test/integration/instance.js b/test/integration/instance.js
index 5312ea41..87374d72 100644
--- a/test/integration/instance.js
+++ b/test/integration/instance.js
@@ -130,16 +130,6 @@ describe("Model instance", function() {
it("should return false for new instances", function () {
should.equal((new Person).isPersisted(), false);
});
-
- it("should be writable for mocking", function() {
- var person = new Person()
- var triggered = false;
- person.isPersisted = function() {
- triggered = true;
- };
- person.isPersisted()
- triggered.should.be.true;
- });
});
describe("#isShell", function () {
diff --git a/test/integration/model-find-chain.js b/test/integration/model-find-chain.js
index 1bc44b09..83638c5e 100644
--- a/test/integration/model-find-chain.js
+++ b/test/integration/model-find-chain.js
@@ -6,7 +6,6 @@ var common = require('../common');
describe("Model.find() chaining", function() {
var db = null;
var Person = null;
- var Dog = null;
var setup = function () {
return function (done) {
@@ -37,30 +36,6 @@ describe("Model.find() chaining", function() {
};
};
- var setup2 = function () {
- return function (done) {
- Dog = db.define("dog", {
- name: String,
- });
- Dog.hasMany("friends");
- Dog.hasMany("family");
-
- ORM.singleton.clear(); // clear cache
-
- return helper.dropSync(Dog, function () {
- Dog.create([{
- name : "Fido",
- friends : [{ name: "Gunner" }, { name: "Chainsaw" }],
- family : [{ name: "Chester" }]
- }, {
- name : "Thumper",
- friends : [{ name: "Bambi" }],
- family : [{ name: "Princess" }, { name: "Butch" }]
- }], done);
- });
- };
- };
-
before(function (done) {
helper.connect(function (connection) {
db = connection;
@@ -504,76 +479,6 @@ describe("Model.find() chaining", function() {
});
});
- describe(".eager()", function () {
- before(setup2());
-
- // TODO: Remove this code once the Mongo eager loading is implemented
- var isMongo = function () {
- if (db.driver.config.protocol == "mongodb:") {
- (function () {
- Dog.find().eager("friends").all(function () {
- // Should not ever run.
- });
- }).should.throw();
-
- return true;
- }
- return false;
- };
-
- it("should fetch all listed associations in a single query", function (done) {
- if (isMongo()) { return done(); };
-
- Dog.find({ name: ["Fido", "Thumper"] }).eager("friends").all(function (err, dogs) {
- should.equal(err, null);
-
- should(Array.isArray(dogs));
-
- dogs.length.should.equal(2);
-
- dogs[0].friends.length.should.equal(2);
- dogs[1].friends.length.should.equal(1);
- done();
- });
- });
-
- it("should be able to handle multiple associations", function (done) {
- if (isMongo()) { return done(); };
-
- Dog.find({ name: ["Fido", "Thumper"] }).eager("friends", "family").all(function (err, dogs) {
- should.equal(err, null);
-
- should(Array.isArray(dogs));
-
- dogs.length.should.equal(2);
-
- dogs[0].friends.length.should.equal(2);
- dogs[0].family.length.should.equal(1);
- dogs[1].friends.length.should.equal(1);
- dogs[1].family.length.should.equal(2);
- done();
- });
- });
-
- it("should work with array parameters too", function (done) {
- if (isMongo()) { return done(); };
-
- Dog.find({ name: ["Fido", "Thumper"] }).eager(["friends", "family"]).all(function (err, dogs) {
- should.equal(err, null);
-
- should(Array.isArray(dogs));
-
- dogs.length.should.equal(2);
-
- dogs[0].friends.length.should.equal(2);
- dogs[0].family.length.should.equal(1);
- dogs[1].friends.length.should.equal(1);
- dogs[1].family.length.should.equal(2);
- done();
- });
- });
- });
-
describe(".success()", function () {
before(setup());
diff --git a/test/integration/model-remove.js b/test/integration/model-remove.js
deleted file mode 100644
index 6b65b476..00000000
--- a/test/integration/model-remove.js
+++ /dev/null
@@ -1,60 +0,0 @@
-var should = require('should');
-var helper = require('../support/spec_helper');
-var ORM = require('../../');
-
-describe("Model.remove()", function() {
- var db = null;
- var Person = null;
-
- var setup = function () {
- return function (done) {
- Person = db.define("person", {
- name : String
- });
-
- return helper.dropSync(Person, function () {
- Person.create([{
- id : 1,
- name: "Jeremy Doe"
- }, {
- id : 2,
- name: "John Doe"
- }, {
- id : 3,
- name: "Jane Doe"
- }], done);
- });
- };
- };
-
- before(function (done) {
- helper.connect(function (connection) {
- db = connection;
-
- return done();
- });
- });
-
- after(function () {
- return db.close();
- });
-
- describe("mockable", function() {
- before(setup());
-
- it("remove should be writable", function(done) {
- var John = new Person({
- name: "John"
- });
- var removeCalled = false;
- John.remove = function(cb) {
- removeCalled = true;
- cb(null);
- };
- John.remove(function(err) {
- should.equal(removeCalled,true);
- return done();
- });
- });
- });
-});
diff --git a/test/integration/model-save.js b/test/integration/model-save.js
index 750eb058..2d17abcd 100644
--- a/test/integration/model-save.js
+++ b/test/integration/model-save.js
@@ -8,14 +8,12 @@ describe("Model.save()", function() {
var Person = null;
var setup = function (nameDefinition, opts) {
- opts = opts || {};
-
return function (done) {
Person = db.define("person", {
name : nameDefinition || String
}, opts || {});
- Person.hasOne("parent", Person, opts.hasOneOpts);
+ Person.hasOne("parent");
return helper.dropSync(Person, done);
};
@@ -200,119 +198,6 @@ describe("Model.save()", function() {
});
});
- describe("with saveAssociations", function () {
- var afterSaveCalled = false;
-
- if (common.protocol() == 'mongodb') return;
-
- beforeEach(function (done) {
- function afterSave () {
- afterSaveCalled = true;
- }
- var hooks = { afterSave: afterSave };
-
- setup(null, { hooks: hooks, cache: false, hasOneOpts: { autoFetch: true } })(function (err) {
- should.not.exist(err);
-
- Person.create({ name: 'Olga' }, function (err, olga) {
- should.not.exist(err);
-
- should.exist(olga);
- Person.create({ name: 'Hagar', parent_id: olga.id }, function (err, hagar) {
- should.not.exist(err);
- should.exist(hagar);
- afterSaveCalled = false;
- done();
- });
- });
- });
- });
-
- it("off should not save associations but save itself", function (done) {
- Person.one({ name: 'Hagar' }, function (err, hagar) {
- should.not.exist(err);
- should.exist(hagar.parent);
-
- hagar.parent.name = 'Olga2';
- hagar.save({name: 'Hagar2'}, { saveAssociations: false }, function (err) {
- should.not.exist(err);
- should.equal(afterSaveCalled, true);
-
- Person.get(hagar.parent.id, function (err, olga) {
- should.not.exist(err);
- should.equal(olga.name, 'Olga');
- done();
- });
- });
- });
- });
-
- it("off should not save associations or itself if there are no changes", function (done) {
- Person.one({ name: 'Hagar' }, function (err, hagar) {
- should.not.exist(err);
-
- hagar.save({}, { saveAssociations: false }, function (err) {
- should.not.exist(err);
- should.equal(afterSaveCalled, false);
-
- Person.get(hagar.parent.id, function (err, olga) {
- should.not.exist(err);
- should.equal(olga.name, 'Olga');
- done();
- });
- });
- });
- });
-
- it("unspecified should save associations and itself", function (done) {
- Person.one({ name: 'Hagar' }, function (err, hagar) {
- should.not.exist(err);
- should.exist(hagar.parent);
-
- hagar.parent.name = 'Olga2';
- hagar.save({name: 'Hagar2'}, function (err) {
- should.not.exist(err);
-
- Person.get(hagar.parent.id, function (err, olga) {
- should.not.exist(err);
- should.equal(olga.name, 'Olga2');
-
- Person.get(hagar.id, function (err, person) {
- should.not.exist(err);
- should.equal(person.name, 'Hagar2');
-
- done();
- });
- });
- });
- });
- });
-
- it("on should save associations and itself", function (done) {
- Person.one({ name: 'Hagar' }, function (err, hagar) {
- should.not.exist(err);
- should.exist(hagar.parent);
-
- hagar.parent.name = 'Olga2';
- hagar.save({name: 'Hagar2'}, { saveAssociations: true }, function (err) {
- should.not.exist(err);
-
- Person.get(hagar.parent.id, function (err, olga) {
- should.not.exist(err);
- should.equal(olga.name, 'Olga2');
-
- Person.get(hagar.id, function (err, person) {
- should.not.exist(err);
- should.equal(person.name, 'Hagar2');
-
- done();
- });
- });
- });
- });
- });
- });
-
describe("with a point property", function () {
if (common.protocol() == 'sqlite' || common.protocol() == 'mongodb') return;
@@ -332,38 +217,4 @@ describe("Model.save()", function() {
});
});
});
-
- describe("mockable", function() {
- before(setup());
-
- it("save should be writable", function(done) {
- var John = new Person({
- name: "John"
- });
- var saveCalled = false;
- John.save = function(cb) {
- saveCalled = true;
- cb(null);
- };
- John.save(function(err) {
- should.equal(saveCalled,true);
- return done();
- });
- });
-
- it("saved should be writable", function(done) {
- var John = new Person({
- name: "John"
- });
- var savedCalled = false;
- John.saved = function() {
- savedCalled = true;
- return true;
- };
-
- John.saved()
- savedCalled.should.be.true;
- done();
- })
- });
});
diff --git a/test/integration/orm-exports.js b/test/integration/orm-exports.js
index ab445a94..d6175b5a 100644
--- a/test/integration/orm-exports.js
+++ b/test/integration/orm-exports.js
@@ -115,11 +115,7 @@ describe("ORM.connect()", function () {
var db = ORM.connect("unknown://db");
db.on("connect", function (err) {
- should.equal(err.literalCode, 'NO_SUPPORT');
- should.equal(
- err.message,
- "Connection protocol not supported - have you installed the database driver for unknown?"
- );
+ err.message.should.equal("CONNECTION_PROTOCOL_NOT_SUPPORTED");
return done();
});
@@ -130,7 +126,7 @@ describe("ORM.connect()", function () {
db.on("connect", function (err) {
should.exist(err);
- should.equal(err.message.indexOf("Connection protocol not supported"), -1);
+ err.message.should.not.equal("CONNECTION_PROTOCOL_NOT_SUPPORTED");
err.message.should.not.equal("CONNECTION_URL_NO_PROTOCOL");
err.message.should.not.equal("CONNECTION_URL_EMPTY");
@@ -189,24 +185,11 @@ describe("ORM.connect()", function () {
it("should return an error if unknown protocol is passed", function (done) {
ORM.connect("unknown://db", function (err) {
- should.equal(err.literalCode, 'NO_SUPPORT');
- should.equal(
- err.message,
- "Connection protocol not supported - have you installed the database driver for unknown?"
- );
+ err.message.should.equal("CONNECTION_PROTOCOL_NOT_SUPPORTED");
return done();
});
});
-
- it("should allow pool and debug settings to be false", function(done) {
- var connString = common.getConnectionString() + "debug=false&pool=false";
- ORM.connect(connString, function(err, db) {
- db.driver.opts.pool.should.equal(false);
- db.driver.opts.debug.should.equal(false);
- done();
- });
- });
});
});
diff --git a/test/integration/validation.js b/test/integration/validation.js
index 8482f0f7..30de4ef2 100644
--- a/test/integration/validation.js
+++ b/test/integration/validation.js
@@ -344,23 +344,4 @@ describe("Validations", function() {
});
});
});
-
- describe("mockable", function() {
- before(setup());
-
- it("validate should be writable", function(done) {
- var John = new Person({
- name: "John"
- });
- var validateCalled = false;
- John.validate = function(cb) {
- validateCalled = true;
- cb(null);
- };
- John.validate(function(err) {
- should.equal(validateCalled,true);
- return done();
- });
- });
- });
});
diff --git a/test/run.js b/test/run.js
index 057880ae..da307f0d 100644
--- a/test/run.js
+++ b/test/run.js
@@ -1,9 +1,9 @@
var Mocha = require("mocha");
-var glob = require("glob");
+var fs = require("fs");
var path = require("path");
var common = require("./common");
var logging = require("./logging");
-var location = path.normalize(path.join(__dirname, "integration", "**", "*.js"));
+var location = path.normalize(path.join(__dirname, "integration"));
var mocha = new Mocha({
reporter: "progress"
});
@@ -20,9 +20,14 @@ switch (common.hasConfig(common.protocol())) {
runTests();
function runTests() {
- glob.sync(location).forEach(function (file) {
+ fs.readdirSync(location).filter(function (file) {
+ return file.substr(-3) === '.js';
+ }).forEach(function (file) {
if (!shouldRunTest(file)) return;
- mocha.addFile(file);
+
+ mocha.addFile(
+ path.join(location, file)
+ );
});
logging.info("Testing **%s**", common.getConnectionString());
@@ -33,11 +38,11 @@ function runTests() {
}
function shouldRunTest(file) {
- var name = path.basename(file).slice(0, -3)
+ var name = file.substr(0, file.length - 3);
var proto = common.protocol();
- var exclude = ['model-aggregate','property-number-size','smart-types'];
- if (proto == "mongodb" && exclude.indexOf(name) >= 0) return false;
+ if (proto == "mongodb" && [ "model-aggregate",
+ "property-number-size", "smart-types" ].indexOf(name) >= 0) return false;
return true;
}
Comments
'; - - for (var a = 0; a < comments.length; a++) { - html += renderComment(comments[a]); - } - html += '