Sqlite-Plugin, DB-Copy plugin added und integriert
This commit is contained in:
574
plugins/cordova-sqlite-storage/www/SQLitePlugin.js
vendored
Normal file
574
plugins/cordova-sqlite-storage/www/SQLitePlugin.js
vendored
Normal file
@@ -0,0 +1,574 @@
|
||||
(function() {
|
||||
var DB_STATE_INIT, DB_STATE_OPEN, READ_ONLY_REGEX, SQLiteFactory, SQLitePlugin, SQLitePluginTransaction, argsArray, dblocations, newSQLError, nextTick, root, txLocks;
|
||||
|
||||
root = this;
|
||||
|
||||
READ_ONLY_REGEX = /^\s*(?:drop|delete|insert|update|create)\s/i;
|
||||
|
||||
DB_STATE_INIT = "INIT";
|
||||
|
||||
DB_STATE_OPEN = "OPEN";
|
||||
|
||||
txLocks = {};
|
||||
|
||||
newSQLError = function(error, code) {
|
||||
var sqlError;
|
||||
sqlError = error;
|
||||
if (!code) {
|
||||
code = 0;
|
||||
}
|
||||
if (!sqlError) {
|
||||
sqlError = new Error("a plugin had an error but provided no response");
|
||||
sqlError.code = code;
|
||||
}
|
||||
if (typeof sqlError === "string") {
|
||||
sqlError = new Error(error);
|
||||
sqlError.code = code;
|
||||
}
|
||||
if (!sqlError.code && sqlError.message) {
|
||||
sqlError.code = code;
|
||||
}
|
||||
if (!sqlError.code && !sqlError.message) {
|
||||
sqlError = new Error("an unknown error was returned: " + JSON.stringify(sqlError));
|
||||
sqlError.code = code;
|
||||
}
|
||||
return sqlError;
|
||||
};
|
||||
|
||||
nextTick = window.setImmediate || function(fun) {
|
||||
window.setTimeout(fun, 0);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Utility that avoids leaking the arguments object. See
|
||||
https://www.npmjs.org/package/argsarray
|
||||
*/
|
||||
|
||||
argsArray = function(fun) {
|
||||
return function() {
|
||||
var args, i, len;
|
||||
len = arguments.length;
|
||||
if (len) {
|
||||
args = [];
|
||||
i = -1;
|
||||
while (++i < len) {
|
||||
args[i] = arguments[i];
|
||||
}
|
||||
return fun.call(this, args);
|
||||
} else {
|
||||
return fun.call(this, []);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
SQLitePlugin = function(openargs, openSuccess, openError) {
|
||||
var dbname;
|
||||
if (!(openargs && openargs['name'])) {
|
||||
throw newSQLError("Cannot create a SQLitePlugin db instance without a db name");
|
||||
}
|
||||
dbname = openargs.name;
|
||||
if (typeof dbname !== 'string') {
|
||||
throw newSQLError('sqlite plugin database name must be a string');
|
||||
}
|
||||
this.openargs = openargs;
|
||||
this.dbname = dbname;
|
||||
this.openSuccess = openSuccess;
|
||||
this.openError = openError;
|
||||
this.openSuccess || (this.openSuccess = function() {
|
||||
console.log("DB opened: " + dbname);
|
||||
});
|
||||
this.openError || (this.openError = function(e) {
|
||||
console.log(e.message);
|
||||
});
|
||||
this.open(this.openSuccess, this.openError);
|
||||
};
|
||||
|
||||
SQLitePlugin.prototype.databaseFeatures = {
|
||||
isSQLitePluginDatabase: true
|
||||
};
|
||||
|
||||
SQLitePlugin.prototype.openDBs = {};
|
||||
|
||||
SQLitePlugin.prototype.addTransaction = function(t) {
|
||||
if (!txLocks[this.dbname]) {
|
||||
txLocks[this.dbname] = {
|
||||
queue: [],
|
||||
inProgress: false
|
||||
};
|
||||
}
|
||||
txLocks[this.dbname].queue.push(t);
|
||||
if (this.dbname in this.openDBs && this.openDBs[this.dbname] !== DB_STATE_INIT) {
|
||||
this.startNextTransaction();
|
||||
} else {
|
||||
if (this.dbname in this.openDBs) {
|
||||
console.log('new transaction is waiting for open operation');
|
||||
} else {
|
||||
console.log('database is closed, new transaction is [stuck] waiting until db is opened again!');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SQLitePlugin.prototype.transaction = function(fn, error, success) {
|
||||
if (!this.openDBs[this.dbname]) {
|
||||
error(newSQLError('database not open'));
|
||||
return;
|
||||
}
|
||||
this.addTransaction(new SQLitePluginTransaction(this, fn, error, success, true, false));
|
||||
};
|
||||
|
||||
SQLitePlugin.prototype.readTransaction = function(fn, error, success) {
|
||||
if (!this.openDBs[this.dbname]) {
|
||||
error(newSQLError('database not open'));
|
||||
return;
|
||||
}
|
||||
this.addTransaction(new SQLitePluginTransaction(this, fn, error, success, false, true));
|
||||
};
|
||||
|
||||
SQLitePlugin.prototype.startNextTransaction = function() {
|
||||
var self;
|
||||
self = this;
|
||||
nextTick((function(_this) {
|
||||
return function() {
|
||||
var txLock;
|
||||
if (!(_this.dbname in _this.openDBs) || _this.openDBs[_this.dbname] !== DB_STATE_OPEN) {
|
||||
console.log('cannot start next transaction: database not open');
|
||||
return;
|
||||
}
|
||||
txLock = txLocks[self.dbname];
|
||||
if (!txLock) {
|
||||
console.log('cannot start next transaction: database connection is lost');
|
||||
return;
|
||||
} else if (txLock.queue.length > 0 && !txLock.inProgress) {
|
||||
txLock.inProgress = true;
|
||||
txLock.queue.shift().start();
|
||||
}
|
||||
};
|
||||
})(this));
|
||||
};
|
||||
|
||||
SQLitePlugin.prototype.abortAllPendingTransactions = function() {
|
||||
var j, len1, ref, tx, txLock;
|
||||
txLock = txLocks[this.dbname];
|
||||
if (!!txLock && txLock.queue.length > 0) {
|
||||
ref = txLock.queue;
|
||||
for (j = 0, len1 = ref.length; j < len1; j++) {
|
||||
tx = ref[j];
|
||||
tx.abortFromQ(newSQLError('Invalid database handle'));
|
||||
}
|
||||
txLock.queue = [];
|
||||
txLock.inProgress = false;
|
||||
}
|
||||
};
|
||||
|
||||
SQLitePlugin.prototype.open = function(success, error) {
|
||||
var openerrorcb, opensuccesscb;
|
||||
if (this.dbname in this.openDBs) {
|
||||
console.log('database already open: ' + this.dbname);
|
||||
nextTick((function(_this) {
|
||||
return function() {
|
||||
success(_this);
|
||||
};
|
||||
})(this));
|
||||
} else {
|
||||
console.log('OPEN database: ' + this.dbname);
|
||||
opensuccesscb = (function(_this) {
|
||||
return function() {
|
||||
var txLock;
|
||||
if (!_this.openDBs[_this.dbname]) {
|
||||
console.log('database was closed during open operation');
|
||||
}
|
||||
if (_this.dbname in _this.openDBs) {
|
||||
_this.openDBs[_this.dbname] = DB_STATE_OPEN;
|
||||
}
|
||||
if (!!success) {
|
||||
success(_this);
|
||||
}
|
||||
txLock = txLocks[_this.dbname];
|
||||
if (!!txLock && txLock.queue.length > 0 && !txLock.inProgress) {
|
||||
_this.startNextTransaction();
|
||||
}
|
||||
};
|
||||
})(this);
|
||||
openerrorcb = (function(_this) {
|
||||
return function() {
|
||||
console.log('OPEN database: ' + _this.dbname + ' failed, aborting any pending transactions');
|
||||
if (!!error) {
|
||||
error(newSQLError('Could not open database'));
|
||||
}
|
||||
delete _this.openDBs[_this.dbname];
|
||||
_this.abortAllPendingTransactions();
|
||||
};
|
||||
})(this);
|
||||
this.openDBs[this.dbname] = DB_STATE_INIT;
|
||||
cordova.exec(opensuccesscb, openerrorcb, "SQLitePlugin", "open", [this.openargs]);
|
||||
}
|
||||
};
|
||||
|
||||
SQLitePlugin.prototype.close = function(success, error) {
|
||||
if (this.dbname in this.openDBs) {
|
||||
if (txLocks[this.dbname] && txLocks[this.dbname].inProgress) {
|
||||
console.log('cannot close: transaction is in progress');
|
||||
error(newSQLError('database cannot be closed while a transaction is in progress'));
|
||||
return;
|
||||
}
|
||||
console.log('CLOSE database: ' + this.dbname);
|
||||
delete this.openDBs[this.dbname];
|
||||
if (txLocks[this.dbname]) {
|
||||
console.log('closing db with transaction queue length: ' + txLocks[this.dbname].queue.length);
|
||||
} else {
|
||||
console.log('closing db with no transaction lock state');
|
||||
}
|
||||
cordova.exec(success, error, "SQLitePlugin", "close", [
|
||||
{
|
||||
path: this.dbname
|
||||
}
|
||||
]);
|
||||
} else {
|
||||
console.log('cannot close: database is not open');
|
||||
if (error) {
|
||||
nextTick(function() {
|
||||
return error();
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SQLitePlugin.prototype.executeSql = function(statement, params, success, error) {
|
||||
var myerror, myfn, mysuccess;
|
||||
mysuccess = function(t, r) {
|
||||
if (!!success) {
|
||||
return success(r);
|
||||
}
|
||||
};
|
||||
myerror = function(t, e) {
|
||||
if (!!error) {
|
||||
return error(e);
|
||||
}
|
||||
};
|
||||
myfn = function(tx) {
|
||||
tx.addStatement(statement, params, mysuccess, myerror);
|
||||
};
|
||||
this.addTransaction(new SQLitePluginTransaction(this, myfn, null, null, false, false));
|
||||
};
|
||||
|
||||
SQLitePluginTransaction = function(db, fn, error, success, txlock, readOnly) {
|
||||
if (typeof fn !== "function") {
|
||||
|
||||
/*
|
||||
This is consistent with the implementation in Chrome -- it
|
||||
throws if you pass anything other than a function. This also
|
||||
prevents us from stalling our txQueue if somebody passes a
|
||||
false value for fn.
|
||||
*/
|
||||
throw newSQLError("transaction expected a function");
|
||||
}
|
||||
this.db = db;
|
||||
this.fn = fn;
|
||||
this.error = error;
|
||||
this.success = success;
|
||||
this.txlock = txlock;
|
||||
this.readOnly = readOnly;
|
||||
this.executes = [];
|
||||
if (txlock) {
|
||||
this.addStatement("BEGIN", [], null, function(tx, err) {
|
||||
throw newSQLError("unable to begin transaction: " + err.message, err.code);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
SQLitePluginTransaction.prototype.start = function() {
|
||||
var err, error1;
|
||||
try {
|
||||
this.fn(this);
|
||||
this.run();
|
||||
} catch (error1) {
|
||||
err = error1;
|
||||
txLocks[this.db.dbname].inProgress = false;
|
||||
this.db.startNextTransaction();
|
||||
if (this.error) {
|
||||
this.error(newSQLError(err));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SQLitePluginTransaction.prototype.executeSql = function(sql, values, success, error) {
|
||||
if (this.finalized) {
|
||||
throw {
|
||||
message: 'InvalidStateError: DOM Exception 11: This transaction is already finalized. Transactions are committed after its success or failure handlers are called. If you are using a Promise to handle callbacks, be aware that implementations following the A+ standard adhere to run-to-completion semantics and so Promise resolution occurs on a subsequent tick and therefore after the transaction commits.',
|
||||
code: 11
|
||||
};
|
||||
return;
|
||||
}
|
||||
if (this.readOnly && READ_ONLY_REGEX.test(sql)) {
|
||||
this.handleStatementFailure(error, {
|
||||
message: 'invalid sql for a read-only transaction'
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.addStatement(sql, values, success, error);
|
||||
};
|
||||
|
||||
SQLitePluginTransaction.prototype.addStatement = function(sql, values, success, error) {
|
||||
var j, len1, params, t, v;
|
||||
params = [];
|
||||
if (!!values && values.constructor === Array) {
|
||||
for (j = 0, len1 = values.length; j < len1; j++) {
|
||||
v = values[j];
|
||||
t = typeof v;
|
||||
params.push((v === null || v === void 0 || t === 'number' || t === 'string' ? v : v instanceof Blob ? v.valueOf() : v.toString()));
|
||||
}
|
||||
}
|
||||
this.executes.push({
|
||||
success: success,
|
||||
error: error,
|
||||
sql: sql,
|
||||
params: params
|
||||
});
|
||||
};
|
||||
|
||||
SQLitePluginTransaction.prototype.handleStatementSuccess = function(handler, response) {
|
||||
var payload, rows;
|
||||
if (!handler) {
|
||||
return;
|
||||
}
|
||||
rows = response.rows || [];
|
||||
payload = {
|
||||
rows: {
|
||||
item: function(i) {
|
||||
return rows[i];
|
||||
},
|
||||
length: rows.length
|
||||
},
|
||||
rowsAffected: response.rowsAffected || 0,
|
||||
insertId: response.insertId || void 0
|
||||
};
|
||||
handler(this, payload);
|
||||
};
|
||||
|
||||
SQLitePluginTransaction.prototype.handleStatementFailure = function(handler, response) {
|
||||
if (!handler) {
|
||||
throw newSQLError("a statement with no error handler failed: " + response.message, response.code);
|
||||
}
|
||||
if (handler(this, response) !== false) {
|
||||
throw newSQLError("a statement error callback did not return false: " + response.message, response.code);
|
||||
}
|
||||
};
|
||||
|
||||
SQLitePluginTransaction.prototype.run = function() {
|
||||
var batchExecutes, handlerFor, i, mycb, mycbmap, request, tropts, tx, txFailure, waiting;
|
||||
txFailure = null;
|
||||
tropts = [];
|
||||
batchExecutes = this.executes;
|
||||
waiting = batchExecutes.length;
|
||||
this.executes = [];
|
||||
tx = this;
|
||||
handlerFor = function(index, didSucceed) {
|
||||
return function(response) {
|
||||
var err, error1;
|
||||
try {
|
||||
if (didSucceed) {
|
||||
tx.handleStatementSuccess(batchExecutes[index].success, response);
|
||||
} else {
|
||||
tx.handleStatementFailure(batchExecutes[index].error, newSQLError(response));
|
||||
}
|
||||
} catch (error1) {
|
||||
err = error1;
|
||||
if (!txFailure) {
|
||||
txFailure = newSQLError(err);
|
||||
}
|
||||
}
|
||||
if (--waiting === 0) {
|
||||
if (txFailure) {
|
||||
tx.abort(txFailure);
|
||||
} else if (tx.executes.length > 0) {
|
||||
tx.run();
|
||||
} else {
|
||||
tx.finish();
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
i = 0;
|
||||
mycbmap = {};
|
||||
while (i < batchExecutes.length) {
|
||||
request = batchExecutes[i];
|
||||
mycbmap[i] = {
|
||||
success: handlerFor(i, true),
|
||||
error: handlerFor(i, false)
|
||||
};
|
||||
tropts.push({
|
||||
qid: 1111,
|
||||
sql: request.sql,
|
||||
params: request.params
|
||||
});
|
||||
i++;
|
||||
}
|
||||
mycb = function(result) {
|
||||
var j, last, q, r, ref, res, type;
|
||||
last = result.length - 1;
|
||||
for (i = j = 0, ref = last; 0 <= ref ? j <= ref : j >= ref; i = 0 <= ref ? ++j : --j) {
|
||||
r = result[i];
|
||||
type = r.type;
|
||||
res = r.result;
|
||||
q = mycbmap[i];
|
||||
if (q) {
|
||||
if (q[type]) {
|
||||
q[type](res);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
cordova.exec(mycb, null, "SQLitePlugin", "backgroundExecuteSqlBatch", [
|
||||
{
|
||||
dbargs: {
|
||||
dbname: this.db.dbname
|
||||
},
|
||||
executes: tropts
|
||||
}
|
||||
]);
|
||||
};
|
||||
|
||||
SQLitePluginTransaction.prototype.abort = function(txFailure) {
|
||||
var failed, succeeded, tx;
|
||||
if (this.finalized) {
|
||||
return;
|
||||
}
|
||||
tx = this;
|
||||
succeeded = function(tx) {
|
||||
txLocks[tx.db.dbname].inProgress = false;
|
||||
tx.db.startNextTransaction();
|
||||
if (tx.error) {
|
||||
tx.error(txFailure);
|
||||
}
|
||||
};
|
||||
failed = function(tx, err) {
|
||||
txLocks[tx.db.dbname].inProgress = false;
|
||||
tx.db.startNextTransaction();
|
||||
if (tx.error) {
|
||||
tx.error(newSQLError("error while trying to roll back: " + err.message, err.code));
|
||||
}
|
||||
};
|
||||
this.finalized = true;
|
||||
if (this.txlock) {
|
||||
this.addStatement("ROLLBACK", [], succeeded, failed);
|
||||
this.run();
|
||||
} else {
|
||||
succeeded(tx);
|
||||
}
|
||||
};
|
||||
|
||||
SQLitePluginTransaction.prototype.finish = function() {
|
||||
var failed, succeeded, tx;
|
||||
if (this.finalized) {
|
||||
return;
|
||||
}
|
||||
tx = this;
|
||||
succeeded = function(tx) {
|
||||
txLocks[tx.db.dbname].inProgress = false;
|
||||
tx.db.startNextTransaction();
|
||||
if (tx.success) {
|
||||
tx.success();
|
||||
}
|
||||
};
|
||||
failed = function(tx, err) {
|
||||
txLocks[tx.db.dbname].inProgress = false;
|
||||
tx.db.startNextTransaction();
|
||||
if (tx.error) {
|
||||
tx.error(newSQLError("error while trying to commit: " + err.message, err.code));
|
||||
}
|
||||
};
|
||||
this.finalized = true;
|
||||
if (this.txlock) {
|
||||
this.addStatement("COMMIT", [], succeeded, failed);
|
||||
this.run();
|
||||
} else {
|
||||
succeeded(tx);
|
||||
}
|
||||
};
|
||||
|
||||
SQLitePluginTransaction.prototype.abortFromQ = function(sqlerror) {
|
||||
if (this.error) {
|
||||
this.error(sqlerror);
|
||||
}
|
||||
};
|
||||
|
||||
dblocations = ["docs", "libs", "nosync"];
|
||||
|
||||
SQLiteFactory = {
|
||||
|
||||
/*
|
||||
NOTE: this function should NOT be translated from Javascript
|
||||
back to CoffeeScript by js2coffee.
|
||||
If this function is edited in Javascript then someone will
|
||||
have to translate it back to CoffeeScript by hand.
|
||||
*/
|
||||
opendb: argsArray(function(args) {
|
||||
var dblocation, errorcb, first, okcb, openargs;
|
||||
if (args.length < 1) {
|
||||
return null;
|
||||
}
|
||||
first = args[0];
|
||||
openargs = null;
|
||||
okcb = null;
|
||||
errorcb = null;
|
||||
if (first.constructor === String) {
|
||||
openargs = {
|
||||
name: first
|
||||
};
|
||||
if (args.length >= 5) {
|
||||
okcb = args[4];
|
||||
if (args.length > 5) {
|
||||
errorcb = args[5];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
openargs = first;
|
||||
if (args.length >= 2) {
|
||||
okcb = args[1];
|
||||
if (args.length > 2) {
|
||||
errorcb = args[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
dblocation = !!openargs.location ? dblocations[openargs.location] : null;
|
||||
openargs.dblocation = dblocation || dblocations[0];
|
||||
if (!!openargs.createFromLocation && openargs.createFromLocation === 1) {
|
||||
openargs.createFromResource = "1";
|
||||
}
|
||||
if (!!openargs.androidDatabaseImplementation && openargs.androidDatabaseImplementation === 2) {
|
||||
openargs.androidOldDatabaseImplementation = 1;
|
||||
}
|
||||
if (!!openargs.androidLockWorkaround && openargs.androidLockWorkaround === 1) {
|
||||
openargs.androidBugWorkaround = 1;
|
||||
}
|
||||
return new SQLitePlugin(openargs, okcb, errorcb);
|
||||
}),
|
||||
deleteDb: function(first, success, error) {
|
||||
var args, dblocation;
|
||||
args = {};
|
||||
if (first.constructor === String) {
|
||||
args.path = first;
|
||||
args.dblocation = dblocations[0];
|
||||
} else {
|
||||
if (!(first && first['name'])) {
|
||||
throw new Error("Please specify db name");
|
||||
}
|
||||
args.path = first.name;
|
||||
dblocation = !!first.location ? dblocations[first.location] : null;
|
||||
args.dblocation = dblocation || dblocations[0];
|
||||
}
|
||||
delete SQLitePlugin.prototype.openDBs[args.path];
|
||||
return cordova.exec(success, error, "SQLitePlugin", "delete", [args]);
|
||||
}
|
||||
};
|
||||
|
||||
root.sqlitePlugin = {
|
||||
sqliteFeatures: {
|
||||
isSQLitePlugin: true
|
||||
},
|
||||
openDatabase: SQLiteFactory.opendb,
|
||||
deleteDatabase: SQLiteFactory.deleteDb
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
Reference in New Issue
Block a user