## Contents
- [Getting started](#getting)
- [Installation](#install)
- [Configuration](#config)
- [Models](#models)
- [Defining Models](#m-definition)
- [Validating Properties](#m-validate)
- [Instantiating Models](#m-instance)
- [Finding Models](#m-find)
- [Getters/Setters](#m-getset)
- [JSON](#m-json)
- [Relationships](#m-rel)
- [One to one](#m-onetoone)
- [One to many](#m-onetomany)
- [Many to Many](#m-manytomany)
- [Load](#m-load)
## Getting started
#### Installation
```
$ npm install hater
```
#### Configuration
First of all, you need to choose which SQL dialect to use and to connect to the database, this is as simple as this:
```javascript
var hater = require('hater');
hater.connect('postgresql', 'tcp://user:password@host/databaseName');
```
## Models
#### Defining Models
To define a model you only need to invoke the ```.define()``` method from ```hater```
```javascript
var myModel = hater.define('mymodel');
```
To extend a Model's base prototype you can pass a second argument
```javascript
var myModel = hater.define('mymodel', {
fullName: function() {
return this.get('name') + this.get('surname');
};
});
```
To specify the Model's schema just pass a configuration object to ```.schema()```
```javascript
myModel.schema({
name : hater.Types.String(),
surname: hater.Types.String({length: 32})
});
```
Tables are created auto-magically \ò/.
#### Validating Properties
```hater``` uses ```revalidator``` to validate properties, [check it out](https://github.com/flatiron/revalidator) to see how it works
```javascript
var Model = hater.define('model');
Model.schema({
test: hater.Types.String({ validate: { minLength: 5 } });
})
```
#### Instantiating Models
To create a model simply use use ```new``` or call ```.create()```
```javascript
// these three methods are equivalent
var instance = new myModel({
name : 'john',
surname: 'doe'
});
instance.save(function(e) {
// do something
});
myModel.create({
name : 'john',
surname: 'doe'
}, function(e, instance) {
// do something
});
var instance2 = new myModel();
instance2.set('name', 'john');
instance2.set('surname', 'doe');
instance2.save(function(e) {
// do something
});
```
#### Find
Hater provides ```find()``` and ```findOne``` to find documents in the database.
```javascript
Model.find({ where: { id: 1 }, limit: { model: [0,10] } }, function(e. models) {
// models in an array
});
Model.findOne({ where: { id: 1 } }, function(e, model) {
// here model is an instance
});
```
The first object can have:
- where (example: ```{ where: { id: 1, name: 'test' } }```)
- limit (example: ```{ limit: { name: 10 } }``` or ```{ limit: { name: [10, 20] } }```
- fetch (example: ```{ fetch: ["children"] }```, check Relationships to see how to use it)
Find is recursive, so you can also query for children's properties (see also Relationships below):
```javascript
Model.find({ where: { children: { name: 'test' } } }, function(e, res) {
// finds all models that have a children with name 'test'
});
```
#### Getters / Setters
Getters and Setters are slower than regular functions in JS, therefore we decided to implement a ```get()``` and ```set()``` function
```javascript
instance.get('property');
instance.set('property', 'newValue');
```
#### JSON
JSON.stringify returns the instance's properties with their respective values
```javascript
JSON.stringify(instance);
// {"key": "value", "key2": "value2" ... }
```
## Relationships
Hater supports:
- One To One
- One To Many
- Many To Many
#### One to One
To link one model to another:
```
instance.set('modelName', modelInstance);
```
Example of a one to one relationship:
```javascript
var Model = hater.define('model');
Model.schema({ ... });
var Other = hater.define('other');
Other.schema({ ... });
hater.Relationships.oneToOne(Model, Other);
var m = new Model();
m.set('other', new Other());
m.save();
Other.findOne({
where: { id: m.get('other').get('id') },
fetch: ["model"]
}, function(e, res) {
other.get('model') // is m
});
```
```fetch: ["model"]``` is a special clause that tells ```hater``` to pre-load datas that are related to the one we are querying
#### One to Many
To set an instance's children
```
instance.set('pluralOfChildName', [childInstance, childInstance]);
```
Example of a one to many relationship:
```javascript
// Model and Other from previous example
hater.Relationships.oneToMany(Model, Other);
var m = new Model();
m.set('others', [new Other(), new Other()]);
m.save(function() {
Model.findOne({ where: { id: m.get('id') }, fetch: ["others"] }, function(e, res) {
res.get('others') // is the array we set in m
});
});
```
We can also filter the children via the where clause
```javascript
Model.findOne({ where: { id: m.get('id'), others: { name: 'test' }, fetch: ["others"] }, function(e, res) {
res.get('others') // every others.name will be 'lol'
});
```
#### Many To Many
To set relationships between instances
```
instance.set('pluralOfOtherModelName', [instanceOther, instanceOther]);
```
Example of a many to many relationship:
```javascript
// Model and Other from previous example
hater.Relationships.manyToMany(Model, Other);
var m = new Model();
m.set('others', [new Other(), new Other()]);
m.save(function(e) {
Other.find({ fetch: ["models"] }, function(e, res) {
var o = res.shift();
o.get('models')[0] // is the m we saved
});
});
```
### Load
If you want to lazy load relationships (eg in the many to many case) you can use ```.load()```
```javascript
One.findOne({ where: { id: 1 } }, function(e, instance) {
instance.load(["others"], function(e) {
instange.get("others") // relationship
});
});
```