auto-grow indices
This commit is contained in:
		
							parent
							
								
									8f0680826a
								
							
						
					
					
						commit
						65fe453ac6
					
				
							
								
								
									
										158
									
								
								lib/dbwrap.js
									
									
									
									
									
								
							
							
						
						
									
										158
									
								
								lib/dbwrap.js
									
									
									
									
									
								
							| @ -5,8 +5,12 @@ function wrap(db, dir) { | ||||
|   // why doesn't the unhandled promise rejection fire?
 | ||||
|   var PromiseA = require('bluebird'); | ||||
|   var promises = []; | ||||
|   var earr = []; | ||||
|   var dbsMap = {}; | ||||
|   var arr = true; | ||||
| 
 | ||||
|   db.escape = function (str) { | ||||
|     return (str||'').replace(/'/g, "''"); | ||||
|   }; | ||||
| 
 | ||||
|   function lowerFirst(str) { | ||||
|     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); | ||||
|   } | ||||
| 
 | ||||
|   // 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) { | ||||
|     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 tablename = db.escape(snakeCase(opts.tablename) || 'data'); | ||||
|     var idname = db.escape(snakeCase(opts.idname) || 'id'); | ||||
|     var idnameCased = (camelCase(opts.idname) || 'id'); | ||||
|     var idname = db.escape(snakeCase(opts.idname || 'id')); | ||||
|     var idnameCased = (camelCase(opts.idname || 'id')); | ||||
| 
 | ||||
|     opts.indices.forEach(normalizeColumn); | ||||
| 
 | ||||
|     db = PromiseA.promisifyAll(db); | ||||
| 
 | ||||
| @ -98,6 +189,21 @@ function wrap(db, dir) { | ||||
|       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) { | ||||
|       var sql = 'SELECT * FROM \'' + tablename + '\' '; | ||||
|       var keys = opts && Object.keys(opts); | ||||
| @ -109,7 +215,12 @@ function wrap(db, dir) { | ||||
|           if (i !== 0) { | ||||
|             sql += 'AND '; | ||||
|           } | ||||
|           sql += db.escape(snakeCase(key)) + " = '" + db.escape(opts[key]) + "'"; | ||||
|           if (null === opts[key]) { | ||||
|             sql += db.escape(snakeCase(key)) + " IS '" + db.escape(opts[key]) + "'"; | ||||
|           } | ||||
|           else { | ||||
|             sql += db.escape(snakeCase(key)) + " = '" + db.escape(opts[key]) + "'"; | ||||
|           } | ||||
|         }); | ||||
|       } | ||||
|       else if (null !== opts || (params && !params.limit)) { | ||||
| @ -264,14 +375,7 @@ function wrap(db, dir) { | ||||
|         }); | ||||
|       }); | ||||
| 
 | ||||
|       (opts.indices || []).forEach(function (col) { | ||||
|         if ('string' === typeof col) { | ||||
|           col = { name: col, type: 'TEXT' }; | ||||
|         } | ||||
|         if (!col.type) { | ||||
|           col.type = 'TEXT'; | ||||
|         } | ||||
| 
 | ||||
|       opts.indices.forEach(function (col) { | ||||
|         var val = data[camelCase(col.name)]; | ||||
| 
 | ||||
|         //if (col.name in data)
 | ||||
| @ -386,7 +490,7 @@ function wrap(db, dir) { | ||||
|       var indexable = [idname + ' TEXT']; | ||||
|       var sql; | ||||
| 
 | ||||
|       (opts.indices || []).forEach(function (col) { | ||||
|       opts.indices.forEach(function (col) { | ||||
|         if ('string' === typeof col) { | ||||
|           col = { name: col, type: 'TEXT' }; | ||||
|         } | ||||
| @ -404,19 +508,25 @@ function wrap(db, dir) { | ||||
|         + "(" + 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)) { | ||||
|     arr = false; | ||||
|     dir = [dir]; | ||||
|           resolve(DB); | ||||
|         }); | ||||
|       }, reject); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   dir.forEach(function (opts) { | ||||
|     promises.push(createTable(opts).then(function (dbw) { | ||||
|       var modelname = opts.modelname; | ||||
|        | ||||
|       var modelname = opts.modelname;  | ||||
| 
 | ||||
|       if (!modelname) { | ||||
|         modelname = (opts.tablename || 'data'); | ||||
|         modelname = upperCamelCase(modelname); | ||||
| @ -430,11 +540,7 @@ function wrap(db, dir) { | ||||
| 
 | ||||
|   dbsMap.sql = db; | ||||
| 
 | ||||
|   return PromiseA.all(promises).then(function (dbs) { | ||||
|     if (!arr) { | ||||
|       return dbs[0]; | ||||
|     } | ||||
| 
 | ||||
|   return PromiseA.all(promises).then(function (/*dbs*/) { | ||||
|     return dbsMap; | ||||
|   }); | ||||
| } | ||||
|  | ||||
| @ -3,6 +3,7 @@ | ||||
| var PromiseA = require('bluebird').Promise; | ||||
| 
 | ||||
| function testDb(DB) { | ||||
|   DB = DB.Data; | ||||
|   return PromiseA.resolve(DB).then(function (DB) { | ||||
|     var data = { secret: 'super secret', verifiedAt: 1437207288791 }; | ||||
|     //return DB.set('aj@the.dj', data)
 | ||||
| @ -43,7 +44,7 @@ function testDb(DB) { | ||||
| } | ||||
| 
 | ||||
| function run(/*isMaster*/) { | ||||
|   require('./setup').run().then(testDb); | ||||
|   require('./setup').run([{ modelname: 'Data', indices: ['data'] }]).then(testDb); | ||||
| 
 | ||||
|   /* | ||||
|   if (require.main === module) { | ||||
|  | ||||
| @ -1,8 +1,15 @@ | ||||
| 'use strict'; | ||||
| 
 | ||||
| function run(opts) { | ||||
|   var config = require('../config.test.js'); | ||||
|   var sqlite3 = require('sqlite3-cluster'); | ||||
|   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({ | ||||
|       standalone: true | ||||
|     , bits: 128 | ||||
| @ -13,8 +20,9 @@ function run(opts) { | ||||
|   return promise.then(function (db) { | ||||
|     return db.init({ bits: 128, key: config.key }); | ||||
|   }).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) { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user