<commit_before>[![Build Status](https://travis-ci.org/sgarza/krypton.svg?branch=master)](https://travis-ci.org/sgarza/krypton)
[![Code Climate](https://codeclimate.com/github/sgarza/krypton/badges/gpa.svg)](https://codeclimate.com/github/sgarza/krypton)
[![Test Coverage](https://codeclimate.com/github/sgarza/krypton/badges/coverage.svg)](https://codeclimate.com/github/sgarza/krypton/coverage)
[![NPM](https://nodei.co/npm/krypton-orm.png?downloads=true&downloadRank=true&stars=true)](https://www.npmjs.com/package/krypton-orm)


W.I.P.
-----

**Krypton** is a full featured Javascript ORM for SQL Databases

Krypton Features:

- Declarative way of defining models
- Mechanism to eager load relations __*__
- Use the full feature-set of Knex.js __*__
- Easy to use transactions __*__
- Easy to declare validations
- Promise based

__*__ _Work in progress_

### Constraints

- Build arround [Neon](https://github.com/azendal/neon/)
- Use [Knex](http://knex.org) as the query builder
- DB **column_names** must be **snake_case**
- Don't handle migrations
- Don't handle database schema creation


### TODO

- This README
- Add more relation types, currently there are HasOne, HasMany and HasManyThrough.
- Add transactions

### Examples

```javascript
var Knex = require('knex');

// Create a knex instance
var knex = Knex({
  client: 'postgres',
  connection: {
    database: 'database-name',
    user:     'DBUser',
    password: '<PASSWORD>'
  }
});

// Log queries
knex.on('query', function(data) {
  console.log(data);
});

// Bind the knex instance to the Krypton Base Model Class
// (Yes you can have multiple knex instances binded to different Models :) )
Krypton.Model.knex(knex);

// Create some Models
Class('Voice').inherits(Krypton.Model)({
  tableName : 'Voices',

  /*
    attributes are used for validation (whitelist) at saving. Whenever a
    model instance is saved it is checked against this schema.
  */
  attributes : ['id', 'title', 'description', 'createdAt', 'updatedAt']
});

Class('Entity').inherits(Krypton.Model)({
  tableName : 'Entities',

  attributes : ['id', ..., 'createdAt', 'updatedAt']
})

// This object defines the relations to other models.
// I intentionaly declared this outside the Entity Class because it has a circular
// relation ('organizations')
Entity.relations = {
  voices : {
    type : 'HasMany',
    relatedModel : Voice,
    ownerCol : 'id',
    relatedCol : 'owner_id'
  },

  organizations : {
    type : 'HasManyThrough',
    relatedModel : Entity,
    ownerCol : 'id',
    relatedCol : 'id',
    scope : ['Entities.type', '=', 'organization'],
    through : {
        tableName : 'EntityOwner',
        ownerCol : 'owner_id',
        relatedCol : 'owned_id'
        scope : null
    }
  }
}

Class('User').inherits(Krypton.Model)({
  tableName : 'Users',

  attributes : ['id', ..., 'createdAt', 'updatedAt'],

  relations : {
    entity : {
      type : 'HasOne',
      relatedModel : Entity,
      ownerCol : 'entity_id',
      relatedCol : 'id'
    }
  }
});
```

Queries

```javascript
var userQuery = User.query();
// => returns a QueryBuilder instance

userQuery.where({id : 1});
// or userQuery.where('id', '<', 5) or whatever knex expression you want to use.


// include(relationExpression)
// Relation expression is a simple DSL for expressing relation trees.
userQuery.include('entity.[voices, organizations]');
// This means: Load the User(s) and its entity and the voices of its entity and the organizations of its entity

userQuery.then(function(result) {
  console.log(result)
});

```

#### ActiveRecord Style callbacks

Callbacks are hooks into the life cycle of an Krypton Model instance that allow you to trigger logic before or after an alteration of the object state.

 - Implemented callbacks:
    - beforeValidation
    - afterValidation
    - beforeSave
    - beforeCreate
    - beforeUpdate
    - afterCreate
    - afterUpdate
    - afterSave

API:
```javascript
// @property on <public> [Function]
// @method
// @argument hook <required> [String]
// @argument handler(callback) <required> [Function]
// @return this;
```

Examples:

```javascript
Model('User').inherits(Krypton.Model)({
    prototype : {
        init : function(config) {
            Krypton.Model.prototype.init.call(this, config);

            var model = this;

            model.on('beforeValidation', function(next) {
                bcrypt.hash(model.password, null, null, function(err, hash) {
                    model.encryptedPassword = <PASSWORD>;
                    delete model.password;
                    next();
                });
            });

            model.on('beforeValidation', function(next) {
                model.count++
            });<commit_msg>Add {before,after}Destroy hooks to README<commit_after>[![Build Status](https://travis-ci.org/sgarza/krypton.svg?branch=master)](https://travis-ci.org/sgarza/krypton)
[![Code Climate](https://codeclimate.com/github/sgarza/krypton/badges/gpa.svg)](https://codeclimate.com/github/sgarza/krypton)
[![Test Coverage](https://codeclimate.com/github/sgarza/krypton/badges/coverage.svg)](https://codeclimate.com/github/sgarza/krypton/coverage)
[![NPM](https://nodei.co/npm/krypton-orm.png?downloads=true&downloadRank=true&stars=true)](https://www.npmjs.com/package/krypton-orm)


W.I.P.
-----

**Krypton** is a full featured Javascript ORM for SQL Databases

Krypton Features:

- Declarative way of defining models
- Mechanism to eager load relations __*__
- Use the full feature-set of Knex.js __*__
- Easy to use transactions __*__
- Easy to declare validations
- Promise based

__*__ _Work in progress_

### Constraints

- Build arround [Neon](https://github.com/azendal/neon/)
- Use [Knex](http://knex.org) as the query builder
- DB **column_names** must be **snake_case**
- Don't handle migrations
- Don't handle database schema creation


### TODO

- This README
- Add more relation types, currently there are HasOne, HasMany and HasManyThrough.
- Add transactions

### Examples

```javascript
var Knex = require('knex');

// Create a knex instance
var knex = Knex({
  client: 'postgres',
  connection: {
    database: 'database-name',
    user:     'DBUser',
    password: '<PASSWORD>'
  }
});

// Log queries
knex.on('query', function(data) {
  console.log(data);
});

// Bind the knex instance to the Krypton Base Model Class
// (Yes you can have multiple knex instances binded to different Models :) )
Krypton.Model.knex(knex);

// Create some Models
Class('Voice').inherits(Krypton.Model)({
  tableName : 'Voices',

  /*
    attributes are used for validation (whitelist) at saving. Whenever a
    model instance is saved it is checked against this schema.
  */
  attributes : ['id', 'title', 'description', 'createdAt', 'updatedAt']
});

Class('Entity').inherits(Krypton.Model)({
  tableName : 'Entities',

  attributes : ['id', ..., 'createdAt', 'updatedAt']
})

// This object defines the relations to other models.
// I intentionaly declared this outside the Entity Class because it has a circular
// relation ('organizations')
Entity.relations = {
  voices : {
    type : 'HasMany',
    relatedModel : Voice,
    ownerCol : 'id',
    relatedCol : 'owner_id'
  },

  organizations : {
    type : 'HasManyThrough',
    relatedModel : Entity,
    ownerCol : 'id',
    relatedCol : 'id',
    scope : ['Entities.type', '=', 'organization'],
    through : {
        tableName : 'EntityOwner',
        ownerCol : 'owner_id',
        relatedCol : 'owned_id'
        scope : null
    }
  }
}

Class('User').inherits(Krypton.Model)({
  tableName : 'Users',

  attributes : ['id', ..., 'createdAt', 'updatedAt'],

  relations : {
    entity : {
      type : 'HasOne',
      relatedModel : Entity,
      ownerCol : 'entity_id',
      relatedCol : 'id'
    }
  }
});
```

Queries

```javascript
var userQuery = User.query();
// => returns a QueryBuilder instance

userQuery.where({id : 1});
// or userQuery.where('id', '<', 5) or whatever knex expression you want to use.


// include(relationExpression)
// Relation expression is a simple DSL for expressing relation trees.
userQuery.include('entity.[voices, organizations]');
// This means: Load the User(s) and its entity and the voices of its entity and the organizations of its entity

userQuery.then(function(result) {
  console.log(result)
});

```

#### ActiveRecord Style callbacks

Callbacks are hooks into the life cycle of an Krypton Model instance that allow you to trigger logic before or after an alteration of the object state.

 - Implemented callbacks:
    - beforeValidation
    - afterValidation
    - beforeSave
    - beforeCreate
    - beforeUpdate
    - afterCreate
    - afterUpdate
    - afterSave
    - beforeDestroy
    - afterDestroy

API:
```javascript
// @property on <public> [Function]
// @method
// @argument hook <required> [String]
// @argument handler(callback) <required> [Function]
// @return this;
```

Examples:

```javascript
Model('User').inherits(Krypton.Model)({
    prototype : {
        init : function(config) {
            Krypton.Model.prototype.init.call(this, config);

            var model = this;

            model.on('beforeValidation', function(next) {
                bcrypt.hash(model.password, null, null, function(err, hash) {
                    model.encryptedPassword = <PASSWORD>;
                    delete model.password;
                    next();
                });
            });

            model.on('beforeValidation', function(next) {
                model.count++
            });
{'fraction_non_alphanumeric': 0.13914228793121527, 'fraction_numerical': 0.0004194191045402118, 'mean_word_length': 3.170529077393966, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 18, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '33211', 'n_tokens_mistral': 2971, 'n_tokens_neox': 2874, 'n_words': 778}