208 lines
6.2 KiB
JavaScript
208 lines
6.2 KiB
JavaScript
|
const path = require('path');
|
||
|
const sqlite3 = require('./sqlite3-binding.js');
|
||
|
const EventEmitter = require('events').EventEmitter;
|
||
|
module.exports = exports = sqlite3;
|
||
|
|
||
|
function normalizeMethod (fn) {
|
||
|
return function (sql) {
|
||
|
let errBack;
|
||
|
const args = Array.prototype.slice.call(arguments, 1);
|
||
|
|
||
|
if (typeof args[args.length - 1] === 'function') {
|
||
|
const callback = args[args.length - 1];
|
||
|
errBack = function(err) {
|
||
|
if (err) {
|
||
|
callback(err);
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
const statement = new Statement(this, sql, errBack);
|
||
|
return fn.call(this, statement, args);
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function inherits(target, source) {
|
||
|
for (const k in source.prototype)
|
||
|
target.prototype[k] = source.prototype[k];
|
||
|
}
|
||
|
|
||
|
sqlite3.cached = {
|
||
|
Database: function(file, a, b) {
|
||
|
if (file === '' || file === ':memory:') {
|
||
|
// Don't cache special databases.
|
||
|
return new Database(file, a, b);
|
||
|
}
|
||
|
|
||
|
let db;
|
||
|
file = path.resolve(file);
|
||
|
|
||
|
if (!sqlite3.cached.objects[file]) {
|
||
|
db = sqlite3.cached.objects[file] = new Database(file, a, b);
|
||
|
}
|
||
|
else {
|
||
|
// Make sure the callback is called.
|
||
|
db = sqlite3.cached.objects[file];
|
||
|
const callback = (typeof a === 'number') ? b : a;
|
||
|
if (typeof callback === 'function') {
|
||
|
function cb() { callback.call(db, null); }
|
||
|
if (db.open) process.nextTick(cb);
|
||
|
else db.once('open', cb);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return db;
|
||
|
},
|
||
|
objects: {}
|
||
|
};
|
||
|
|
||
|
|
||
|
const Database = sqlite3.Database;
|
||
|
const Statement = sqlite3.Statement;
|
||
|
const Backup = sqlite3.Backup;
|
||
|
|
||
|
inherits(Database, EventEmitter);
|
||
|
inherits(Statement, EventEmitter);
|
||
|
inherits(Backup, EventEmitter);
|
||
|
|
||
|
// Database#prepare(sql, [bind1, bind2, ...], [callback])
|
||
|
Database.prototype.prepare = normalizeMethod(function(statement, params) {
|
||
|
return params.length
|
||
|
? statement.bind.apply(statement, params)
|
||
|
: statement;
|
||
|
});
|
||
|
|
||
|
// Database#run(sql, [bind1, bind2, ...], [callback])
|
||
|
Database.prototype.run = normalizeMethod(function(statement, params) {
|
||
|
statement.run.apply(statement, params).finalize();
|
||
|
return this;
|
||
|
});
|
||
|
|
||
|
// Database#get(sql, [bind1, bind2, ...], [callback])
|
||
|
Database.prototype.get = normalizeMethod(function(statement, params) {
|
||
|
statement.get.apply(statement, params).finalize();
|
||
|
return this;
|
||
|
});
|
||
|
|
||
|
// Database#all(sql, [bind1, bind2, ...], [callback])
|
||
|
Database.prototype.all = normalizeMethod(function(statement, params) {
|
||
|
statement.all.apply(statement, params).finalize();
|
||
|
return this;
|
||
|
});
|
||
|
|
||
|
// Database#each(sql, [bind1, bind2, ...], [callback], [complete])
|
||
|
Database.prototype.each = normalizeMethod(function(statement, params) {
|
||
|
statement.each.apply(statement, params).finalize();
|
||
|
return this;
|
||
|
});
|
||
|
|
||
|
Database.prototype.map = normalizeMethod(function(statement, params) {
|
||
|
statement.map.apply(statement, params).finalize();
|
||
|
return this;
|
||
|
});
|
||
|
|
||
|
// Database#backup(filename, [callback])
|
||
|
// Database#backup(filename, destName, sourceName, filenameIsDest, [callback])
|
||
|
Database.prototype.backup = function() {
|
||
|
let backup;
|
||
|
if (arguments.length <= 2) {
|
||
|
// By default, we write the main database out to the main database of the named file.
|
||
|
// This is the most likely use of the backup api.
|
||
|
backup = new Backup(this, arguments[0], 'main', 'main', true, arguments[1]);
|
||
|
} else {
|
||
|
// Otherwise, give the user full control over the sqlite3_backup_init arguments.
|
||
|
backup = new Backup(this, arguments[0], arguments[1], arguments[2], arguments[3], arguments[4]);
|
||
|
}
|
||
|
// Per the sqlite docs, exclude the following errors as non-fatal by default.
|
||
|
backup.retryErrors = [sqlite3.BUSY, sqlite3.LOCKED];
|
||
|
return backup;
|
||
|
};
|
||
|
|
||
|
Statement.prototype.map = function() {
|
||
|
const params = Array.prototype.slice.call(arguments);
|
||
|
const callback = params.pop();
|
||
|
params.push(function(err, rows) {
|
||
|
if (err) return callback(err);
|
||
|
const result = {};
|
||
|
if (rows.length) {
|
||
|
const keys = Object.keys(rows[0]);
|
||
|
const key = keys[0];
|
||
|
if (keys.length > 2) {
|
||
|
// Value is an object
|
||
|
for (let i = 0; i < rows.length; i++) {
|
||
|
result[rows[i][key]] = rows[i];
|
||
|
}
|
||
|
} else {
|
||
|
const value = keys[1];
|
||
|
// Value is a plain value
|
||
|
for (let i = 0; i < rows.length; i++) {
|
||
|
result[rows[i][key]] = rows[i][value];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
callback(err, result);
|
||
|
});
|
||
|
return this.all.apply(this, params);
|
||
|
};
|
||
|
|
||
|
let isVerbose = false;
|
||
|
|
||
|
const supportedEvents = [ 'trace', 'profile', 'change' ];
|
||
|
|
||
|
Database.prototype.addListener = Database.prototype.on = function(type) {
|
||
|
const val = EventEmitter.prototype.addListener.apply(this, arguments);
|
||
|
if (supportedEvents.indexOf(type) >= 0) {
|
||
|
this.configure(type, true);
|
||
|
}
|
||
|
return val;
|
||
|
};
|
||
|
|
||
|
Database.prototype.removeListener = function(type) {
|
||
|
const val = EventEmitter.prototype.removeListener.apply(this, arguments);
|
||
|
if (supportedEvents.indexOf(type) >= 0 && !this._events[type]) {
|
||
|
this.configure(type, false);
|
||
|
}
|
||
|
return val;
|
||
|
};
|
||
|
|
||
|
Database.prototype.removeAllListeners = function(type) {
|
||
|
const val = EventEmitter.prototype.removeAllListeners.apply(this, arguments);
|
||
|
if (supportedEvents.indexOf(type) >= 0) {
|
||
|
this.configure(type, false);
|
||
|
}
|
||
|
return val;
|
||
|
};
|
||
|
|
||
|
// Save the stack trace over EIO callbacks.
|
||
|
sqlite3.verbose = function() {
|
||
|
if (!isVerbose) {
|
||
|
const trace = require('./trace');
|
||
|
[
|
||
|
'prepare',
|
||
|
'get',
|
||
|
'run',
|
||
|
'all',
|
||
|
'each',
|
||
|
'map',
|
||
|
'close',
|
||
|
'exec'
|
||
|
].forEach(function (name) {
|
||
|
trace.extendTrace(Database.prototype, name);
|
||
|
});
|
||
|
[
|
||
|
'bind',
|
||
|
'get',
|
||
|
'run',
|
||
|
'all',
|
||
|
'each',
|
||
|
'map',
|
||
|
'reset',
|
||
|
'finalize',
|
||
|
].forEach(function (name) {
|
||
|
trace.extendTrace(Statement.prototype, name);
|
||
|
});
|
||
|
isVerbose = true;
|
||
|
}
|
||
|
|
||
|
return sqlite3;
|
||
|
};
|