var uuid = require('node-uuid');
var sqlite3 = require('sqlite3').verbose();

function SQLiteStore(opts) {
  opts = opts || {};
  this.path = opts.path || ':memory:';
}

var takeNextN = function (first) {
  return function (n, cb) {
    var self = this;
    var sql = function (fields) {
      return "SELECT " + fields + " FROM tasks WHERE lock = '' ORDER BY priority DESC, added " + (first ? "ASC" : "DESC") + " LIMIT ?"
    };
    var lockId = uuid.v4();
    self.db.run("UPDATE tasks SET lock = ? WHERE id IN (" + sql('id') + ")", [lockId, n], function (err) {
      if (err) return cb(err);
      if (!this.changes) return cb(null, '');
      cb(null, lockId);
    });
  }
}

SQLiteStore.prototype.connect = function (cb) {
  var self = this;
  self.db = new sqlite3.Database(self.path, function (err) {
    if (err) return cb({ message: 'failed_to_open_sqlite_db' });
    self.db.run("CREATE TABLE IF NOT EXISTS tasks (id TEXT UNIQUE, lock TEXT, task TEXT, priority NUMERIC, added INTEGER PRIMARY KEY AUTOINCREMENT)", function (err) {
      if (err) return cb({ message: 'failed_to_create_table' });
      self.db.get("SELECT count(*) as n FROM tasks WHERE lock = ''", function (err, row) {
        if (err) return cb({ message: 'failed_to_fetch_count' });
        cb(null, row.n);
      });
    });
  });
}

SQLiteStore.prototype.getTask = function (taskId, cb) {
  this.db.get("SELECT task FROM tasks WHERE id = ? AND lock = ''", taskId, function (err, row) {
    if (err) return cb({ message: 'failed_to_get_from_sqlite_db' });
    if (!row) return cb(null);
    try {
      var savedTask = JSON.parse(row.task);
    } catch (e) {
      return cb('failed_to_deserialize_task');
    }
    cb(null, savedTask);
  });
}

SQLiteStore.prototype.deleteTask = function (taskId, cb) {
  this.db.run("DELETE FROM tasks WHERE id = ?", [taskId], cb);
}

SQLiteStore.prototype.putTask = function (taskId, task, priority, cb) {
  try {
    var serializedTask = JSON.stringify(task);
  } catch (e) {
    return cb('failed_to_serialize_task');
  }
  this.db.run("INSERT OR REPLACE INTO tasks VALUES (?, ?, ?, ?, NULL)", [taskId, '', serializedTask, priority || 1], cb);
}

SQLiteStore.prototype.takeFirstN = takeNextN(true);
SQLiteStore.prototype.takeLastN = takeNextN(false);

SQLiteStore.prototype.getLock = function (lockId, cb) {
  var self = this;
  self.db.all("SELECT id, task FROM tasks WHERE lock = ?", lockId, function (err, rows) {
    if (err) return cb(err)
    var tasks = {};
    rows.forEach(function (row) {
      tasks[row.id] = JSON.parse(row.task);
    })
    cb(null, tasks);
  });
}

SQLiteStore.prototype.getRunningTasks = function (cb) {
  var self = this;
  self.db.all("SELECT id, task, lock FROM tasks", function (err, rows) {
    if (err) return cb({ message: 'failed_to_fetch_tasks' });
    var tasks = {};
    rows.forEach(function (row) {
      tasks[row.lock] = tasks[row.lock] || [];
      tasks[row.lock][row.id] = JSON.parse(row.task);
    })
    cb(null, tasks);
  })
}

SQLiteStore.prototype.releaseLock = function (lockId, cb) {
  var self = this;
  self.db.run("DELETE FROM tasks WHERE lock = ?", lockId, cb);
}


module.exports = SQLiteStore;

@@ -1,48 +1,16 @@
 var 
-uuid = require('node-uuid');%0Avar sqlite3
+SqlStore
  = r
@@ -21,26 +21,14 @@
 re('
+./
 sql
-ite3').verbose(
+'
 );%0A%0A
@@ -83,3023 +83,162 @@
 ;%0A  
-this.path = opts.path %7C%7C ':memory:';%0A%7D%0A%0Avar takeNextN = function (first) %7B%0A  return function (n, cb) %7B%0A    var self = this;%0A    var sql = function (fields) %7B%0A      return %22SELECT %22 + fields + %22 FROM tasks WHERE lock = '' ORDER BY priority DESC, added %22 + (first ? %22ASC%22 : %22DESC%22) + %22 LIMIT ?%22%0A    %7D;%0A    var lockId = uuid.v4();%0A    self.db.run(%22UPDATE tasks SET lock = ? WHERE id IN (%22 + sql('id') + %22)%22, %5BlockId, n%5D, function (err) %7B%0A      if (err) return cb(err);%0A      if (!this.changes) return cb(null, '');%0A      cb(null, lockId);%0A    %7D);%0A  %7D%0A%7D%0A%0ASQLiteStore.prototype.connect = function (cb) %7B%0A  var self = this;%0A  self.db = new sqlite3.Database(self.path, function (err) %7B%0A    if (err) return cb(%7B message: 'failed_to_open_sqlite_db' %7D);%0A    self.db.run(%22CREATE TABLE IF NOT EXISTS tasks (id TEXT UNIQUE, lock TEXT, task TEXT, priority NUMERIC, added INTEGER PRIMARY KEY AUTOINCREMENT)%22, function (err) %7B%0A      if (err) return cb(%7B message: 'failed_to_create_table' %7D);%0A      self.db.get(%22SELECT count(*) as n FROM tasks WHERE lock = ''%22, function (err, row) %7B%0A        if (err) return cb(%7B message: 'failed_to_fetch_count' %7D);%0A        cb(null, row.n);%0A      %7D);%0A    %7D);%0A  %7D);%0A%7D%0A%0ASQLiteStore.prototype.getTask = function (taskId, cb) %7B%0A  this.db.get(%22SELECT task FROM tasks WHERE id = ? AND lock = ''%22, taskId, function (err, row) %7B%0A    if (err) return cb(%7B message: 'failed_to_get_from_sqlite_db' %7D);%0A    if (!row) return cb(null);%0A    try %7B%0A      var savedTask = JSON.parse(row.task);%0A    %7D catch (e) %7B%0A      return cb('failed_to_deserialize_task')
+opts.dialect = 'sqlite';%0A  opts.path = opts.path %7C%7C ':memory:'
 ;%0A  
- 
- %7D%0A    cb(null, savedTask);%0A  %7D);%0A%7D%0A%0ASQLiteStore.prototype.deleteTask = function (taskId, cb) %7B%0A  this.db.run(%22DELETE FROM tasks WHERE id = ?%22, %5BtaskId%5D, cb);%0A%7D%0A%0ASQLiteStore.prototype.putTask = function (taskId, task, priority, cb) %7B%0A  try %7B%0A    var serializedTask = JSON.stringify(task);%0A  %7D catch (e) %7B%0A    return cb('failed_to_serialize_task');%0A  %7D%0A  this.db.run(%22INSERT OR REPLACE INTO tasks VALUES (?, ?, ?, ?, NULL)%22, %5BtaskId, '', serializedTask, priority %7C%7C 1%5D, cb);%0A%7D%0A%0ASQLiteStore.prototype.takeFirstN = takeNextN(true);%0ASQLiteStore.prototype.takeLastN = takeNextN(false);%0A%0ASQLiteStore.prototype.getLock = function (lockId, cb) %7B%0A  var self = this;%0A  self.db.all(%22SELECT id, task FROM tasks WHERE lock = ?%22, lockId, function (err, rows) %7B%0A    if (err) return cb(err)%0A    var tasks = %7B%7D;%0A    rows.forEach(function (row) %7B%0A      tasks%5Brow.id%5D = JSON.parse(row.task);%0A    %7D)%0A    cb(null, tasks);%0A  %7D);%0A%7D%0A%0ASQLiteStore.prototype.getRunningTasks = function (cb) %7B%0A  var self = this;%0A  self.db.all(%22SELECT id, task, lock FROM tasks%22, function (err, rows) %7B%0A    if (err) return cb(%7B message: 'failed_to_fetch_tasks' %7D);%0A    var tasks = %7B%7D;%0A    rows.forEach(function (row) %7B%0A      tasks%5Brow.lock%5D = tasks%5Brow.lock%5D %7C%7C %5B%5D;%0A      tasks%5Brow.lock%5D%5Brow.id%5D = JSON.parse(row.task);%0A    %7D)%0A    cb(null, tasks);%0A  %7D)%0A%7D%0A%0ASQLiteStore.prototype.releaseLock = function (lockId, cb) %7B%0A  var self = this;%0A  self.db.run(%22DELETE FROM tasks WHERE lock = ?%22, lockId, cb);%0A%7D%0A
+SqlStore.call(this, opts);%0A%7D%0A%0ASQLiteStore.prototype = Object.create(SqlStore.prototype);
 %0A%0Amo

make sqlite store use sql store