auto-grow indices

This commit is contained in:
AJ ONeal 2015-12-01 04:44:52 +00:00
parent 8f0680826a
commit 65fe453ac6
3 changed files with 144 additions and 29 deletions

View File

@ -5,8 +5,12 @@ function wrap(db, dir) {
// why doesn't the unhandled promise rejection fire? // why doesn't the unhandled promise rejection fire?
var PromiseA = require('bluebird'); var PromiseA = require('bluebird');
var promises = []; var promises = [];
var earr = [];
var dbsMap = {}; var dbsMap = {};
var arr = true;
db.escape = function (str) {
return (str||'').replace(/'/g, "''");
};
function lowerFirst(str) { function lowerFirst(str) {
return str.charAt(0).toLowerCase() + str.slice(1); return str.charAt(0).toLowerCase() + str.slice(1);
@ -36,11 +40,98 @@ function wrap(db, dir) {
return str.charAt(0).toUpperCase() + camelCase(str).slice(1); return str.charAt(0).toUpperCase() + camelCase(str).slice(1);
} }
// PRAGMA schema.table_info(table-name);
//
function sqlite3GetColumns(tablename, columns, cb) {
var sql = "PRAGMA table_info(" + db.escape(tablename) + ")";
db.all(sql, earr, function (err, result) {
if (err) {
console.error('[Error] query columns');
console.error(err.stack);
cb(err);
return;
}
console.log('sqlite3 rows 0');
console.log(result);
function alterTable() {
var column = columns.pop();
var sql;
if (!column) {
cb(null);
return;
}
if ((result.rows||result).some(function (row) {
return (row.column_name || row.name) === snakeCase(column.name);
})) {
alterTable();
return;
}
sql = "ALTER TABLE " + db.escape(tablename)
+ " ADD COLUMN "
+ db.escape(column.name) + " " + db.escape(column.type)
+ " DEFAULT null"
;
console.log('sqlite3 1');
console.log(sql);
db.all(sql, earr, function (err, results) {
if (err) {
console.error("[Error] add column '" + tablename + "'");
console.error(err.stack);
cb(err);
return;
}
console.log('sqlite3 rows 1');
console.log(results);
alterTable();
});
}
alterTable();
});
}
function normalizeColumn(col, i, arr) {
if ('string' === typeof col) {
col = arr[i] = { name: col, type: 'text' };
}
if (!col.type) {
col.type = 'text';
}
col.type = col.type.toLowerCase(); // oh postgres...
col.name = snakeCase(col.name);
return col;
}
function createTable(opts) { function createTable(opts) {
if (!opts.modelname && !opts.tablename) {
throw new Error('Please specify opts.modelname');
}
if (!opts.tablename) {
opts.tablename = snakeCase(opts.modelname);
}
if (!opts.indices) {
opts.indices = [];
}
var DB = {}; var DB = {};
var tablename = db.escape(snakeCase(opts.tablename) || 'data'); var tablename = db.escape(snakeCase(opts.tablename) || 'data');
var idname = db.escape(snakeCase(opts.idname) || 'id'); var idname = db.escape(snakeCase(opts.idname || 'id'));
var idnameCased = (camelCase(opts.idname) || 'id'); var idnameCased = (camelCase(opts.idname || 'id'));
opts.indices.forEach(normalizeColumn);
db = PromiseA.promisifyAll(db); db = PromiseA.promisifyAll(db);
@ -98,6 +189,21 @@ function wrap(db, dir) {
return results; return results;
} }
DB.migrate = function (columns) {
columns.forEach(normalizeColumn);
return new PromiseA(function (resolve, reject) {
sqlite3GetColumns(tablename, columns, function (err) {
if (err) {
reject(err);
return;
}
resolve();
});
});
};
DB.find = function (opts, params) { DB.find = function (opts, params) {
var sql = 'SELECT * FROM \'' + tablename + '\' '; var sql = 'SELECT * FROM \'' + tablename + '\' ';
var keys = opts && Object.keys(opts); var keys = opts && Object.keys(opts);
@ -109,7 +215,12 @@ function wrap(db, dir) {
if (i !== 0) { if (i !== 0) {
sql += 'AND '; sql += 'AND ';
} }
if (null === opts[key]) {
sql += db.escape(snakeCase(key)) + " IS '" + db.escape(opts[key]) + "'";
}
else {
sql += db.escape(snakeCase(key)) + " = '" + db.escape(opts[key]) + "'"; sql += db.escape(snakeCase(key)) + " = '" + db.escape(opts[key]) + "'";
}
}); });
} }
else if (null !== opts || (params && !params.limit)) { else if (null !== opts || (params && !params.limit)) {
@ -264,14 +375,7 @@ function wrap(db, dir) {
}); });
}); });
(opts.indices || []).forEach(function (col) { opts.indices.forEach(function (col) {
if ('string' === typeof col) {
col = { name: col, type: 'TEXT' };
}
if (!col.type) {
col.type = 'TEXT';
}
var val = data[camelCase(col.name)]; var val = data[camelCase(col.name)];
//if (col.name in data) //if (col.name in data)
@ -386,7 +490,7 @@ function wrap(db, dir) {
var indexable = [idname + ' TEXT']; var indexable = [idname + ' TEXT'];
var sql; var sql;
(opts.indices || []).forEach(function (col) { opts.indices.forEach(function (col) {
if ('string' === typeof col) { if ('string' === typeof col) {
col = { name: col, type: 'TEXT' }; col = { name: col, type: 'TEXT' };
} }
@ -404,13 +508,19 @@ function wrap(db, dir) {
+ "(" + indexable.join(', ') + ", PRIMARY KEY(" + idname + "))" + "(" + indexable.join(', ') + ", PRIMARY KEY(" + idname + "))"
; ;
db.runAsync(sql).then(function () { resolve(DB); }, reject); db.runAsync(sql).then(function () {
}); sqlite3GetColumns(tablename, opts.indices, function (err) {
if (err) {
console.error('[Error] dbwrap get columns');
console.error(err.stack);
reject(err);
return;
} }
if (!Array.isArray(dir)) { resolve(DB);
arr = false; });
dir = [dir]; }, reject);
});
} }
dir.forEach(function (opts) { dir.forEach(function (opts) {
@ -430,11 +540,7 @@ function wrap(db, dir) {
dbsMap.sql = db; dbsMap.sql = db;
return PromiseA.all(promises).then(function (dbs) { return PromiseA.all(promises).then(function (/*dbs*/) {
if (!arr) {
return dbs[0];
}
return dbsMap; return dbsMap;
}); });
} }

View File

@ -3,6 +3,7 @@
var PromiseA = require('bluebird').Promise; var PromiseA = require('bluebird').Promise;
function testDb(DB) { function testDb(DB) {
DB = DB.Data;
return PromiseA.resolve(DB).then(function (DB) { return PromiseA.resolve(DB).then(function (DB) {
var data = { secret: 'super secret', verifiedAt: 1437207288791 }; var data = { secret: 'super secret', verifiedAt: 1437207288791 };
//return DB.set('aj@the.dj', data) //return DB.set('aj@the.dj', data)
@ -43,7 +44,7 @@ function testDb(DB) {
} }
function run(/*isMaster*/) { function run(/*isMaster*/) {
require('./setup').run().then(testDb); require('./setup').run([{ modelname: 'Data', indices: ['data'] }]).then(testDb);
/* /*
if (require.main === module) { if (require.main === module) {

View File

@ -1,8 +1,15 @@
'use strict';
function run(opts) { function run(opts) {
var config = require('../config.test.js'); var config = require('../config.test.js');
var sqlite3 = require('sqlite3-cluster');
var wrap = require('../lib/dbwrap'); var wrap = require('../lib/dbwrap');
var sqlite3 = require('sqlite3');
var db = new sqlite3.Database(config.filename);
return wrap.wrap(db, opts);
/*
var sqlite3 = require('sqlite3-cluster');
var promise = sqlite3.create({ var promise = sqlite3.create({
standalone: true standalone: true
, bits: 128 , bits: 128
@ -13,8 +20,9 @@ function run(opts) {
return promise.then(function (db) { return promise.then(function (db) {
return db.init({ bits: 128, key: config.key }); return db.init({ bits: 128, key: config.key });
}).then(function (db) { }).then(function (db) {
return wrap.wrap(db, Array.isArray(opts) && opts || { idname: 'uuid', tablename: opts && opts.tablename || 'authn' }); return wrap.wrap(db, opts);
}); });
*/
/* /*
if (require.main === module) { if (require.main === module) {