var sql = require('psqljs'),
    q = require('q'),
    pg = require('pg');

function Model(table, connectionString, primaryKey) {
  this.table = table;
  this.connectionString = connectionString;
  this.attributes = {};
  this.primaryKey = primaryKey || 'id';
  this.query = null;
}

Model.createModel = function(table, connectionString, primaryKey) {
  var self = new Model(table, connectionString, primaryKey);

  // user's model definition
  var definition = function(attributes) {
    if(attributes === null || typeof(attributes) !== 'object') {
      throw new Error('Cannot build a record for table ' + self.table + ' without an object');
    }

    self.attributes = attributes;
    var keys = Object.keys(attributes);
    keys.map(function(k) { self[k] = attributes[k]; });

    return self;
  };

  // Hack to call Model.prototype methods after definition is instantiated
  definition.__proto__ = self;

  definition.define = function(key, fn) {
    var proto = Object.getPrototypeOf(this);
    proto[key] = fn;
  };

  return definition;
};

Model.prototype.run = function() {
  var deferred = q.defer();
  var query = this.query;
  this.query = null;
  pg.connect(this.connectionString, function(err, client, done) {
    if(err) {
      deferred.reject(new Error(err));
    }

    client.query(query.toQuery(), function(err, result) {
      done();

      if(err) {
        deferred.reject(new Error(err));
      }
      else {
        deferred.resolve(result.rows);
      }
    });
  });

  return deferred.promise;
};

Model.prototype.where = function(str) {
  this.query = sql.select().from(this.table).where.apply(sql, arguments);

  return this;
};

Model.prototype.get = function(id) {
  this.query = sql.select().from(this.table).where(this.primaryKey + ' = ?', id);

  var deferred = q.defer();
  this.run().then(function(rows) {
    deferred.resolve(rows[0]);
  }, deferred.reject);

  return deferred.promise;
};

Model.prototype.save = function() {
  var query = sql.insert(this.table, this.attributes).returning().toQuery();

  var deferred = q.defer();
  pg.connect(this.connectionString, function(err, client, done) {
    if(err) {
      deferred.reject(new Error(err));
    }

    client.query(query, function(err, result) {
      done();

      if(err) {
        deferred.reject(new Error(err));
      } else {
        deferred.resolve(result.rows[0]);
      }
    });
  });

  return deferred.promise;
};

module.exports = Model;

@@ -126,24 +126,25 @@
 y) %7B%0A  this.
+_
 table = tabl
@@ -149,24 +149,25 @@
 ble;%0A  this.
+_
 connectionSt
@@ -202,32 +202,9 @@
 his.
-attributes = %7B%7D;%0A  this.
+_
 prim
@@ -231,32 +231,33 @@
 %7C%7C 'id';%0A  this.
+_
 query = null;%0A%7D%0A
@@ -254,16 +254,38 @@
 = null;%0A
+  this._methods = %7B%7D;%0A
 %7D%0A%0AModel
@@ -351,18 +351,20 @@
 ) %7B%0A
+%0A
   var 
-s
+mod
 el
-f
  = n
@@ -606,21 +606,23 @@
 ble ' + 
-self.
+model._
 table + 
@@ -962,58 +962,22 @@
     
-var proto = Object.getPrototypeOf(this);%0A    proto
+model._methods
 %5Bkey
@@ -992,23 +992,16 @@
   %7D;%0A%0A  
-return 
 definiti
@@ -1006,33 +1006,12 @@
 tion
-;%0A%7D;%0A%0AModel.prototype.run
+.get
  = f
@@ -1022,172 +1022,112 @@
 ion(
+id
 ) %7B%0A  
-var deferred = q.defer();%0A  var query = this.query;%0A  this.query = null;%0A  pg.connect(this.connectionString, function(err, client, done) %7B%0A    if(err) %7B
+  model._query = sql.select().from(model._table).where(model._primaryKey + ' = ?', id);%0A
 %0A    
- 
+var
  def
@@ -1135,253 +1135,121 @@
 rred
-.reject(new Error(err));%0A    %7D%0A%0A    client.query(query.toQuery(), function(err, result) %7B%0A      done();%0A%0A      if(err) %7B%0A        deferred.reject(new Error(err));%0A      %7D%0A      else %7B%0A        deferred.resolve(result.rows);%0A      %7D%0A    %7D);%0A  %7D);%0A%0A
+ = q.defer();%0A    model.run().then(function(rows) %7B%0A      deferred.resolve(rows%5B0%5D);%0A    %7D, deferred.reject);%0A%0A  
   re
@@ -1271,35 +1271,34 @@
 romise;%0A
+  
 %7D;%0A%0A
-Model.prototype
+  definition
 .where =
@@ -1312,29 +1312,33 @@
 on(str) %7B%0A  
-this.
+  model._
 query = sql.
@@ -1343,37 +1343,39 @@
 l.select().from(
-this.
+model._
 table).where.app
@@ -1398,263 +1398,29 @@
 s);%0A
-%0A
   
-return this;%0A%7D;%0A%0AModel.prototype.get = function(id) %7B%0A  this.query = sql.select().from(this.table).where(this.primaryKey + ' = ?', id);%0A%0A  var deferred = q.defer();%0A  this.run().then(function(rows) %7B%0A    deferred.resolve(rows%5B0%5D);%0A  %7D, deferred.reject)
+  return model;%0A  %7D
 ;%0A%0A 
@@ -1426,37 +1426,31 @@
   return def
-erred.promise
+inition
 ;%0A%7D;%0A%0AModel.
@@ -1463,12 +1463,11 @@
 ype.
-save
+run
  = f
@@ -1488,106 +1488,78 @@
 var 
-query = sql.insert(this.table, this.attributes).returning().toQ
+deferred = q.defer();%0A  var query = this._q
 uery
-()
 ;%0A%0A  
-var deferred = q.defer()
+this._query = null
 ;%0A  
@@ -1574,16 +1574,17 @@
 ct(this.
+_
 connecti
@@ -1705,16 +1705,26 @@
 ry(query
+.toQuery()
 , functi
@@ -1820,16 +1820,22 @@
 %0A      %7D
+%0A     
  else %7B%0A
@@ -1866,27 +1866,24 @@
 (result.rows
-%5B0%5D
 );%0A      %7D%0A 

Reorganize model