3377 lines
184 KiB
JavaScript
3377 lines
184 KiB
JavaScript
/// <reference path="jquery-1.7.2.js" />
|
|
/// <reference path="indexeddb.shim.js" />
|
|
|
|
var linq2indexedDB;
|
|
var enableLogging = false;
|
|
|
|
// Initializes the linq2indexeddb object.
|
|
(function () {
|
|
"use strict";
|
|
|
|
linq2indexedDB = function (name, configuration, enableDebugging) {
|
|
/// <summary>Creates a new or opens an existing database for the given name</summary>
|
|
/// <param name="name" type="String">The name of the database</param>
|
|
/// <param name="configuration" type="Object">
|
|
/// [Optional] provide comment
|
|
/// </param>
|
|
/// <returns type="linq2indexedDB" />
|
|
|
|
var dbConfig = {
|
|
autoGenerateAllowed: true
|
|
};
|
|
|
|
if (name) {
|
|
dbConfig.name = name;
|
|
}
|
|
|
|
if (configuration) {
|
|
if (configuration.version) {
|
|
dbConfig.version = configuration.version;
|
|
}
|
|
// From the moment the configuration is provided by the developper, autoGeneration isn't allowed.
|
|
// If this would be allowed, the developper wouldn't be able to determine what to do for which version.
|
|
if (configuration.schema) {
|
|
var appVersion = dbConfig.version || -1;
|
|
for (key in configuration.schema) {
|
|
if (typeof key === "number") {
|
|
appVersion = version > key ? version : key;
|
|
}
|
|
}
|
|
if (version > -1) {
|
|
dbConfig.autoGenerateAllowed = false;
|
|
dbConfig.version = appVersion;
|
|
dbConfig.schema = configuration.schema;
|
|
}
|
|
}
|
|
if (configuration.definition) {
|
|
dbConfig.autoGenerateAllowed = false;
|
|
dbConfig.definition = configuration.definition;
|
|
}
|
|
if (configuration.onupgradeneeded) {
|
|
dbConfig.autoGenerateAllowed = false;
|
|
dbConfig.onupgradeneeded = configuration.onupgradeneeded;
|
|
}
|
|
if (configuration.oninitializeversion) {
|
|
dbConfig.autoGenerateAllowed = false;
|
|
dbConfig.oninitializeversion = configuration.oninitializeversion;
|
|
}
|
|
}
|
|
|
|
var returnObject = {
|
|
utilities: linq2indexedDB.prototype.utilities,
|
|
core: linq2indexedDB.prototype.core,
|
|
linq: linq(dbConfig),
|
|
initialize: function () {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Initialize Started");
|
|
return linq2indexedDB.prototype.utilities.promiseWrapper(function (pw) {
|
|
linq2indexedDB.prototype.core.db(dbConfig.name, dbConfig.version).then(function (args) /*db*/ {
|
|
var db = args[0];
|
|
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Close dbconnection");
|
|
db.close();
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Initialize Succesfull");
|
|
pw.complete();
|
|
}, pw.error, function (args) /*txn, e*/ {
|
|
var txn = args[0];
|
|
var e = args[1];
|
|
if (e.type == "upgradeneeded") {
|
|
upgradeDatabase(dbConfig, e.oldVersion, e.newVersion, txn);
|
|
}
|
|
});
|
|
});
|
|
},
|
|
deleteDatabase: function () {
|
|
return linq2indexedDB.prototype.utilities.promiseWrapper(function (pw) {
|
|
linq2indexedDB.prototype.core.deleteDb(dbConfig.name).then(function () {
|
|
pw.complete();
|
|
}, pw.error);
|
|
});
|
|
}
|
|
};
|
|
|
|
enableLogging = enableDebugging;
|
|
if (enableDebugging) {
|
|
returnObject.viewer = viewer(dbConfig);
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.warning, "Debugging enabled: be carefull when using in production enviroment. Complex objects get written to the log and may cause memory leaks.")
|
|
|
|
} else {
|
|
returnObject.viewer = null;
|
|
}
|
|
|
|
|
|
return returnObject;
|
|
};
|
|
|
|
function linq(dbConfig) {
|
|
|
|
var queryBuilderObj = function (objectStoreName) {
|
|
this.from = objectStoreName;
|
|
this.where = [];
|
|
this.select = [];
|
|
this.sortClauses = [];
|
|
this.get = [];
|
|
this.insert = [];
|
|
this.merge = [];
|
|
this.update = [];
|
|
this.remove = [];
|
|
this.clear = false;
|
|
};
|
|
|
|
queryBuilderObj.prototype = {
|
|
executeQuery: function () {
|
|
executeQuery(this);
|
|
}
|
|
};
|
|
|
|
function from(queryBuilder, objectStoreName) {
|
|
queryBuilder.from = objectStoreName;
|
|
return {
|
|
where: function (filter) {
|
|
/// <summary>Filters the selected data.</summary>
|
|
/// <param name="filter">
|
|
/// The filter argument can be a string (In this case the string represents the property name you want to filter on) or a function.
|
|
/// (In this case the function will be used to filter the data. This callback function is called with 1 parameter: data
|
|
/// ,this argument holds the data that has to be validated. The return type of the function must be a boolean.)
|
|
///</param>
|
|
return where(queryBuilder, filter, true, false);
|
|
},
|
|
orderBy: function (propertyName) {
|
|
/// <summary>Sorts the selected data ascending.</summary>
|
|
/// <param name="propertyName" type="String">The name of the property you want to sort on.</param>
|
|
return orderBy(queryBuilder, propertyName, false);
|
|
},
|
|
orderByDesc: function (propertyName) {
|
|
/// <summary>Sorts the selected data descending.</summary>
|
|
/// <param name="propertyName" type="String">The name of the property you want to sort on.</param>
|
|
return orderBy(queryBuilder, propertyName, true);
|
|
},
|
|
select: function (propertyNames) {
|
|
/// <summary>Selects the data.</summary>
|
|
/// <param name="propertyNames" type="Array">A list of the names of the properties you want to select.</param>
|
|
/// <returns type="Array">A list with the selected objects.</returns>
|
|
return select(queryBuilder, propertyNames);
|
|
},
|
|
insert: function (data, key) {
|
|
/// <summary>inserts data.</summary>
|
|
/// <param name="data" type="Object">The object you want to insert.</param>
|
|
/// <param name="key" type="Object">
|
|
/// [Optional] The key of the data you want to insert.
|
|
/// </param>
|
|
/// <returns type="Object">The object that was inserted.</returns>
|
|
return insert(queryBuilder, data, key);
|
|
},
|
|
update: function (data, key) {
|
|
/// <summary>updates data.</summary>
|
|
/// <param name="data" type="Object">The object you want to update.</param>
|
|
/// <param name="key" type="Object">
|
|
/// [Optional] The key of the data you want to update.
|
|
/// </param>
|
|
/// <returns type="Object">The object that was updated.</returns>
|
|
return update(queryBuilder, data, key);
|
|
},
|
|
merge: function (data, key) {
|
|
/// <summary>merges data.</summary>
|
|
/// <param name="data" type="Object">The data you want to merge.</param>
|
|
/// <param name="key" type="Object">
|
|
/// The key of the data you want to update.
|
|
/// </param>
|
|
/// <returns type="Object">The object that was updated.</returns>
|
|
return merge(queryBuilder, data, key);
|
|
},
|
|
remove: function (key) {
|
|
/// <summary>Removes data from the objectstore by his key.</summary>
|
|
/// <param name="key" type="Object">The key of the object you want to remove.</param>
|
|
return remove(queryBuilder, key);
|
|
},
|
|
clear: function () {
|
|
/// <summary>Removes all data from the objectstore.</summary>
|
|
return clear(queryBuilder);
|
|
},
|
|
get: function (key) {
|
|
/// <summary>Gets an object by his key.</summary>
|
|
/// <param name="key" type="Object">The key of the object you want to retrieve.</param>
|
|
/// <returns type="Object">The object that has the provided key.</returns>
|
|
return get(queryBuilder, key);
|
|
}
|
|
};
|
|
}
|
|
|
|
function where(queryBuilder, filter, isAndClause, isOrClause, isNotClause) {
|
|
var whereClauses = {};
|
|
var filterMetaData;
|
|
|
|
if (isNotClause === "undefined") {
|
|
whereClauses.not = function () {
|
|
return where(queryBuilder, filter, isAndClause, isOrClause, true);
|
|
};
|
|
}
|
|
|
|
if (typeof filter === "function") {
|
|
filterMetaData = {
|
|
propertyName: filter,
|
|
isOrClause: isOrClause,
|
|
isAndClause: isAndClause,
|
|
isNotClause: (isNotClause === "undefined" ? false : isNotClause),
|
|
filter: linq2indexedDB.prototype.linq.createFilter("anonymous" + queryBuilder.where.length, filter, null)
|
|
};
|
|
return whereClause(queryBuilder, filterMetaData);
|
|
} else if (typeof filter === "string") {
|
|
// Builds up the where filter methodes
|
|
for (var filterName in linq2indexedDB.prototype.linq.filters) {
|
|
filterMetaData = {
|
|
propertyName: filter,
|
|
isOrClause: isOrClause,
|
|
isAndClause: isAndClause,
|
|
isNotClause: (typeof isNotClause === "undefined" ? false : isNotClause),
|
|
filter: linq2indexedDB.prototype.linq.filters[filterName]
|
|
};
|
|
if (typeof linq2indexedDB.prototype.linq.filters[filterName].filter !== "function") {
|
|
throw "Linq2IndexedDB: a filter methods needs to be provided for the filter '" + filterName + "'";
|
|
}
|
|
if (typeof linq2indexedDB.prototype.linq.filters[filterName].name === "undefined") {
|
|
throw "Linq2IndexedDB: a filter name needs to be provided for the filter '" + filterName + "'";
|
|
}
|
|
|
|
whereClauses[linq2indexedDB.prototype.linq.filters[filterName].name] = linq2indexedDB.prototype.linq.filters[filterName].filter(whereClause, queryBuilder, filterMetaData);
|
|
}
|
|
}
|
|
return whereClauses;
|
|
}
|
|
|
|
function whereClause(queryBuilder, filterMetaData) {
|
|
queryBuilder.where.push(filterMetaData);
|
|
return {
|
|
and: function (filter) {
|
|
/// <summary>Adds an extra filter.</summary>
|
|
/// <param name="filter">
|
|
/// The filter argument can be a string (In this case the string represents the property name you want to filter on) or a function.
|
|
/// (In this case the function will be used to filter the data. This callback function is called with 1 parameter: data
|
|
/// ,this argument holds the data that has to be validated. The return type of the function must be a boolean.)
|
|
///</param>
|
|
return where(queryBuilder, filter, true, false);
|
|
},
|
|
or: function (filter) {
|
|
/// <summary>Adds an extra filter.</summary>
|
|
/// <param name="filter">
|
|
/// The filter argument can be a string (In this case the string represents the property name you want to filter on) or a function.
|
|
/// (In this case the function will be used to filter the data. This callback function is called with 1 parameter: data
|
|
/// ,this argument holds the data that has to be validated. The return type of the function must be a boolean.)
|
|
///</param>
|
|
return where(queryBuilder, filter, false, true);
|
|
},
|
|
orderBy: function (propertyName) {
|
|
/// <summary>Sorts the selected data ascending.</summary>
|
|
/// <param name="propertyName" type="String">The name of the property you want to sort on.</param>
|
|
return orderBy(queryBuilder, propertyName, false);
|
|
},
|
|
orderByDesc: function (propertyName) {
|
|
/// <summary>Sorts the selected data descending.</summary>
|
|
/// <param name="propertyName" type="String">The name of the property you want to sort on.</param>
|
|
return orderBy(queryBuilder, propertyName, true);
|
|
},
|
|
select: function (propertyNames) {
|
|
/// <summary>Selects the data.</summary>
|
|
/// <param name="propertyNames" type="Array">A list of the names of the properties you want to select.</param>
|
|
return select(queryBuilder, propertyNames);
|
|
},
|
|
remove: function () {
|
|
return remove(queryBuilder);
|
|
},
|
|
merge: function (data) {
|
|
return merge(queryBuilder, data);
|
|
}
|
|
};
|
|
}
|
|
|
|
function orderBy(queryBuilder, propName, descending) {
|
|
queryBuilder.sortClauses.push({ propertyName: propName, descending: descending });
|
|
return {
|
|
orderBy: function (propertyName) {
|
|
/// <summary>Sorts the selected data ascending.</summary>
|
|
/// <param name="propertyName" type="String">The name of the property you want to sort on.</param>
|
|
return orderBy(queryBuilder, propertyName, false);
|
|
},
|
|
orderByDesc: function (propertyName) {
|
|
/// <summary>Sorts the selected data descending.</summary>
|
|
/// <param name="propertyName" type="String">The name of the property you want to sort on.</param>
|
|
return orderBy(queryBuilder, propertyName, true);
|
|
},
|
|
select: function (propertyNames) {
|
|
/// <summary>Selects the data.</summary>
|
|
/// <param name="propertyNames" type="Array">A list of the names of the properties you want to select.</param>
|
|
return select(queryBuilder, propertyNames);
|
|
}
|
|
};
|
|
}
|
|
|
|
function select(queryBuilder, propertyNames) {
|
|
if (propertyNames) {
|
|
if (!linq2indexedDB.prototype.utilities.isArray(propertyNames)) {
|
|
propertyNames = [propertyNames];
|
|
}
|
|
|
|
for (var i = 0; i < propertyNames.length; i++) {
|
|
queryBuilder.select.push(propertyNames[i]);
|
|
}
|
|
}
|
|
return linq2indexedDB.prototype.utilities.promiseWrapper(function (pw) {
|
|
var returnData = [];
|
|
executeQuery(queryBuilder, linq2indexedDB.prototype.core.transactionTypes.READ_WRITE, executeWhere).then(function () {
|
|
pw.complete(this, returnData);
|
|
},pw.error, function(args) {
|
|
var obj = selectData(args[0].data, queryBuilder.select);
|
|
returnData.push(obj);
|
|
pw.progress(this, obj /*[obj]*/);
|
|
});
|
|
});
|
|
}
|
|
|
|
function insert(queryBuilder, data, key) {
|
|
queryBuilder.insert.push({ data: data, key: key });
|
|
return executeQuery(queryBuilder, linq2indexedDB.prototype.core.transactionTypes.READ_WRITE, function (qb, pw, transaction) {
|
|
var objectStorePromis = linq2indexedDB.prototype.core.objectStore(transaction, qb.from);
|
|
if (linq2indexedDB.prototype.utilities.isArray(qb.insert[0].data) && !qb.insert[0].key) {
|
|
var returnData = [];
|
|
for (var i = 0; i < qb.insert[0].data.length; i++) {
|
|
linq2indexedDB.prototype.core.insert(objectStorePromis, qb.insert[0].data[i]).then(function (args /*storedData, storedkey*/) {
|
|
pw.progress(this, {object: args[0], key: args[1]}/*[storedData, storedkey]*/);
|
|
returnData.push({ object: args[0], key: args[1] });
|
|
if (returnData.length == qb.insert[0].data.length) {
|
|
pw.complete(this, returnData);
|
|
}
|
|
}, pw.error);
|
|
}
|
|
}
|
|
else {
|
|
linq2indexedDB.prototype.core.insert(objectStorePromis, qb.insert[0].data, qb.insert[0].key).then(function(args /*storedData, storedkey*/) {
|
|
pw.complete(this, {object: args[0], key: args[1]} /*[storedData, storedkey]*/);
|
|
}, pw.error);
|
|
}
|
|
});
|
|
}
|
|
|
|
function update(queryBuilder, data, key) {
|
|
queryBuilder.update.push({ data: data, key: key });
|
|
return executeQuery(queryBuilder, linq2indexedDB.prototype.core.transactionTypes.READ_WRITE, function (qb, pw, transaction) {
|
|
linq2indexedDB.prototype.core.update(linq2indexedDB.prototype.core.objectStore(transaction, qb.from), qb.update[0].data, qb.update[0].key).then(function (args /*storedData, storedkey*/) {
|
|
pw.complete(this, {object: args[0], key: args[1]} /*[storedData, storedkey]*/);
|
|
}, pw.error);
|
|
});
|
|
}
|
|
|
|
function merge(queryBuilder, data, key) {
|
|
queryBuilder.merge.push({ data: data, key: key });
|
|
if (key) {
|
|
return executeQuery(queryBuilder, linq2indexedDB.prototype.core.transactionTypes.READ_WRITE, function(qb, pw, transaction) {
|
|
var objectStore = linq2indexedDB.prototype.core.objectStore(transaction, qb.from);
|
|
var obj = null;
|
|
linq2indexedDB.prototype.core.cursor(objectStore, IDBKeyRange.only(qb.merge[0].key)).then(function() {
|
|
}, pw.error, function(args /*data*/) {
|
|
obj = args[0].data;
|
|
for (var prop in qb.merge[0].data) {
|
|
obj[prop] = qb.merge[0].data[prop];
|
|
}
|
|
|
|
args[0].update(obj);
|
|
pw.complete(this, obj);
|
|
}, pw.error);
|
|
});
|
|
}
|
|
else {
|
|
var returnData = [];
|
|
return linq2indexedDB.prototype.utilities.promiseWrapper(function (pw) {
|
|
executeQuery(queryBuilder, linq2indexedDB.prototype.core.transactionTypes.READ_WRITE, executeWhere).then(function (args) {
|
|
if (returnData.length > 0) {
|
|
pw.complete(this, returnData);
|
|
}
|
|
else {
|
|
executeQuery(queryBuilder, linq2indexedDB.prototype.core.transactionTypes.READ_WRITE, function (qb, promise, transaction) {
|
|
linq2indexedDB.prototype.core.objectStore(transaction, qb.from).then(function (objectStoreArgs) {
|
|
for (var i = 0; i < args.length; i++) {
|
|
var obj = args[i];
|
|
for (var prop in queryBuilder.merge[0].data) {
|
|
obj[prop] = queryBuilder.merge[0].data[prop];
|
|
}
|
|
linq2indexedDB.prototype.core.update(objectStoreArgs[1], obj).then(function (args1 /*data*/) {
|
|
pw.progress(this, args1[0] /*[data]*/);
|
|
returnData.push(args1[0]);
|
|
if (returnData.length == args.length) {
|
|
promise.complete(this, returnData);
|
|
}
|
|
}, promise.error);
|
|
}
|
|
}, promise.error);
|
|
}).then(pw.complete, pw.error, pw.progress);
|
|
}
|
|
}, null, function (args) {
|
|
if (args[0].update) {
|
|
var obj = args[0].data;
|
|
for (var prop in queryBuilder.merge[0].data) {
|
|
obj[prop] = queryBuilder.merge[0].data[prop];
|
|
}
|
|
|
|
args[0].update(obj);
|
|
pw.progress(this, obj);
|
|
returnData.push(obj);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
function remove(queryBuilder, key) {
|
|
if (key) {
|
|
queryBuilder.remove.push({ key: key });
|
|
return executeQuery(queryBuilder, linq2indexedDB.prototype.core.transactionTypes.READ_WRITE, function (qb, pw, transaction) {
|
|
linq2indexedDB.prototype.core.remove(linq2indexedDB.prototype.core.objectStore(transaction, qb.from), qb.remove[0].key).then(function () {
|
|
pw.complete(this, queryBuilder.remove[0].key /*[queryBuilder.remove[0].key]*/);
|
|
}, pw.error);
|
|
});
|
|
}
|
|
else {
|
|
var cursorDelete = false;
|
|
return linq2indexedDB.prototype.utilities.promiseWrapper(function(pw) {
|
|
executeQuery(queryBuilder, linq2indexedDB.prototype.core.transactionTypes.READ_WRITE, executeWhere).then(function (data) {
|
|
if (cursorDelete) {
|
|
pw.complete(this);
|
|
}
|
|
else {
|
|
executeQuery(queryBuilder, linq2indexedDB.prototype.core.transactionTypes.READ_WRITE, function (qb, promise, transaction) {
|
|
linq2indexedDB.prototype.core.objectStore(transaction, qb.from).then(function (objectStoreArgs) {
|
|
var itemsDeleted = 0;
|
|
for (var i = 0; i < data.length; i++) {
|
|
linq2indexedDB.prototype.core.remove(objectStoreArgs[1], linq2indexedDB.prototype.utilities.getPropertyValue(data[i], objectStoreArgs[1].keyPath)).then(function(args1 /*data*/) {
|
|
pw.progress(this, args1[0] /*[data]*/);
|
|
if (++itemsDeleted == data.length) {
|
|
promise.complete(this);
|
|
}
|
|
}, promise.error);
|
|
}
|
|
}, promise.error);
|
|
}).then(pw.complete, pw.error, pw.progress);
|
|
}
|
|
}, null, function(args) {
|
|
if (args[0].remove) {
|
|
args[0].remove();
|
|
pw.progress(this);
|
|
cursorDelete = true;
|
|
}
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
function clear(queryBuilder) {
|
|
queryBuilder.clear = true;
|
|
return executeQuery(queryBuilder, linq2indexedDB.prototype.core.transactionTypes.READ_WRITE, function (qb, pw, transaction) {
|
|
linq2indexedDB.prototype.core.clear(linq2indexedDB.prototype.core.objectStore(transaction, qb.from)).then(function () {
|
|
pw.complete(this);
|
|
}, pw.error);
|
|
});
|
|
}
|
|
|
|
function get(queryBuilder, key) {
|
|
queryBuilder.get.push({ key: key });
|
|
return executeQuery(queryBuilder, linq2indexedDB.prototype.core.transactionTypes.READ_ONLY, function (qb, pw, transaction) {
|
|
linq2indexedDB.prototype.core.get(linq2indexedDB.prototype.core.objectStore(transaction, qb.from), qb.get[0].key).then(function (args /*data*/) {
|
|
pw.complete(this, args[0] /*[data]*/);
|
|
}, pw.error);
|
|
});
|
|
}
|
|
|
|
function executeQuery(queryBuilder, transactionType, callBack) {
|
|
return linq2indexedDB.prototype.utilities.promiseWrapper(function (pw) {
|
|
// Create DB connection
|
|
linq2indexedDB.prototype.core.db(dbConfig.name, dbConfig.version).then(function (args /* [db, event] */) {
|
|
// Opening a transaction
|
|
linq2indexedDB.prototype.core.transaction(args[0], queryBuilder.from, transactionType, dbConfig.autoGenerateAllowed).then(function (transactionArgs /* [transaction] */) {
|
|
var txn = transactionArgs[0];
|
|
txn.db.close();
|
|
// call complete if it isn't called already
|
|
//pw.complete();
|
|
},
|
|
pw.error,
|
|
function (transactionArgs /* [transaction] */) {
|
|
callBack(queryBuilder, pw, transactionArgs[0]);
|
|
});
|
|
}
|
|
, pw.error
|
|
, function (args /*txn, e*/) {
|
|
var txn = args[0];
|
|
var e = args[1];
|
|
|
|
// Upgrading the database to the correct version
|
|
if (e.type == "upgradeneeded") {
|
|
upgradeDatabase(dbConfig, e.oldVersion, e.newVersion, txn);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
function executeWhere(queryBuilder, pw, transaction) {
|
|
linq2indexedDB.prototype.core.objectStore(transaction, queryBuilder.from).then(function (objArgs) {
|
|
try {
|
|
var objectStore = objArgs[1];
|
|
var whereClauses = queryBuilder.where || [];
|
|
var returnData = [];
|
|
var cursorPromise = determineCursor(objectStore, whereClauses);
|
|
|
|
cursorPromise.then(
|
|
function (args1 /*data*/) {
|
|
var data = args1[0];
|
|
|
|
linq2indexedDB.prototype.utilities.linq2indexedDBWorker(data, whereClauses, queryBuilder.sortClauses).then(function (d) {
|
|
// No need to notify again if it allready happend in the onProgress method of the cursor.
|
|
if (returnData.length == 0) {
|
|
for (var j = 0; j < d.length; j++) {
|
|
pw.progress(this, [d[j]] /*[obj]*/);
|
|
}
|
|
}
|
|
pw.complete(this, d /*[returnData]*/);
|
|
});
|
|
},
|
|
pw.error,
|
|
function (args1 /*data*/) {
|
|
|
|
// When there are no more where clauses to fulfill and the collection doesn't need to be sorted, the data can be returned.
|
|
// In the other case let the complete handle it.
|
|
if (whereClauses.length == 0 && queryBuilder.sortClauses.length == 0) {
|
|
returnData.push({ data: args1[0].data, key: args1[0].key });
|
|
pw.progress(this, args1 /*[obj]*/);
|
|
}
|
|
}
|
|
);
|
|
} catch (ex) {
|
|
// Handle errors like an invalid keyRange.
|
|
linq2indexedDB.prototype.core.abortTransaction(args[0]);
|
|
pw.error(this, [ex.message, ex]);
|
|
}
|
|
}, pw.error);
|
|
}
|
|
|
|
function determineCursor(objectStore, whereClauses) {
|
|
var cursorPromise;
|
|
|
|
// Checks if an indexeddb filter can be used
|
|
if (whereClauses.length > 0
|
|
&& !whereClauses[0].isNotClause
|
|
&& whereClauses[0].filter.indexeddbFilter
|
|
&& (whereClauses.length == 1 || (whereClauses.length > 1 && !whereClauses[1].isOrClause))) {
|
|
var source = objectStore;
|
|
var indexPossible = dbConfig.autoGenerateAllowed || objectStore.indexNames.contains(whereClauses[0].propertyName + linq2indexedDB.prototype.core.indexSuffix);
|
|
// Checks if we can use an index
|
|
if (whereClauses[0].propertyName != objectStore.keyPath && indexPossible) {
|
|
source = linq2indexedDB.prototype.core.index(objectStore, whereClauses[0].propertyName, dbConfig.autoGenerateAllowed);
|
|
}
|
|
// Checks if we can use indexeddb filter
|
|
if (whereClauses[0].propertyName == objectStore.keyPath
|
|
|| indexPossible) {
|
|
// Gets the where clause + removes it from the collection
|
|
var clause = whereClauses.shift();
|
|
switch (clause.filter) {
|
|
case linq2indexedDB.prototype.linq.filters.equals:
|
|
cursorPromise = linq2indexedDB.prototype.core.cursor(source, IDBKeyRange.only(clause.value));
|
|
break;
|
|
case linq2indexedDB.prototype.linq.filters.between:
|
|
cursorPromise = linq2indexedDB.prototype.core.cursor(source, IDBKeyRange.bound(clause.minValue, clause.maxValue, clause.minValueIncluded, clause.maxValueIncluded));
|
|
break;
|
|
case linq2indexedDB.prototype.linq.filters.greaterThan:
|
|
cursorPromise = linq2indexedDB.prototype.core.cursor(source, IDBKeyRange.lowerBound(clause.value, clause.valueIncluded));
|
|
break;
|
|
case linq2indexedDB.prototype.linq.filters.smallerThan:
|
|
cursorPromise = linq2indexedDB.prototype.core.cursor(source, IDBKeyRange.upperBound(clause.value, clause.valueIncluded));
|
|
break;
|
|
default:
|
|
cursorPromise = linq2indexedDB.prototype.core.cursor(source);
|
|
break;
|
|
}
|
|
} else {
|
|
// Get everything if the index can't be used
|
|
cursorPromise = linq2indexedDB.prototype.core.cursor(source);
|
|
}
|
|
} else {
|
|
// Get's everything, manually filter data
|
|
cursorPromise = linq2indexedDB.prototype.core.cursor(objectStore);
|
|
}
|
|
return cursorPromise;
|
|
}
|
|
|
|
function selectData(data, propertyNames) {
|
|
if (propertyNames && propertyNames.length > 0) {
|
|
if (!linq2indexedDB.prototype.utilities.isArray(propertyNames)) {
|
|
propertyNames = [propertyNames];
|
|
}
|
|
|
|
var obj = new Object();
|
|
for (var i = 0; i < propertyNames.length; i++) {
|
|
linq2indexedDB.prototype.utilities.setPropertyValue(obj, propertyNames[i], linq2indexedDB.prototype.utilities.getPropertyValue(data, propertyNames[i]));
|
|
}
|
|
return obj;
|
|
}
|
|
return data;
|
|
}
|
|
|
|
return {
|
|
from: function (objectStoreName) {
|
|
return from(new queryBuilderObj(objectStoreName), objectStoreName);
|
|
}
|
|
};
|
|
}
|
|
|
|
function viewer(dbConfig) {
|
|
var dbView = {};
|
|
var refresh = true;
|
|
|
|
function refreshInternal() {
|
|
if (refresh) {
|
|
refresh = false;
|
|
getDbInformation(dbView, dbConfig);
|
|
}
|
|
}
|
|
|
|
dbView.Configuration = {
|
|
name: dbConfig.name,
|
|
version: dbConfig.version,
|
|
autoGenerateAllowed: dbConfig.autoGenerateAllowed,
|
|
schema: dbConfig.schema,
|
|
definition: dbConfig.definition,
|
|
onupgradeneeded: dbConfig.onupgradeneeded,
|
|
oninitializeversion: dbConfig.oninitializeversion
|
|
};
|
|
|
|
dbView.refresh = function () {
|
|
refresh = true;
|
|
refreshInternal();
|
|
};
|
|
|
|
linq2indexedDB.prototype.core.dbStructureChanged.addListener(linq2indexedDB.prototype.core.databaseEvents.databaseUpgrade, function () {
|
|
refresh = true;
|
|
});
|
|
linq2indexedDB.prototype.core.dbStructureChanged.addListener(linq2indexedDB.prototype.core.databaseEvents.databaseOpened, function () {
|
|
refreshInternal();
|
|
});
|
|
linq2indexedDB.prototype.core.dbStructureChanged.addListener(linq2indexedDB.prototype.core.databaseEvents.databaseRemoved, function () {
|
|
dbView.name = null;
|
|
dbView.version = null;
|
|
dbView.ObjectStores = [];
|
|
});
|
|
linq2indexedDB.prototype.core.dbDataChanged.addListener([linq2indexedDB.prototype.core.dataEvents.dataInserted, linq2indexedDB.prototype.core.dataEvents.dataRemoved, linq2indexedDB.prototype.core.dataEvents.dataUpdated, linq2indexedDB.prototype.core.dataEvents.objectStoreCleared], function () {
|
|
dbView.refresh();
|
|
});
|
|
|
|
return dbView;
|
|
}
|
|
|
|
function getDbInformation(dbView, dbConfig) {
|
|
linq2indexedDB.prototype.core.db(dbConfig.name).then(function () {
|
|
var connection = arguments[0][0];
|
|
dbView.name = connection.name;
|
|
dbView.version = connection.version;
|
|
dbView.ObjectStores = [];
|
|
|
|
linq2indexedDB.prototype.core.dbStructureChanged.addListener(linq2indexedDB.prototype.core.databaseEvents.databaseBlocked, function () {
|
|
connection.close();
|
|
});
|
|
|
|
var objectStoreNames = [];
|
|
for (var k = 0; k < connection.objectStoreNames.length; k++) {
|
|
objectStoreNames.push(connection.objectStoreNames[k]);
|
|
}
|
|
|
|
if (objectStoreNames.length > 0) {
|
|
linq2indexedDB.prototype.core.transaction(connection, objectStoreNames, linq2indexedDB.prototype.core.transactionTypes.READ_ONLY, false).then(null, null, function () {
|
|
var transaction = arguments[0][0];
|
|
|
|
for (var i = 0; i < connection.objectStoreNames.length; i++) {
|
|
linq2indexedDB.prototype.core.objectStore(transaction, connection.objectStoreNames[i]).then(function () {
|
|
var objectStore = arguments[0][1];
|
|
var indexes = [];
|
|
var objectStoreData = [];
|
|
|
|
for (var j = 0; j < objectStore.indexNames.length; j++) {
|
|
linq2indexedDB.prototype.core.index(objectStore, objectStore.indexNames[j], false).then(function () {
|
|
var index = arguments[0][1];
|
|
var indexData = [];
|
|
|
|
linq2indexedDB.prototype.core.cursor(index).then(null, null, function () {
|
|
var data = arguments[0][0];
|
|
var key = arguments[0][1].primaryKey;
|
|
indexData.push({ key: key, data: data });
|
|
});
|
|
|
|
indexes.push({
|
|
name: index.name,
|
|
keyPath: index.keyPath,
|
|
multiEntry: index.multiEntry,
|
|
data: indexData
|
|
});
|
|
});
|
|
}
|
|
|
|
linq2indexedDB.prototype.core.cursor(objectStore).then(null, null, function () {
|
|
var data = arguments[0][0];
|
|
var key = arguments[0][1].primaryKey;
|
|
objectStoreData.push({ key: key, data: data });
|
|
});
|
|
|
|
dbView.ObjectStores.push({
|
|
name: objectStore.name,
|
|
keyPath: objectStore.keyPath,
|
|
autoIncrement: objectStore.autoIncrement,
|
|
indexes: indexes,
|
|
data: objectStoreData
|
|
});
|
|
});
|
|
}
|
|
});
|
|
}
|
|
}, null, function (args) {
|
|
if (args[1].type == "upgradeneeded") {
|
|
args[0].abort();
|
|
}
|
|
});
|
|
}
|
|
|
|
function getVersionDefinition(version, definitions) {
|
|
var result = null;
|
|
for (var i = 0; i < definitions.length; i++) {
|
|
if (parseInt(definitions[i].version) == parseInt(version)) {
|
|
result = definitions[i];
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function initializeVersion(txn, definition) {
|
|
try {
|
|
if (definition.objectStores) {
|
|
for (var i = 0; i < definition.objectStores.length; i++) {
|
|
var objectStoreDefinition = definition.objectStores[i];
|
|
if (objectStoreDefinition.remove) {
|
|
linq2indexedDB.prototype.core.deleteObjectStore(txn, objectStoreDefinition.name);
|
|
} else {
|
|
linq2indexedDB.prototype.core.createObjectStore(txn, objectStoreDefinition.name, objectStoreDefinition.objectStoreOptions);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (definition.indexes) {
|
|
for (var j = 0; j < definition.indexes.length; j++) {
|
|
var indexDefinition = definition.indexes[j];
|
|
if (indexDefinition.remove) {
|
|
linq2indexedDB.prototype.core.deleteIndex(linq2indexedDB.prototype.core.objectStore(txn, indexDefinition.objectStoreName), indexDefinition.propertyName);
|
|
} else {
|
|
linq2indexedDB.prototype.core.createIndex(linq2indexedDB.prototype.core.objectStore(txn, indexDefinition.objectStoreName), indexDefinition.propertyName, indexDefinition.indexOptions);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (definition.defaultData) {
|
|
for (var k = 0; k < definition.defaultData.length; k++) {
|
|
var defaultDataDefinition = definition.defaultData[k];
|
|
if (defaultDataDefinition.remove) {
|
|
linq2indexedDB.prototype.core.remove(linq2indexedDB.prototype.core.objectStore(txn, defaultDataDefinition.objectStoreName), defaultDataDefinition.key);
|
|
} else {
|
|
linq2indexedDB.prototype.core.insert(linq2indexedDB.prototype.core.objectStore(txn, defaultDataDefinition.objectStoreName), defaultDataDefinition.data, defaultDataDefinition.key);
|
|
}
|
|
}
|
|
}
|
|
} catch (ex) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.exception, "initialize version exception: ", ex);
|
|
linq2indexedDB.prototype.core.abortTransaction(txn);
|
|
}
|
|
}
|
|
|
|
function upgradeDatabase(dbConfig, oldVersion, newVersion, txn) {
|
|
if (dbConfig.onupgradeneeded) {
|
|
dbConfig.onupgradeneeded(txn, oldVersion, newVersion);
|
|
}
|
|
if (dbConfig.oninitializeversion || dbConfig.schema || dbConfig.definition) {
|
|
for (var version = oldVersion + 1; version <= newVersion; version++) {
|
|
if (dbConfig.schema) {
|
|
dbConfig.schema[version](txn);
|
|
}
|
|
if (dbConfig.definition) {
|
|
var versionDefinition = getVersionDefinition(version, dbConfig.definition);
|
|
if (versionDefinition) {
|
|
initializeVersion(txn, versionDefinition);
|
|
}
|
|
} else if (dbConfig.oninitializeversion) {
|
|
dbConfig.oninitializeversion(txn, version);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
})();
|
|
|
|
// Namespace linq2indexedDB.prototype.linq
|
|
(function () {
|
|
linq2indexedDB.prototype.linq = {
|
|
addFilter: function (name, isValid, filterCallback) {
|
|
if (typeof linq2indexedDB.prototype.linq.filters[name] !== 'undefined') {
|
|
throw "linq2IndexedDB: A filter with the name '" + name + "' already exists.";
|
|
}
|
|
|
|
linq2indexedDB.prototype.linq.filters[name] = linq2indexedDB.prototype.linq.createFilter(name, isValid, filterCallback);
|
|
},
|
|
createFilter: function (name, isValid, filterCallback) {
|
|
if (typeof name === 'undefined') {
|
|
throw "linq2IndexedDB: No name argument provided to the addFilter method.";
|
|
}
|
|
if (typeof name !== 'string') {
|
|
throw "linq2IndexedDB: The name argument provided to the addFilterObject method must be a string.";
|
|
}
|
|
if (typeof isValid === 'undefined') {
|
|
throw "linq2IndexedDB: No isValid argument provided to the addFilter method.";
|
|
}
|
|
if (typeof isValid !== 'function') {
|
|
throw "linq2IndexedDB: The isValid argument provided to the addFilterObject method must be a function.";
|
|
}
|
|
if (typeof filterCallback === 'undefined') {
|
|
throw "linq2IndexedDB: No filterCallback argument provided to the addFilter method.";
|
|
}
|
|
//if (typeof filterCallback !== 'function') {
|
|
// throw "linq2IndexedDB: The filterCallback argument provided to the addFilterObject method must be a function.";
|
|
//}
|
|
|
|
return {
|
|
name: name,
|
|
indexeddbFilter: false,
|
|
sortOrder: 99,
|
|
isValid: isValid,
|
|
filter: filterCallback
|
|
};
|
|
},
|
|
filters: {
|
|
equals: {
|
|
name: "equals",
|
|
indexeddbFilter: true,
|
|
sortOrder: 0,
|
|
isValid: function (data, filter) {
|
|
return linq2indexedDB.prototype.utilities.getPropertyValue(data, filter.propertyName) == filter.value;
|
|
},
|
|
filter: function (callback, queryBuilder, filterMetaData) {
|
|
/// <summary>Creates a function to retrieve values for the filter and adds the filter to the querybuilder.</summary>
|
|
/// <param name="callback" type="function">
|
|
/// Callback method so the query expression can be builded.
|
|
/// </param>
|
|
/// <param name="queryBuilder" type="Object">
|
|
/// The objects that builds up the query for the user.
|
|
/// </param>
|
|
/// <param name="filterMetaData" type="string">
|
|
/// The metadata for the filter.
|
|
/// </param>
|
|
/// <returns type="function">
|
|
/// returns a function to retrieve the necessary values for the filter
|
|
/// </returns>
|
|
return function (value) {
|
|
if (typeof (value) === "undefined") {
|
|
throw "linq2indexedDB: value needs to be provided to the equal clause";
|
|
}
|
|
filterMetaData.value = value;
|
|
|
|
return callback(queryBuilder, filterMetaData);
|
|
};
|
|
}
|
|
},
|
|
between: {
|
|
name: "between",
|
|
sortOrder: 1,
|
|
indexeddbFilter: true,
|
|
isValid: function (data, filter) {
|
|
var value = linq2indexedDB.prototype.utilities.getPropertyValue(data, filter.propertyName);
|
|
return (value > filter.minValue || (filter.minValueIncluded && value == filter.minValue))
|
|
&& (value < filter.maxValue || (filter.maxValueIncluded && value == filter.maxValue));
|
|
},
|
|
filter: function (callback, queryBuilder, filterMetaData) {
|
|
/// <summary>Creates a function to retrieve values for the filter and adds the filter to the querybuilder.</summary>
|
|
/// <param name="callback" type="function">
|
|
/// Callback method so the query expression can be builded.
|
|
/// </param>
|
|
/// <param name="queryBuilder" type="Object">
|
|
/// The objects that builds up the query for the user.
|
|
/// </param>
|
|
/// <param name="filterMetaData" type="string">
|
|
/// The metadata for the filter.
|
|
/// </param>
|
|
/// <returns type="function">
|
|
/// returns a function to retrieve the necessary values for the filter
|
|
/// </returns>
|
|
return function (minValue, maxValue, minValueIncluded, maxValueIncluded) {
|
|
var isMinValueIncluded = typeof (minValueIncluded) === undefined ? false : minValueIncluded;
|
|
var isMasValueIncluded = typeof (maxValueIncluded) === undefined ? false : maxValueIncluded;
|
|
if (typeof (minValue) === "undefined") {
|
|
throw "linq2indexedDB: minValue needs to be provided to the between clause";
|
|
}
|
|
if (typeof (maxValue) === "undefined") {
|
|
throw "linq2indexedDB: maxValue needs to be provided to the between clause";
|
|
}
|
|
|
|
filterMetaData.minValue = minValue;
|
|
filterMetaData.maxValue = maxValue;
|
|
filterMetaData.minValueIncluded = isMinValueIncluded;
|
|
filterMetaData.maxValueIncluded = isMasValueIncluded;
|
|
|
|
return callback(queryBuilder, filterMetaData);
|
|
};
|
|
}
|
|
},
|
|
greaterThan: {
|
|
name: "greaterThan",
|
|
sortOrder: 2,
|
|
indexeddbFilter: true,
|
|
isValid: function (data, filter) {
|
|
var value = linq2indexedDB.prototype.utilities.getPropertyValue(data, filter.propertyName);
|
|
return value > filter.value || (filter.valueIncluded && value == filter.value);
|
|
},
|
|
filter: function (callback, queryBuilder, filterMetaData) {
|
|
/// <summary>Creates a function to retrieve values for the filter and adds the filter to the querybuilder.</summary>
|
|
/// <param name="callback" type="function">
|
|
/// Callback method so the query expression can be builded.
|
|
/// </param>
|
|
/// <param name="queryBuilder" type="Object">
|
|
/// The objects that builds up the query for the user.
|
|
/// </param>
|
|
/// <param name="filterMetaData" type="string">
|
|
/// The metadata for the filter.
|
|
/// </param>
|
|
/// <returns type="function">
|
|
/// returns a function to retrieve the necessary values for the filter
|
|
/// </returns>
|
|
return function (value, valueIncluded) {
|
|
if (typeof (value) === "undefined") {
|
|
throw "linq2indexedDB: value needs to be provided to the greatherThan clause";
|
|
}
|
|
var isValueIncluded = typeof (valueIncluded) === undefined ? false : valueIncluded;
|
|
|
|
filterMetaData.value = value;
|
|
filterMetaData.valueIncluded = isValueIncluded;
|
|
|
|
return callback(queryBuilder, filterMetaData);
|
|
};
|
|
}
|
|
},
|
|
smallerThan: {
|
|
name: "smallerThan",
|
|
sortOrder: 2,
|
|
indexeddbFilter: true,
|
|
isValid: function (data, filter) {
|
|
var value = linq2indexedDB.prototype.utilities.getPropertyValue(data, filter.propertyName);
|
|
return value < filter.value || (filter.valueIncluded && value == filter.value);
|
|
},
|
|
filter: function (callback, queryBuilder, filterMetaData) {
|
|
/// <summary>Creates a function to retrieve values for the filter and adds the filter to the querybuilder.</summary>
|
|
/// <param name="callback" type="function">
|
|
/// Callback method so the query expression can be builded.
|
|
/// </param>
|
|
/// <param name="queryBuilder" type="Object">
|
|
/// The objects that builds up the query for the user.
|
|
/// </param>
|
|
/// <param name="filterMetaData" type="string">
|
|
/// The metadata for the filter.
|
|
/// </param>
|
|
/// <returns type="function">
|
|
/// returns a function to retrieve the necessary values for the filter
|
|
/// </returns>
|
|
return function (value, valueIncluded) {
|
|
if (typeof (value) === "undefined") {
|
|
throw "linq2indexedDB: value needs to be provided to the smallerThan clause";
|
|
}
|
|
var isValueIncluded = typeof (valueIncluded) === undefined ? false : valueIncluded;
|
|
|
|
filterMetaData.value = value;
|
|
filterMetaData.valueIncluded = isValueIncluded;
|
|
|
|
return callback(queryBuilder, filterMetaData);
|
|
};
|
|
}
|
|
},
|
|
inArray: {
|
|
name: "inArray",
|
|
sortOrder: 3,
|
|
indexeddbFilter: false,
|
|
isValid: function (data, filter) {
|
|
var value = linq2indexedDB.prototype.utilities.getPropertyValue(data, filter.propertyName);
|
|
if (value) {
|
|
return filter.value.indexOf(value) >= 0;
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
},
|
|
filter: function (callback, queryBuilder, filterMetaData) {
|
|
/// <summary>Creates a function to retrieve values for the filter and adds the filter to the querybuilder.</summary>
|
|
/// <param name="callback" type="function">
|
|
/// Callback method so the query expression can be builded.
|
|
/// </param>
|
|
/// <param name="queryBuilder" type="Object">
|
|
/// The objects that builds up the query for the user.
|
|
/// </param>
|
|
/// <param name="filterMetaData" type="string">
|
|
/// The metadata for the filter.
|
|
/// </param>
|
|
/// <returns type="function">
|
|
/// returns a function to retrieve the necessary values for the filter
|
|
/// </returns>
|
|
return function (array) {
|
|
if (typeof (array) === "undefined" || typeof array !== "Array") {
|
|
throw "linq2indexedDB: array needs to be provided to the inArray clause";
|
|
}
|
|
|
|
filterMetaData.value = array;
|
|
|
|
return callback(queryBuilder, filterMetaData);
|
|
};
|
|
}
|
|
},
|
|
like: {
|
|
name: "like",
|
|
sortOrder: 4,
|
|
indexeddbFilter: false,
|
|
isValid: function (data, filter) {
|
|
var value = linq2indexedDB.prototype.utilities.getPropertyValue(data, filter.propertyName);
|
|
if (value) {
|
|
return value.indexOf(filter.value) >= 0;
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
},
|
|
filter: function (callback, queryBuilder, filterMetaData) {
|
|
/// <summary>Creates a function to retrieve values for the filter and adds the filter to the querybuilder.</summary>
|
|
/// <param name="callback" type="function">
|
|
/// Callback method so the query expression can be builded.
|
|
/// </param>
|
|
/// <param name="queryBuilder" type="Object">
|
|
/// The objects that builds up the query for the user.
|
|
/// </param>
|
|
/// <param name="filterMetaData" type="string">
|
|
/// The metadata for the filter.
|
|
/// </param>
|
|
/// <returns type="function">
|
|
/// returns a function to retrieve the necessary values for the filter
|
|
/// </returns>
|
|
return function (value) {
|
|
if (typeof (value) === "undefined") {
|
|
throw "linq2indexedDB: value needs to be provided to the like clause";
|
|
}
|
|
|
|
filterMetaData.value = value;
|
|
|
|
return callback(queryBuilder, filterMetaData);
|
|
};
|
|
}
|
|
},
|
|
isUndefined: {
|
|
name: "isUndefined",
|
|
sortOrder: 5,
|
|
indexeddbFilter: false,
|
|
isValid: function (data, filter) {
|
|
return linq2indexedDB.prototype.utilities.getPropertyValue(data, filter.propertyName) === undefined;
|
|
},
|
|
filter: function (callback, queryBuilder, filterMetaData) {
|
|
/// <summary>Creates a function to retrieve values for the filter and adds the filter to the querybuilder.</summary>
|
|
/// <param name="callback" type="function">
|
|
/// Callback method so the query expression can be builded.
|
|
/// </param>
|
|
/// <param name="queryBuilder" type="Object">
|
|
/// The objects that builds up the query for the user.
|
|
/// </param>
|
|
/// <param name="filterMetaData" type="string">
|
|
/// The metadata for the filter.
|
|
/// </param>
|
|
/// <returns type="function">
|
|
/// returns a function to retrieve the necessary values for the filter
|
|
/// </returns>
|
|
return function () {
|
|
return callback(queryBuilder, filterMetaData);
|
|
};
|
|
}
|
|
}
|
|
}
|
|
};
|
|
})();
|
|
|
|
// Namespace linq2indexedDB.prototype.utitlities
|
|
(function (isMetroApp) {
|
|
"use strict";
|
|
|
|
var utilities = {
|
|
linq2indexedDBWorkerFileLocation: "/Scripts/Linq2IndexedDB.js",
|
|
linq2indexedDBWorker: function (data, filters, sortClauses) {
|
|
return utilities.promiseWrapper(function (pw) {
|
|
if (!!window.Worker) {
|
|
var worker = new Worker(utilities.linq2indexedDBWorkerFileLocation);
|
|
worker.onmessage = function (event) {
|
|
pw.complete(this, event.data);
|
|
worker.terminate();
|
|
};
|
|
worker.onerror = pw.error;
|
|
|
|
var filtersString = JSON.stringify(filters, linq2indexedDB.prototype.utilities.serialize);
|
|
|
|
worker.postMessage({ data: data, filters: filtersString, sortClauses: sortClauses });
|
|
} else {
|
|
// Fallback when there are no webworkers present. Beware, this runs on the UI thread and can block the UI
|
|
pw.complete(this, utilities.filterSort(data, filters, sortClauses));
|
|
}
|
|
});
|
|
},
|
|
isArray: function (array) {
|
|
if (array instanceof Array) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
},
|
|
JSONComparer: function (propertyName, descending) {
|
|
return {
|
|
sort: function (valueX, valueY) {
|
|
if (descending) {
|
|
return ((valueX[propertyName] == valueY[propertyName]) ? 0 : ((valueX[propertyName] > valueY[propertyName]) ? -1 : 1));
|
|
} else {
|
|
return ((valueX[propertyName] == valueY[propertyName]) ? 0 : ((valueX[propertyName] > valueY[propertyName]) ? 1 : -1));
|
|
}
|
|
}
|
|
};
|
|
},
|
|
promiseWrapper: function (promise, arg1, arg2, arg3, arg4, arg5) {
|
|
if (isMetroApp) {
|
|
return new WinJS.Promise(function (completed, error, progress) {
|
|
promise({
|
|
complete: function (context, args) {
|
|
completed(args);
|
|
},
|
|
error: function (context, args) {
|
|
error(args);
|
|
},
|
|
progress: function (context, args) {
|
|
progress(args);
|
|
}
|
|
}, arg1, arg2, arg3, arg4, arg5);
|
|
});
|
|
} else if (typeof ($) === "function" && $.Deferred) {
|
|
return $.Deferred(function (dfd) {
|
|
promise({
|
|
complete: function (context, args) {
|
|
dfd.resolveWith(context, [args]);
|
|
},
|
|
error: function (context, args) {
|
|
dfd.rejectWith(context, [args]);
|
|
},
|
|
progress: function (context, args) {
|
|
dfd.notifyWith(context, [args]);
|
|
}
|
|
}, arg1, arg2, arg3, arg4, arg5);
|
|
}).promise();
|
|
} else {
|
|
throw "linq2indexedDB: No framework (WinJS or jQuery) that supports promises found. Please ensure jQuery or WinJS is referenced before the linq2indexedDB.js file.";
|
|
}
|
|
},
|
|
log: function () {
|
|
if ((window && typeof (window.console) === "undefined") || !enableLogging) {
|
|
return false;
|
|
}
|
|
|
|
var currtime = (function currentTime() {
|
|
var time = new Date();
|
|
return time.getHours() + ':' + time.getMinutes() + ':' + time.getSeconds() + '.' + time.getMilliseconds();
|
|
})();
|
|
|
|
var args = [];
|
|
var severity = arguments[0];
|
|
|
|
args.push(currtime + ' Linq2IndexedDB: ');
|
|
|
|
for (var i = 1; i < arguments.length; i++) {
|
|
args.push(arguments[i]);
|
|
}
|
|
|
|
switch (severity) {
|
|
case linq2indexedDB.prototype.utilities.severity.exception:
|
|
if (window.console.exception) {
|
|
window.console.exception.apply(console, args);
|
|
} else {
|
|
window.console.error.apply(console, args);
|
|
}
|
|
break;
|
|
case linq2indexedDB.prototype.utilities.severity.error:
|
|
window.console.error.apply(console, args);
|
|
break;
|
|
case linq2indexedDB.prototype.utilities.severity.warning:
|
|
window.console.warning.apply(console, args);
|
|
break;
|
|
case linq2indexedDB.prototype.utilities.severity.information:
|
|
window.console.log.apply(console, args);
|
|
break;
|
|
default:
|
|
window.console.log.apply(console, args);
|
|
}
|
|
|
|
return true;
|
|
},
|
|
logError: function (error) {
|
|
return linq2indexedDB.prototype.utilities.log(error.severity, error.message, error.type, error.method, error.orignialError);
|
|
},
|
|
filterSort: function (data, filters, sortClauses) {
|
|
var returnData = [];
|
|
|
|
for (var i = 0; i < data.length; i++) {
|
|
if (utilities.isDataValid(data[i].data, filters)) {
|
|
returnData = utilities.addToSortedArray(returnData, data[i], sortClauses);
|
|
}
|
|
}
|
|
|
|
return returnData;
|
|
},
|
|
isDataValid: function (data, filters) {
|
|
var isValid = true;
|
|
|
|
for (var i = 0; i < filters.length; i++) {
|
|
var filterValid = filters[i].filter.isValid(data, filters[i]);
|
|
if (filters[i].isNotClause) {
|
|
filterValid = !filterValid;
|
|
}
|
|
if (filters[i].isAndClause) {
|
|
isValid = isValid && filterValid;
|
|
} else if (filters[i].isOrClause) {
|
|
isValid = isValid || filterValid;
|
|
}
|
|
}
|
|
return isValid;
|
|
},
|
|
addToSortedArray: function (array, data, sortClauses) {
|
|
var newArray = [];
|
|
if (array.length == 0 || sortClauses.length == 0) {
|
|
newArray = array;
|
|
newArray.push(data);
|
|
} else {
|
|
var valueAdded = false;
|
|
for (var i = 0; i < array.length; i++) {
|
|
var valueX = array[i].data;
|
|
var valueY = data.data;
|
|
for (var j = 0; j < sortClauses.length; j++) {
|
|
var sortPropvalueX = linq2indexedDB.prototype.utilities.getPropertyValue(valueX, sortClauses[j].propertyName);
|
|
var sortPropvalueY = linq2indexedDB.prototype.utilities.getPropertyValue(valueY, sortClauses[j].propertyName);
|
|
|
|
if (sortPropvalueX != sortPropvalueY) {
|
|
if ((sortClauses[j].descending && sortPropvalueX > sortPropvalueY)
|
|
|| (!sortClauses[j].descending && sortPropvalueX < sortPropvalueY)) {
|
|
newArray.push(array[i]);
|
|
} else {
|
|
if (!valueAdded) {
|
|
valueAdded = true;
|
|
newArray.push(data);
|
|
}
|
|
newArray.push(array[i]);
|
|
}
|
|
}
|
|
else if (j == (sortClauses.length - 1)) {
|
|
newArray.push(array[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add at the end
|
|
if (!valueAdded) {
|
|
newArray.push(data);
|
|
}
|
|
}
|
|
return newArray;
|
|
},
|
|
serialize: function (key, value) {
|
|
if (typeof value === 'function') {
|
|
return value.toString();
|
|
}
|
|
return value;
|
|
},
|
|
deserialize: function (key, value) {
|
|
if (value && typeof value === "string" && value.substr(0, 8) == "function") {
|
|
var startBody = value.indexOf('{') + 1;
|
|
var endBody = value.lastIndexOf('}');
|
|
var startArgs = value.indexOf('(') + 1;
|
|
var endArgs = value.indexOf(')');
|
|
|
|
return new Function(value.substring(startArgs, endArgs), value.substring(startBody, endBody));
|
|
}
|
|
return value;
|
|
},
|
|
getPropertyValue: function (data, propertyName) {
|
|
var structure = propertyName.split(".");
|
|
var value = data;
|
|
for (var i = 0; i < structure.length; i++) {
|
|
if (value) {
|
|
value = value[structure[i]];
|
|
}
|
|
}
|
|
return value;
|
|
},
|
|
setPropertyValue: function (data, propertyName, value) {
|
|
var structure = propertyName.split(".");
|
|
var obj = data;
|
|
for (var i = 0; i < structure.length; i++) {
|
|
if (i != (structure.length - 1)) {
|
|
obj[structure[i]] = {};
|
|
obj = obj[structure[i]];
|
|
}
|
|
else {
|
|
obj[structure[i]] = value;
|
|
}
|
|
}
|
|
return obj;
|
|
},
|
|
severity: {
|
|
information: 0,
|
|
warning: 1,
|
|
error: 2,
|
|
exception: 3
|
|
}
|
|
};
|
|
|
|
linq2indexedDB.prototype.utilities = utilities;
|
|
})(typeof Windows !== "undefined");
|
|
|
|
if (typeof window !== "undefined") {
|
|
// UI Thread
|
|
|
|
// Namespace linq2indexedDB.prototype.core
|
|
(function (window, isMetroApp) {
|
|
"use strict";
|
|
|
|
// Region variables
|
|
var defaultDatabaseName = "Default";
|
|
var implementations = {
|
|
NONE: 0,
|
|
NATIVE: 1,
|
|
MICROSOFT: 2,
|
|
MOZILLA: 3,
|
|
GOOGLE: 4,
|
|
MICROSOFTPROTOTYPE: 5,
|
|
SHIM: 6
|
|
};
|
|
var transactionTypes = {
|
|
READ_ONLY: "readonly",
|
|
READ_WRITE: "readwrite",
|
|
VERSION_CHANGE: "versionchange"
|
|
};
|
|
var implementation = initializeIndexedDb();
|
|
var handlers = {
|
|
IDBRequest: function (request) {
|
|
return deferredHandler(IDBRequestHandler, request);
|
|
},
|
|
IDBBlockedRequest: function (request) {
|
|
return deferredHandler(IDBBlockedRequestHandler, request);
|
|
},
|
|
IDBOpenDBRequest: function (request) {
|
|
return deferredHandler(IDBOpenDbRequestHandler, request);
|
|
},
|
|
IDBDatabase: function (database) {
|
|
return deferredHandler(IDBDatabaseHandler, database);
|
|
},
|
|
IDBTransaction: function (txn) {
|
|
return deferredHandler(IDBTransactionHandler, txn);
|
|
},
|
|
IDBCursorRequest: function (request) {
|
|
return deferredHandler(IDBCursorRequestHandler, request);
|
|
}
|
|
};
|
|
|
|
//Copyright (c) 2010 Nicholas C. Zakas. All rights reserved.
|
|
//MIT License
|
|
|
|
function eventTarget() {
|
|
this._listeners = {};
|
|
}
|
|
|
|
eventTarget.prototype = {
|
|
constructor: eventTarget,
|
|
|
|
addListener: function (type, listener) {
|
|
if (!linq2indexedDB.prototype.utilities.isArray(type)) {
|
|
type = [type];
|
|
}
|
|
|
|
for (var i = 0; i < type.length; i++) {
|
|
if (typeof this._listeners[type[i]] == "undefined") {
|
|
this._listeners[type[i]] = [];
|
|
}
|
|
|
|
this._listeners[type[i]].push(listener);
|
|
}
|
|
},
|
|
|
|
fire: function (event) {
|
|
if (typeof event == "string") {
|
|
event = { type: event };
|
|
}
|
|
if (!event.target) {
|
|
event.target = this;
|
|
}
|
|
|
|
if (!event.type) { //falsy
|
|
throw new Error("Event object missing 'type' property.");
|
|
}
|
|
|
|
if (this._listeners[event.type] instanceof Array) {
|
|
var listeners = this._listeners[event.type];
|
|
for (var i = 0, len = listeners.length; i < len; i++) {
|
|
listeners[i].call(this, event);
|
|
}
|
|
}
|
|
},
|
|
|
|
removeListener: function (type, listener) {
|
|
if (!linq2indexedDB.prototype.utilities.isArray(type)) {
|
|
type = [type];
|
|
}
|
|
|
|
for (var j = 0; j < type[j].length; j++) {
|
|
if (this._listeners[type[j]] instanceof Array) {
|
|
var listeners = this._listeners[type[j]];
|
|
for (var i = 0, len = listeners.length; i < len; i++) {
|
|
if (listeners[i] === listener) {
|
|
listeners.splice(i, 1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
// End copyright
|
|
|
|
var dbEvents = {
|
|
objectStoreCreated: "Object store created",
|
|
objectStoreRemoved: "Object store removed",
|
|
indexCreated: "Index created",
|
|
indexRemoved: "Index removed",
|
|
databaseRemoved: "Database removed",
|
|
databaseBlocked: "Database blocked",
|
|
databaseUpgrade: "Database upgrade",
|
|
databaseOpened: "Database opened"
|
|
};
|
|
|
|
var dataEvents = {
|
|
dataInserted: "Data inserted",
|
|
dataUpdated: "Data updated",
|
|
dataRemoved: "Data removed",
|
|
objectStoreCleared: "Object store cleared"
|
|
};
|
|
|
|
var upgradingDatabase = false;
|
|
|
|
var internal = {
|
|
db: function (pw, name, version) {
|
|
var req;
|
|
try {
|
|
// Initializing defaults
|
|
name = name ? name : defaultDatabaseName;
|
|
|
|
// Creating a new database conection
|
|
if (version) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "db opening", name, version);
|
|
req = window.indexedDB.open(name, version);
|
|
} else {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "db opening", name);
|
|
req = window.indexedDB.open(name);
|
|
}
|
|
|
|
// Handle the events of the creation of the database connection
|
|
handlers.IDBOpenDBRequest(req).then(
|
|
function (args /*db, e*/) {
|
|
var db = args[0];
|
|
var e = args[1];
|
|
// Database connection established
|
|
|
|
// Handle the events on the database.
|
|
handlers.IDBDatabase(db).then(
|
|
function (/*result, event*/) {
|
|
// No done present.
|
|
},
|
|
function (args1/*error, event*/) {
|
|
// Database error or abort
|
|
linq2indexedDB.prototype.core.closeDatabaseConnection(args1[1].target);
|
|
// When an error occures the result will already be resolved. This way calling the reject won't case a thing
|
|
},
|
|
function (args1 /*result, event*/) {
|
|
var event = args1[1];
|
|
if (event) {
|
|
// Sending a notify won't have any effect because the result is already resolved. There is nothing more to do than close the current connection.
|
|
if (event.type === "versionchange") {
|
|
if (event.version != event.target.db.version) {
|
|
// If the version is changed and the current version is different from the requested version, the connection needs to get closed.
|
|
linq2indexedDB.prototype.core.closeDatabaseConnection(event.target);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
var currentVersion = internal.getDatabaseVersion(db);
|
|
if (currentVersion < version || (version == -1) || currentVersion == "") {
|
|
// Current version deferres from the requested version, database upgrade needed
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "DB Promise upgradeneeded", this, db, e, db.connectionId);
|
|
internal.changeDatabaseStructure(db, version || 1).then(
|
|
function (args1 /*txn, event*/) {
|
|
var txn = args1[0];
|
|
var event = args1[1];
|
|
|
|
// Fake the onupgrade event.
|
|
var context = txn.db;
|
|
context.transaction = txn;
|
|
|
|
var upgardeEvent = {};
|
|
upgardeEvent.type = "upgradeneeded";
|
|
upgardeEvent.newVersion = version;
|
|
upgardeEvent.oldVersion = currentVersion;
|
|
upgardeEvent.originalEvent = event;
|
|
|
|
linq2indexedDB.prototype.core.dbStructureChanged.fire({ type: dbEvents.databaseUpgrade, data: upgardeEvent });
|
|
pw.progress(context, [txn, upgardeEvent]);
|
|
|
|
handlers.IDBTransaction(txn).then(function (/*trans, args*/) {
|
|
// When completed return the db + event of the original request.
|
|
pw.complete(this, args);
|
|
},
|
|
function (args2 /*err, ev*/) {
|
|
//txn error or abort
|
|
pw.error(this, args2);
|
|
});
|
|
},
|
|
function (args1 /*err, event*/) {
|
|
// txn error or abort
|
|
pw.error(this, args1);
|
|
},
|
|
function (args1 /*result, event*/) {
|
|
// txn blocked
|
|
linq2indexedDB.prototype.core.dbStructureChanged.fire({ type: dbEvents.databaseBlocked, data: args1 });
|
|
pw.progress(this, args1);
|
|
});
|
|
} else if (version && version < currentVersion) {
|
|
linq2indexedDB.prototype.core.closeDatabaseConnection(db);
|
|
var err = {
|
|
severity: linq2indexedDB.prototype.utilities.severity.error,
|
|
type: "VersionError",
|
|
message: "You are trying to open the database in a lower version (" + version + ") than the current version of the database",
|
|
method: "db"
|
|
};
|
|
linq2indexedDB.prototype.utilities.logError(err);
|
|
pw.error(this, err);
|
|
}
|
|
else {
|
|
// Database Connection resolved.
|
|
linq2indexedDB.prototype.core.dbStructureChanged.fire({ type: dbEvents.databaseOpened, data: db });
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "DB Promise resolved", db, e);
|
|
pw.complete(this, [db, e]);
|
|
}
|
|
},
|
|
function (args /*error, e*/) {
|
|
// Database connection error or abort
|
|
var err = internal.wrapError(args[1], "db");
|
|
|
|
// Fix for firefox & chrome
|
|
if (args[1].target && args[1].target.errorCode == 12) {
|
|
err.type = "VersionError";
|
|
}
|
|
|
|
if (err.type == "VersionError") {
|
|
err.message = "You are trying to open the database in a lower version (" + version + ") than the current version of the database";
|
|
}
|
|
|
|
// Fix for firefox & chrome
|
|
if (args[1].target && args[1].target.errorCode == 8) {
|
|
err.type = "AbortError";
|
|
}
|
|
|
|
if (err.type == "AbortError") {
|
|
err.message = "The VERSION_CHANGE transaction was aborted.";
|
|
}
|
|
// For old firefox implementations
|
|
linq2indexedDB.prototype.utilities.logError(err);
|
|
pw.error(this, err);
|
|
},
|
|
function (args /*result, e*/) {
|
|
// Database upgrade + db blocked
|
|
if (args[1].type == "blocked") {
|
|
linq2indexedDB.prototype.core.dbStructureChanged.fire({ type: dbEvents.databaseBlocked, data: args });
|
|
} else if (args[1].type == "upgradeneeded") {
|
|
linq2indexedDB.prototype.core.dbStructureChanged.fire({ type: dbEvents.databaseUpgrade, data: args });
|
|
}
|
|
pw.progress(this, args);
|
|
}
|
|
);
|
|
} catch (ex) {
|
|
var error = internal.wrapException(ex, "db");
|
|
if ((ex.INVALID_ACCESS_ERR && ex.code == ex.INVALID_ACCESS_ERR) || ex.name == "InvalidAccessError") {
|
|
error.type = "InvalidAccessError";
|
|
error.message = "You are trying to open a database with a negative version number.";
|
|
}
|
|
linq2indexedDB.prototype.utilities.logError(error);
|
|
pw.error(this, error);
|
|
}
|
|
},
|
|
transaction: function (pw, db, objectStoreNames, transactionType, autoGenerateAllowed) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Transaction promise started", db, objectStoreNames, transactionType);
|
|
|
|
// Initialize defaults
|
|
if (!linq2indexedDB.prototype.utilities.isArray(objectStoreNames)) objectStoreNames = [objectStoreNames];
|
|
transactionType = transactionType || linq2indexedDB.prototype.core.transactionTypes.READ_ONLY;
|
|
|
|
var nonExistingObjectStores = [];
|
|
|
|
try {
|
|
// Check for non-existing object stores
|
|
for (var i = 0; i < objectStoreNames.length; i++) {
|
|
if (!db.objectStoreNames || !db.objectStoreNames.contains(objectStoreNames[i])) {
|
|
nonExistingObjectStores.push(objectStoreNames[i]);
|
|
}
|
|
}
|
|
|
|
// When non-existing object stores are found and the autoGenerateAllowed is true.
|
|
// Then create these object stores
|
|
if (nonExistingObjectStores.length > 0 && autoGenerateAllowed) {
|
|
// setTimeout is necessary when multiple request to generate an index come together.
|
|
// This can result in a deadlock situation, there for the setTimeout
|
|
setTimeout(function() {
|
|
upgradingDatabase = true;
|
|
var version = internal.getDatabaseVersion(db) + 1;
|
|
var dbName = db.name;
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Transaction database upgrade needed: ", db);
|
|
// Closing the current connections so it won't block the upgrade.
|
|
linq2indexedDB.prototype.core.closeDatabaseConnection(db);
|
|
// Open a new connection with the new version
|
|
linq2indexedDB.prototype.core.db(dbName, version).then(function (args /*dbConnection, event*/) {
|
|
upgradingDatabase = false;
|
|
// Necessary for getting it work in WIN 8, WinJS promises have troubles with nesting promises
|
|
var txn = args[0].transaction(objectStoreNames, transactionType);
|
|
|
|
// Handle transaction events
|
|
handlers.IDBTransaction(txn).then(function(args1 /*result, event*/) {
|
|
// txn completed
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Transaction completed.", txn);
|
|
pw.complete(this, args1);
|
|
},
|
|
function(args1 /*err, event*/) {
|
|
// txn error or abort
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.error, "Transaction error/abort.", args1);
|
|
pw.error(this, args1);
|
|
});
|
|
|
|
// txn created
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Transaction created.", txn);
|
|
pw.progress(txn, [txn]);
|
|
},
|
|
function(args /*error, event*/) {
|
|
// When an error occures, bubble up.
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.error, "Transaction error.", args);
|
|
pw.error(this, args);
|
|
},
|
|
function(args /*txn, event*/) {
|
|
var event = args[1];
|
|
|
|
// When an upgradeneeded event is thrown, create the non-existing object stores
|
|
if (event.type == "upgradeneeded") {
|
|
for (var j = 0; j < nonExistingObjectStores.length; j++) {
|
|
linq2indexedDB.prototype.core.createObjectStore(args[0], nonExistingObjectStores[j], { keyPath: "Id", autoIncrement: true });
|
|
}
|
|
}
|
|
});
|
|
}, upgradingDatabase ? 10 : 1);
|
|
} else {
|
|
// If no non-existing object stores are found, create the transaction.
|
|
var transaction = db.transaction(objectStoreNames, transactionType);
|
|
|
|
// Handle transaction events
|
|
handlers.IDBTransaction(transaction).then(function(args /*result, event*/) {
|
|
// txn completed
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Transaction completed.", args);
|
|
pw.complete(this, args);
|
|
},
|
|
function (args /*err, event*/) {
|
|
var err = internal.wrapError(args[1], "transaction");
|
|
if (args[1].type == "abort") {
|
|
err.type = "abort";
|
|
err.severity = "abort";
|
|
err.message = "Transaction was aborted";
|
|
}
|
|
|
|
// Fix for firefox & chrome
|
|
if (args[1].target && args[1].target.errorCode == 4) {
|
|
err.type = "ConstraintError";
|
|
}
|
|
|
|
if (err.type == "ConstraintError") {
|
|
err.message = "A mutation operation in the transaction failed. For more details look at the error on the instert, update, remove or clear statement.";
|
|
}
|
|
// txn error or abort
|
|
linq2indexedDB.prototype.utilities.logError(err);
|
|
pw.error(this, err);
|
|
});
|
|
|
|
// txn created
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Transaction transaction created.", transaction);
|
|
pw.progress(transaction, [transaction]);
|
|
}
|
|
}
|
|
catch (ex) {
|
|
var error = internal.wrapException(ex, "transaction");
|
|
if ((ex.INVALID_ACCESS_ERR && ex.code == ex.INVALID_ACCESS_ERR) || ex.name == "InvalidAccessError") {
|
|
error.type = "InvalidAccessError";
|
|
error.message = "You are trying to open a transaction without providing an object store as scope.";
|
|
}
|
|
if ((ex.NOT_FOUND_ERR && ex.code == ex.NOT_FOUND_ERR) || ex.name == "NotFoundError") {
|
|
var objectStores = "";
|
|
for (var m = 0; m < nonExistingObjectStores.length; m++) {
|
|
if (m > 0) {
|
|
objectStores += ", ";
|
|
}
|
|
objectStores += nonExistingObjectStores[m];
|
|
}
|
|
error.type = "NotFoundError";
|
|
error.message = "You are trying to open a transaction for object stores (" + objectStores + "), that doesn't exist.";
|
|
}
|
|
if ((ex.QUOTA_ERR && ex.code == ex.QUOTA_ERR) || ex.name == "QuotaExceededError") {
|
|
error.type = "QuotaExceededError";
|
|
error.message = "The size quota of the indexedDB database is reached.";
|
|
}
|
|
if ((ex.UNKNOWN_ERR && ex.code == ex.UNKNOWN_ERR) || ex.name == "UnknownError") {
|
|
error.type = "UnknownError";
|
|
error.message = "An I/O exception occured.";
|
|
}
|
|
linq2indexedDB.prototype.utilities.logError(error);
|
|
pw.error(this, error);
|
|
}
|
|
},
|
|
changeDatabaseStructure: function (db, version) {
|
|
return linq2indexedDB.prototype.utilities.promiseWrapper(function (pw) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "changeDatabaseStructure started", db, version);
|
|
handlers.IDBBlockedRequest(db.setVersion(version)).then(function (args /*txn, event*/) {
|
|
// txn created
|
|
pw.complete(this, args);
|
|
},
|
|
function (args /*error, event*/) {
|
|
// txn error or abort
|
|
pw.error(this, args);
|
|
},
|
|
function (args /*txn, event*/) {
|
|
// txn blocked
|
|
pw.progress(this, args);
|
|
});
|
|
});
|
|
},
|
|
objectStore: function (pw, transaction, objectStoreName) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "objectStore started", transaction, objectStoreName);
|
|
try {
|
|
var store = transaction.objectStore(objectStoreName);
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "objectStore completed", transaction, store);
|
|
pw.complete(store, [transaction, store]);
|
|
} catch (ex) {
|
|
var error = internal.wrapException(ex, "objectStore");
|
|
if ((ex.NOT_FOUND_ERR && ex.code == ex.NOT_FOUND_ERR) || ex.name == "NotFoundError") {
|
|
error.type = "NotFoundError";
|
|
error.message = "You are trying to open an object store (" + objectStoreName + "), that doesn't exist or isn't in side the transaction scope.";
|
|
}
|
|
if (ex.name == "TransactionInactiveError") {
|
|
error.type = "TransactionInactiveError";
|
|
error.message = "You are trying to open an object store (" + objectStoreName + ") outside a transaction.";
|
|
}
|
|
|
|
linq2indexedDB.prototype.utilities.logError(error);
|
|
linq2indexedDB.prototype.core.abortTransaction(transaction);
|
|
pw.error(this, error);
|
|
}
|
|
},
|
|
createObjectStore: function (pw, transaction, objectStoreName, objectStoreOptions) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "createObjectStore started", transaction, objectStoreName, objectStoreOptions);
|
|
try {
|
|
if (!transaction.db.objectStoreNames.contains(objectStoreName)) {
|
|
// If the object store doesn't exists, create it
|
|
var options = new Object();
|
|
|
|
if (objectStoreOptions) {
|
|
if (objectStoreOptions.keyPath) options.keyPath = objectStoreOptions.keyPath;
|
|
options.autoIncrement = objectStoreOptions.autoIncrement;
|
|
} else {
|
|
options.autoIncrement = true;
|
|
}
|
|
|
|
var store = transaction.db.createObjectStore(objectStoreName, options, options.autoIncrement);
|
|
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "ObjectStore Created", transaction, store);
|
|
linq2indexedDB.prototype.core.dbStructureChanged.fire({ type: dbEvents.objectStoreCreated, data: store });
|
|
pw.complete(store, [transaction, store]);
|
|
} else {
|
|
// If the object store exists, retrieve it
|
|
linq2indexedDB.prototype.core.objectStore(transaction, objectStoreName).then(function (args /*trans, store*/) {
|
|
// store resolved
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "ObjectStore Found", args[1], objectStoreName);
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "createObjectStore Promise", args[0], args[1]);
|
|
pw.complete(store, args);
|
|
},
|
|
function (args /*error, event*/) {
|
|
// store error
|
|
pw.error(this, args);
|
|
});
|
|
}
|
|
} catch (ex) {
|
|
// store exception
|
|
var error = internal.wrapException(ex, "createObjectStore");
|
|
if ((ex.INVALID_STATE_ERR && ex.code == ex.INVALID_STATE_ERR) || (ex.NOT_ALLOWED_ERR && ex.code == ex.NOT_ALLOWED_ERR) || ex.name == "InvalidStateError") {
|
|
error.type = "InvalidStateError";
|
|
error.message = "You are trying to create an object store in a readonly or readwrite transaction.";
|
|
}
|
|
if ((ex.INVALID_ACCESS_ERR && ex.code == ex.INVALID_ACCESS_ERR) || ex.name == "InvalidAccessError") {
|
|
error.type = "InvalidAccessError";
|
|
error.message = "The object store can't have autoIncrement on and an empty string or an array with an empty string as keyPath.";
|
|
}
|
|
linq2indexedDB.prototype.utilities.logError(error);
|
|
if (error.type != "InvalidStateError") {
|
|
linq2indexedDB.prototype.core.abortTransaction(transaction);
|
|
}
|
|
pw.error(this, error);
|
|
}
|
|
},
|
|
deleteObjectStore: function (pw, transaction, objectStoreName) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "deleteObjectStore Promise started", transaction, objectStoreName);
|
|
try {
|
|
transaction.db.deleteObjectStore(objectStoreName);
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "ObjectStore Deleted", objectStoreName);
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "deleteObjectStore completed", objectStoreName);
|
|
linq2indexedDB.prototype.core.dbStructureChanged.fire({ type: dbEvents.objectStoreRemoved, data: objectStoreName });
|
|
pw.complete(this, [transaction, objectStoreName]);
|
|
} catch (ex) {
|
|
var error = internal.wrapException(ex, "deleteObjectStore");
|
|
if ((ex.NOT_FOUND_ERR && ex.code == ex.NOT_FOUND_ERR) || ex.name == "NotFoundError") {
|
|
error.type = "NotFoundError";
|
|
error.message = "You are trying to delete an object store (" + objectStoreName + "), that doesn't exist.";
|
|
}
|
|
if ((ex.INVALID_STATE_ERR && ex.code == ex.INVALID_STATE_ERR) || (ex.NOT_ALLOWED_ERR && ex.code == ex.NOT_ALLOWED_ERR) || ex.name == "InvalidStateError") {
|
|
error.type = "InvalidStateError";
|
|
error.message = "You are trying to delete an object store in a readonly or readwrite transaction.";
|
|
}
|
|
// store exception
|
|
linq2indexedDB.prototype.utilities.logError(error);
|
|
if (error.type != "InvalidStateError") {
|
|
linq2indexedDB.prototype.core.abortTransaction(transaction);
|
|
}
|
|
pw.error(this, error);
|
|
}
|
|
},
|
|
index: function (pw, objectStore, propertyName, autoGenerateAllowed) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Index started", objectStore, propertyName, autoGenerateAllowed);
|
|
var indexName = propertyName;
|
|
if (propertyName.indexOf(linq2indexedDB.prototype.core.indexSuffix) == -1) {
|
|
indexName = indexName + linq2indexedDB.prototype.core.indexSuffix;
|
|
}
|
|
|
|
try {
|
|
if (!objectStore.indexNames.contains(indexName) && autoGenerateAllowed) {
|
|
// setTimeout is necessary when multiple request to generate an index come together.
|
|
// This can result in a deadlock situation, there for the setTimeout
|
|
setTimeout((function(objStore) {
|
|
upgradingDatabase = true;
|
|
// If index doesn't exists, create it if autoGenerateAllowed
|
|
var version = internal.getDatabaseVersion(objStore.transaction.db) + 1;
|
|
var dbName = objStore.transaction.db.name;
|
|
var transactionType = objStore.transaction.mode;
|
|
var objectStoreNames = [objStore.name]; //transaction.objectStoreNames;
|
|
var objectStoreName = objStore.name;
|
|
// Close the currenct database connections so it won't block
|
|
linq2indexedDB.prototype.core.closeDatabaseConnection(objStore);
|
|
|
|
// Open a new connection with the new version
|
|
linq2indexedDB.prototype.core.db(dbName, version).then(function (args /*dbConnection, event*/) {
|
|
upgradingDatabase = false;
|
|
// When the upgrade is completed, the index can be resolved.
|
|
linq2indexedDB.prototype.core.transaction(args[0], objectStoreNames, transactionType, autoGenerateAllowed).then(function(/*transaction, ev*/) {
|
|
// txn completed
|
|
// TODO: what to do in this case
|
|
},
|
|
function(args1 /*error, ev*/) {
|
|
// txn error or abort
|
|
pw.error(this, args1);
|
|
},
|
|
function(args1 /*transaction*/) {
|
|
// txn created
|
|
linq2indexedDB.prototype.core.index(linq2indexedDB.prototype.core.objectStore(args1[0], objectStoreName), propertyName).then(function(args2 /*trans, index, store*/) {
|
|
pw.complete(this, args2);
|
|
}, function(args2 /*error, ev*/) {
|
|
// txn error or abort
|
|
pw.error(this, args2);
|
|
});
|
|
});
|
|
},
|
|
function(args /*error, event*/) {
|
|
// When an error occures, bubble up.
|
|
pw.error(this, args);
|
|
},
|
|
function(args /*trans, event*/) {
|
|
var trans = args[0];
|
|
var event = args[1];
|
|
|
|
// When an upgradeneeded event is thrown, create the non-existing object stores
|
|
if (event.type == "upgradeneeded") {
|
|
linq2indexedDB.prototype.core.createIndex(linq2indexedDB.prototype.core.objectStore(trans, objectStoreName), propertyName).then(function (/*index, store, transaction*/) {
|
|
// index created
|
|
},
|
|
function(args1 /*error, ev*/) {
|
|
// When an error occures, bubble up.
|
|
pw.error(this, args1);
|
|
});
|
|
}
|
|
});
|
|
})(objectStore), upgradingDatabase ? 10 : 1);
|
|
} else {
|
|
// If index exists, resolve it
|
|
var index = objectStore.index(indexName);
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Index completed", objectStore.transaction, index, objectStore);
|
|
pw.complete(this, [objectStore.transaction, index, objectStore]);
|
|
}
|
|
} catch (ex) {
|
|
var error = internal.wrapException(ex, "index");
|
|
if ((ex.NOT_FOUND_ERR && ex.code == ex.NOT_FOUND_ERR) || ex.name == "NotFoundError") {
|
|
error.type = "NotFoundError";
|
|
error.message = "You are trying to open an index (" + indexName + "), that doesn't exist.";
|
|
}
|
|
if (ex.name == "TransactionInactiveError") {
|
|
error.type = "TransactionInactiveError";
|
|
error.message = "You are trying to open an object store (" + indexName + ") outside a transaction.";
|
|
}
|
|
// index exception
|
|
linq2indexedDB.prototype.utilities.logError(error);
|
|
linq2indexedDB.prototype.core.abortTransaction(objectStore.transaction);
|
|
pw.error(this, error);
|
|
}
|
|
},
|
|
createIndex: function (pw, objectStore, propertyName, indexOptions) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "createIndex started", objectStore, propertyName, indexOptions);
|
|
try {
|
|
var indexName = propertyName;
|
|
if (propertyName.indexOf(linq2indexedDB.prototype.core.indexSuffix) == -1) {
|
|
indexName = indexName + linq2indexedDB.prototype.core.indexSuffix;
|
|
}
|
|
|
|
if (!objectStore.indexNames.contains(indexName)) {
|
|
var index = objectStore.createIndex(indexName, propertyName, { unique: indexOptions ? indexOptions.unique : false, multiRow: indexOptions ? indexOptions.multirow : false, multiEntry: indexOptions ? indexOptions.multirow : false });
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "createIndex completed", objectStore.transaction, index, objectStore);
|
|
linq2indexedDB.prototype.core.dbStructureChanged.fire({ type: dbEvents.indexCreated, data: index });
|
|
pw.complete(this, [objectStore.transaction, index, objectStore]);
|
|
} else {
|
|
// if the index exists retrieve it
|
|
linq2indexedDB.prototype.core.index(objectStore, propertyName, false).then(function (args) {
|
|
pw.complete(this, args);
|
|
});
|
|
}
|
|
} catch (ex) {
|
|
// store exception
|
|
var error = internal.wrapException(ex, "createIndex");
|
|
if ((ex.INVALID_STATE_ERR && ex.code == ex.INVALID_STATE_ERR) || (ex.NOT_ALLOWED_ERR && ex.code == ex.NOT_ALLOWED_ERR) || ex.name == "InvalidStateError") {
|
|
error.type = "InvalidStateError";
|
|
error.message = "You are trying to create an index in a readonly or readwrite transaction.";
|
|
}
|
|
if (error.type != "InvalidStateError") {
|
|
linq2indexedDB.prototype.core.abortTransaction(transaction);
|
|
}
|
|
linq2indexedDB.prototype.utilities.logError(error);
|
|
pw.error(this, error);
|
|
}
|
|
},
|
|
deleteIndex: function (pw, objectStore, propertyName) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "deleteIndex started", objectStore, propertyName);
|
|
var indexName = propertyName;
|
|
if (propertyName.indexOf(linq2indexedDB.prototype.core.indexSuffix) == -1) {
|
|
indexName = indexName + linq2indexedDB.prototype.core.indexSuffix;
|
|
}
|
|
|
|
try {
|
|
objectStore.deleteIndex(indexName);
|
|
linq2indexedDB.prototype.core.dbStructureChanged.fire({ type: dbEvents.indexRemoved, data: indexName });
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "deleteIndex completed", objectStore.transaction, propertyName, objectStore);
|
|
pw.complete(this, [objectStore.transaction, propertyName, objectStore]);
|
|
} catch (ex) {
|
|
var error = internal.wrapException(ex, "deleteIndex");
|
|
if ((ex.NOT_FOUND_ERR && ex.code == ex.NOT_FOUND_ERR) || ex.name == "NotFoundError") {
|
|
error.type = "NotFoundError";
|
|
error.message = "You are trying to delete an index (" + indexName + ", propertyName: " + propertyName + " ), that doesn't exist.";
|
|
}
|
|
if ((ex.INVALID_STATE_ERR && ex.code == ex.INVALID_STATE_ERR) || (ex.NOT_ALLOWED_ERR && ex.code == ex.NOT_ALLOWED_ERR) || ex.name == "InvalidStateError") {
|
|
error.type = "InvalidStateError";
|
|
error.message = "You are trying to delete an index in a readonly or readwrite transaction.";
|
|
}
|
|
// store exception
|
|
linq2indexedDB.prototype.utilities.logError(error);
|
|
if (error.type != "InvalidStateError") {
|
|
linq2indexedDB.prototype.core.abortTransaction(transaction);
|
|
}
|
|
pw.error(this, error);
|
|
}
|
|
},
|
|
cursor: function (pw, source, range, direction) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Cursor Promise Started", source);
|
|
var keyRange;
|
|
var returnData = [];
|
|
var request;
|
|
|
|
try {
|
|
|
|
keyRange = range;
|
|
|
|
if (!keyRange) {
|
|
if (implementation != implementations.GOOGLE) {
|
|
keyRange = IDBKeyRange.lowerBound(0);
|
|
} else {
|
|
keyRange = IDBKeyRange.lowerBound(parseFloat(0));
|
|
}
|
|
}
|
|
|
|
// direction can not be null when passed.
|
|
if (direction) {
|
|
request = handlers.IDBCursorRequest(source.openCursor(keyRange, direction));
|
|
} else if (keyRange) {
|
|
request = handlers.IDBCursorRequest(source.openCursor(keyRange));
|
|
} else {
|
|
request = handlers.IDBCursorRequest(source.openCursor());
|
|
}
|
|
|
|
request.then(function (args1 /*result, e*/) {
|
|
var e = args1[1];
|
|
var transaction = source.transaction || source.objectStore.transaction;
|
|
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Cursor completed", returnData, transaction, e);
|
|
pw.complete(this, [returnData, transaction, e]);
|
|
},
|
|
function (args /*error, e*/) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.error, "Cursor error", args);
|
|
pw.error(this, args);
|
|
},
|
|
function (args /*result, e*/) {
|
|
var result = args[0];
|
|
var e = args[1];
|
|
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Cursor progress", result, e);
|
|
if (result.value) {
|
|
var progressObj = {
|
|
data: result.value,
|
|
key: result.primaryKey,
|
|
skip: function(number) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Cursor skip", result, e);
|
|
try {
|
|
result.advance(number);
|
|
}
|
|
catch (advanceEx) {
|
|
var advanceErr = internal.wrapException(advanceEx, "cursor - skip");
|
|
|
|
if ((advanceEx.DATA_ERR && advanceEx.code == advanceEx.DATA_ERR) || advanceEx.name == "DataError") {
|
|
advanceErr.type = "DataError";
|
|
advanceErr.message = "The provided range parameter isn't a valid key or key range.";
|
|
}
|
|
|
|
if (advanceEx.name == "TypeError") {
|
|
advanceErr.type = "TypeError";
|
|
advanceErr.message = "The provided count parameter is zero or a negative number.";
|
|
}
|
|
|
|
if ((advanceEx.INVALID_STATE_ERR && advanceEx.code == advanceEx.INVALID_STATE_ERR) || advanceEx.name == "InvalidStateError") {
|
|
advanceErr.type = "InvalidStateError";
|
|
advanceErr.message = "You are trying to skip data on a removed object store.";
|
|
}
|
|
linq2indexedDB.prototype.utilities.logError(advanceErr);
|
|
linq2indexedDB.prototype.core.abortTransaction(txn);
|
|
pw.error(this, advanceErr);
|
|
}
|
|
},
|
|
update: function(obj) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Cursor update", result, e);
|
|
try {
|
|
result.update(obj);
|
|
}
|
|
catch (updateEx) {
|
|
var updateError = internal.wrapException(updateEx, "cursor - update");
|
|
|
|
if ((updateEx.DATA_ERR && updateEx.code == updateEx.DATA_ERR) || updateEx.name == "DataError") {
|
|
updateError.type = "DataError";
|
|
updateError.message = "The underlying object store uses in-line keys and the property in value at the object store's key path does not match the key in this cursor's position.";
|
|
}
|
|
|
|
if ((updateEx.READ_ONLY_ERR && ex.code == updateEx.READ_ONLY_ERR) || updateEx.name == "ReadOnlyError") {
|
|
updateError.type = "ReadOnlyError";
|
|
updateError.message = "You are trying to update data in a readonly transaction.";
|
|
}
|
|
|
|
if (updateEx.name == "TransactionInactiveError") {
|
|
updateError.type = "TransactionInactiveError";
|
|
updateError.message = "You are trying to update data on an inactieve transaction. (The transaction was already aborted or committed)";
|
|
}
|
|
|
|
if ((updateEx.DATA_CLONE_ERR && updateEx.code == updateEx.DATA_CLONE_ERR) || updateEx.name == "DataCloneError") {
|
|
updateError.type = "DataCloneError";
|
|
updateError.message = "The data you are trying to update could not be cloned. Your data probably contains a function which can not be cloned by default. Try using the serialize method to update the data.";
|
|
}
|
|
|
|
if ((updateEx.INVALID_STATE_ERR && updateEx.code == updateEx.INVALID_STATE_ERR) || updateEx.name == "InvalidStateError") {
|
|
updateError.type = "InvalidStateError";
|
|
updateError.message = "You are trying to update data on a removed object store.";
|
|
}
|
|
|
|
linq2indexedDB.prototype.utilities.logError(updateError);
|
|
linq2indexedDB.prototype.core.abortTransaction(txn);
|
|
pw.error(this, updateError);
|
|
}
|
|
},
|
|
remove: function() {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Cursor remove", result, e);
|
|
try {
|
|
result["delete"]();
|
|
}
|
|
catch (deleteEx) {
|
|
var deleteError = internal.wrapException(deleteEx, "cursor - delete");
|
|
|
|
if ((deleteEx.READ_ONLY_ERR && deleteEx.code == deleteEx.READ_ONLY_ERR) || deleteEx.name == "ReadOnlyError") {
|
|
deleteError.type = "ReadOnlyError";
|
|
deleteError.message = "You are trying to remove data in a readonly transaction.";
|
|
}
|
|
|
|
if (deleteEx.name == "TransactionInactiveError") {
|
|
deleteError.type = "TransactionInactiveError";
|
|
deleteError.message = "You are trying to remove data on an inactieve transaction. (The transaction was already aborted or committed)";
|
|
}
|
|
|
|
if ((deleteEx.INVALID_STATE_ERR && deleteEx.code == deleteEx.INVALID_STATE_ERR) || deleteEx.name == "InvalidStateError") {
|
|
deleteError.type = "InvalidStateError";
|
|
deleteError.message = "You are trying to remove data on a removed object store.";
|
|
}
|
|
|
|
linq2indexedDB.prototype.utilities.logError(deleteError);
|
|
linq2indexedDB.prototype.core.abortTransaction(txn);
|
|
pw.error(this, deleteError);
|
|
}
|
|
}
|
|
};
|
|
|
|
pw.progress(this, [progressObj, result, e]);
|
|
returnData.push({data: progressObj.data ,key: progressObj.key });
|
|
}
|
|
result["continue"]();
|
|
});
|
|
} catch (ex) {
|
|
var txn = source.transaction || source.objectStore.transaction;
|
|
var error = internal.wrapException(ex, "cursor");
|
|
|
|
if ((ex.DATA_ERR && error.code == ex.DATA_ERR) || ex.name == "DataError") {
|
|
error.type = "DataError";
|
|
error.message = "The provided range parameter isn't a valid key or key range.";
|
|
}
|
|
|
|
if (ex.name == "TransactionInactiveError") {
|
|
error.type = "TransactionInactiveError";
|
|
error.message = "You are trying to retrieve data on an inactieve transaction. (The transaction was already aborted or committed)";
|
|
}
|
|
|
|
if (ex.name == "TypeError") {
|
|
error.type = "TypeError";
|
|
error.message = "The provided directory parameter is invalid";
|
|
}
|
|
|
|
if ((ex.INVALID_STATE_ERR && ex.code == ex.INVALID_STATE_ERR) || (ex.NOT_ALLOWED_ERR && ex.code == ex.NOT_ALLOWED_ERR) || ex.name == "InvalidStateError") {
|
|
error.type = "InvalidStateError";
|
|
error.message = "You are trying to insert data on a removed object store.";
|
|
}
|
|
linq2indexedDB.prototype.utilities.logError(error);
|
|
linq2indexedDB.prototype.core.abortTransaction(txn);
|
|
pw.error(this, error);
|
|
}
|
|
finally {
|
|
keyRange = null;
|
|
}
|
|
},
|
|
keyCursor: function (pw, index, range, direction) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "keyCursor Started", index, range, direction);
|
|
var returnData = [];
|
|
|
|
try {
|
|
var request;
|
|
var keyRange = range;
|
|
|
|
if (!keyRange) {
|
|
keyRange = IDBKeyRange.lowerBound(0);
|
|
}
|
|
|
|
// direction can not be null when passed.
|
|
if (direction) {
|
|
request = handlers.IDBCursorRequest(source.openKeyCursor(keyRange, direction));
|
|
} else {
|
|
request = handlers.IDBCursorRequest(source.openKeyCursor(keyRange));
|
|
}
|
|
|
|
request.then(function (args /*result, e*/) {
|
|
var e = args[1];
|
|
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "keyCursor completed", returnData, index.objectStore.transaction, e);
|
|
pw.complete(this, [returnData, index.objectStore.transaction, e]);
|
|
},
|
|
function (args /*error, e*/) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.error, "keyCursor error", args);
|
|
pw.error(this, args);
|
|
},
|
|
function (args /*result, e*/) {
|
|
var result = args[0];
|
|
var e = args[1];
|
|
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "keyCursor progress", result, e);
|
|
if (result.value) {
|
|
var progressObj = {
|
|
data: result.value,
|
|
key: result.primaryKey,
|
|
skip: function (number) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "keyCursor skip", result, e);
|
|
try {
|
|
result.advance(number);
|
|
}
|
|
catch (advanceEx) {
|
|
var advanceErr = internal.wrapException(advanceEx, "keyCursor - skip");
|
|
|
|
if ((advanceEx.DATA_ERR && advanceEx.code == advanceEx.DATA_ERR) || advanceEx.name == "DataError") {
|
|
advanceErr.type = "DataError";
|
|
advanceErr.message = "The provided range parameter isn't a valid key or key range.";
|
|
}
|
|
|
|
if (advanceEx.name == "TypeError") {
|
|
advanceErr.type = "TypeError";
|
|
advanceErr.message = "The provided count parameter is zero or a negative number.";
|
|
}
|
|
|
|
if ((advanceEx.INVALID_STATE_ERR && advanceEx.code == advanceEx.INVALID_STATE_ERR) || advanceEx.name == "InvalidStateError") {
|
|
advanceErr.type = "InvalidStateError";
|
|
advanceErr.message = "You are trying to skip data on a removed object store.";
|
|
}
|
|
linq2indexedDB.prototype.utilities.logError(advanceErr);
|
|
linq2indexedDB.prototype.core.abortTransaction(index.objectStore.transaction);
|
|
pw.error(this, advanceErr);
|
|
}
|
|
},
|
|
update: function (obj) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "keyCursor update", result, e);
|
|
try {
|
|
result.update(obj);
|
|
}
|
|
catch (updateEx) {
|
|
var updateError = internal.wrapException(updateEx, "keyCursor - update");
|
|
|
|
if ((updateEx.DATA_ERR && updateEx.code == updateEx.DATA_ERR) || updateEx.name == "DataError") {
|
|
updateError.type = "DataError";
|
|
updateError.message = "The underlying object store uses in-line keys and the property in value at the object store's key path does not match the key in this cursor's position.";
|
|
}
|
|
|
|
if ((updateEx.READ_ONLY_ERR && ex.code == updateEx.READ_ONLY_ERR) || updateEx.name == "ReadOnlyError") {
|
|
updateError.type = "ReadOnlyError";
|
|
updateError.message = "You are trying to update data in a readonly transaction.";
|
|
}
|
|
|
|
if (updateEx.name == "TransactionInactiveError") {
|
|
updateError.type = "TransactionInactiveError";
|
|
updateError.message = "You are trying to update data on an inactieve transaction. (The transaction was already aborted or committed)";
|
|
}
|
|
|
|
if ((updateEx.DATA_CLONE_ERR && updateEx.code == updateEx.DATA_CLONE_ERR) || updateEx.name == "DataCloneError") {
|
|
updateError.type = "DataCloneError";
|
|
updateError.message = "The data you are trying to update could not be cloned. Your data probably contains a function which can not be cloned by default. Try using the serialize method to update the data.";
|
|
}
|
|
|
|
if ((updateEx.INVALID_STATE_ERR && updateEx.code == updateEx.INVALID_STATE_ERR) || updateEx.name == "InvalidStateError") {
|
|
updateError.type = "InvalidStateError";
|
|
updateError.message = "You are trying to update data on a removed object store.";
|
|
}
|
|
|
|
linq2indexedDB.prototype.utilities.logError(updateError);
|
|
linq2indexedDB.prototype.core.abortTransaction(index.objectStore.transaction);
|
|
pw.error(this, updateError);
|
|
}
|
|
},
|
|
remove: function () {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "keyCursor remove", result, e);
|
|
try {
|
|
result["delete"]();
|
|
}
|
|
catch (deleteEx) {
|
|
var deleteError = internal.wrapException(deleteEx, "keyCursor - delete");
|
|
|
|
if ((deleteEx.READ_ONLY_ERR && deleteEx.code == deleteEx.READ_ONLY_ERR) || deleteEx.name == "ReadOnlyError") {
|
|
deleteError.type = "ReadOnlyError";
|
|
deleteError.message = "You are trying to remove data in a readonly transaction.";
|
|
}
|
|
|
|
if (deleteEx.name == "TransactionInactiveError") {
|
|
deleteError.type = "TransactionInactiveError";
|
|
deleteError.message = "You are trying to remove data on an inactieve transaction. (The transaction was already aborted or committed)";
|
|
}
|
|
|
|
if ((deleteEx.INVALID_STATE_ERR && deleteEx.code == deleteEx.INVALID_STATE_ERR) || deleteEx.name == "InvalidStateError") {
|
|
deleteError.type = "InvalidStateError";
|
|
deleteError.message = "You are trying to remove data on a removed object store.";
|
|
}
|
|
|
|
linq2indexedDB.prototype.utilities.logError(deleteError);
|
|
linq2indexedDB.prototype.core.abortTransaction(index.objectStore.transaction);
|
|
pw.error(this, deleteError);
|
|
}
|
|
}
|
|
};
|
|
|
|
pw.progress(this, [progressObj, result, e]);
|
|
returnData.push(progressObj.data);
|
|
}
|
|
result["continue"]();
|
|
});
|
|
} catch (ex) {
|
|
var error = internal.wrapException(ex, "keyCursor");
|
|
|
|
if ((ex.DATA_ERR && error.code == ex.DATA_ERR) || ex.name == "DataError") {
|
|
error.type = "DataError";
|
|
error.message = "The provided range parameter isn't a valid key or key range.";
|
|
}
|
|
|
|
if (ex.name == "TransactionInactiveError") {
|
|
error.type = "TransactionInactiveError";
|
|
error.message = "You are trying to retrieve data on an inactieve transaction. (The transaction was already aborted or committed)";
|
|
}
|
|
|
|
if (ex.name == "TypeError") {
|
|
error.type = "TypeError";
|
|
error.message = "The provided directory parameter is invalid";
|
|
}
|
|
|
|
if ((ex.INVALID_STATE_ERR && ex.code == ex.INVALID_STATE_ERR) || (ex.NOT_ALLOWED_ERR && ex.code == ex.NOT_ALLOWED_ERR) || ex.name == "InvalidStateError") {
|
|
error.type = "InvalidStateError";
|
|
error.message = "You are trying to insert data on a removed object store.";
|
|
}
|
|
linq2indexedDB.prototype.utilities.logError(error);
|
|
linq2indexedDB.prototype.core.abortTransaction(index.objectStore.transaction);
|
|
pw.error(this, error);
|
|
}
|
|
},
|
|
get: function (pw, source, key) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Get Started", source);
|
|
|
|
try {
|
|
handlers.IDBRequest(source.get(key)).then(function (args /*result, e*/) {
|
|
var result = args[0];
|
|
var e = args[1];
|
|
var transaction = source.transaction || source.objectStore.transaction;
|
|
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Get completed", result, transaction, e);
|
|
pw.complete(this, [result, transaction, e]);
|
|
}, function (args /*error, e*/) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.error, "Get error", args);
|
|
pw.error(this, args);
|
|
});
|
|
} catch (ex) {
|
|
var txn = source.transaction || source.objectStore.transaction;
|
|
var error = internal.wrapException(ex, "get");
|
|
|
|
if (error.code == ex.DATA_ERR || ex.name == "DataError") {
|
|
error.message = "The provided key isn't a valid key (must be an array, string, date or number).";
|
|
}
|
|
|
|
if (ex.name == "TransactionInactiveError") {
|
|
error.type = "TransactionInactiveError";
|
|
error.message = "You are trying to retrieve data on an inactieve transaction. (The transaction was already aborted or committed)";
|
|
}
|
|
|
|
if ((ex.INVALID_STATE_ERR && ex.code == ex.INVALID_STATE_ERR) || (ex.NOT_ALLOWED_ERR && ex.code == ex.NOT_ALLOWED_ERR) || ex.name == "InvalidStateError") {
|
|
error.type = "InvalidStateError";
|
|
error.message = "You are trying to retrieve data on a removed object store.";
|
|
}
|
|
linq2indexedDB.prototype.utilities.logError(error);
|
|
linq2indexedDB.prototype.core.abortTransaction(txn);
|
|
pw.error(this, error);
|
|
}
|
|
},
|
|
count: function (pw, source, key) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Count Started", source);
|
|
|
|
try {
|
|
var req;
|
|
|
|
if (key) {
|
|
req = source.count(key);
|
|
}
|
|
else {
|
|
req = source.count();
|
|
}
|
|
|
|
handlers.IDBRequest(req).then(function (args /*result, e*/) {
|
|
var result = args[0];
|
|
var e = args[1];
|
|
var transaction = source.transaction || source.objectStore.transaction;
|
|
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Count completed", result, transaction, e);
|
|
pw.complete(this, [result, transaction, e]);
|
|
}, function (args /*error, e*/) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.error, "Count error", args);
|
|
pw.error(this, args);
|
|
});
|
|
} catch (ex) {
|
|
var txn = source.transaction || source.objectStore.transaction;
|
|
var error = internal.wrapException(ex, "count");
|
|
|
|
if (error.code == ex.DATA_ERR || ex.name == "DataError") {
|
|
error.type = "DataError";
|
|
error.message = "The provided key isn't a valid key or keyRange.";
|
|
}
|
|
|
|
if (ex.name == "TransactionInactiveError") {
|
|
error.type = "TransactionInactiveError";
|
|
error.message = "You are trying to count data on an inactieve transaction. (The transaction was already aborted or committed)";
|
|
}
|
|
|
|
if ((ex.INVALID_STATE_ERR && ex.code == ex.INVALID_STATE_ERR) || (ex.NOT_ALLOWED_ERR && ex.code == ex.NOT_ALLOWED_ERR) || ex.name == "InvalidStateError") {
|
|
error.type = "InvalidStateError";
|
|
error.message = "You are trying to count data on a removed object store.";
|
|
}
|
|
linq2indexedDB.prototype.utilities.logError(error);
|
|
linq2indexedDB.prototype.core.abortTransaction(txn);
|
|
pw.error(this, error);
|
|
}
|
|
},
|
|
getKey: function (pw, index, key) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "GetKey Started", index, key);
|
|
|
|
try {
|
|
handlers.IDBRequest(index.getKey(key)).then(function (args /*result, e*/) {
|
|
var result = args[0];
|
|
var e = args[1];
|
|
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "GetKey completed", result, index.objectStore.transaction, e);
|
|
pw.complete(this, [result, index.objectStore.transaction, e]);
|
|
}, function (args /*error, e*/) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.error, "GetKey error", args);
|
|
pw.error(this, args);
|
|
});
|
|
} catch (ex) {
|
|
var error = internal.wrapException(ex, "getKey");
|
|
|
|
if (error.code == ex.DATA_ERR || ex.name == "DataError") {
|
|
error.type = "DataError";
|
|
error.message = "The provided key isn't a valid key or keyRange.";
|
|
}
|
|
|
|
if (ex.name == "TransactionInactiveError") {
|
|
error.type = "TransactionInactiveError";
|
|
error.message = "You are trying to getKey data on an inactieve transaction. (The transaction was already aborted or committed)";
|
|
}
|
|
|
|
if ((ex.INVALID_STATE_ERR && ex.code == ex.INVALID_STATE_ERR) || (ex.NOT_ALLOWED_ERR && ex.code == ex.NOT_ALLOWED_ERR) || ex.name == "InvalidStateError") {
|
|
error.type = "InvalidStateError";
|
|
error.message = "You are trying to getKey data on a removed object store.";
|
|
}
|
|
linq2indexedDB.prototype.utilities.logError(error);
|
|
linq2indexedDB.prototype.core.abortTransaction(index.objectStore.transaction);
|
|
pw.error(this, error);
|
|
}
|
|
},
|
|
insert: function (pw, objectStore, data, key) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Insert Started", objectStore, data, key);
|
|
try {
|
|
var req;
|
|
|
|
if (key /*&& !store.keyPath*/) {
|
|
req = handlers.IDBRequest(objectStore.add(data, key));
|
|
} else {
|
|
/*if (key) linq2indexedDB.prototype.utilities.log("Key can't be provided when a keyPath is defined on the object store", store, key, data);*/
|
|
req = handlers.IDBRequest(objectStore.add(data));
|
|
}
|
|
|
|
req.then(function (args /*result, e*/) {
|
|
var result = args[0];
|
|
var e = args[1];
|
|
|
|
// Add key to the object if a keypath exists
|
|
if (objectStore.keyPath) {
|
|
data[objectStore.keyPath] = result;
|
|
}
|
|
|
|
linq2indexedDB.prototype.core.dbDataChanged.fire({ type: dataEvents.dataInserted, data: data, objectStore: objectStore });
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Insert completed", data, result, objectStore.transaction, e);
|
|
pw.complete(this, [data, result, objectStore.transaction, e]);
|
|
}, function (args /*error, e*/) {
|
|
var err = internal.wrapError(args[1], "insert");
|
|
|
|
// Fix for firefox & chrome
|
|
if (args[1].target && args[1].target.errorCode == 4) {
|
|
err.type = "ConstraintError";
|
|
}
|
|
|
|
if (err.type == "ConstraintError") {
|
|
var duplicateKey = key;
|
|
if (!duplicateKey && objectStore.keyPath) {
|
|
duplicateKey = data[objectStore.keyPath];
|
|
}
|
|
err.message = "A record for the key (" + duplicateKey + ") already exists in the database or one of the properties of the provided data has a unique index declared.";
|
|
}
|
|
linq2indexedDB.prototype.core.abortTransaction(objectStore.transaction);
|
|
linq2indexedDB.prototype.utilities.logError(err);
|
|
pw.error(this, err);
|
|
});
|
|
} catch (ex) {
|
|
var error = internal.wrapException(ex, "insert");
|
|
|
|
if (error.code == ex.DATA_ERR || ex.name == "DataError") {
|
|
error.type = "DataError";
|
|
var possibleKey = key;
|
|
if (!possibleKey && objectStore.keyPath) {
|
|
possibleKey = data[objectStore.keyPath];
|
|
}
|
|
if (!possibleKey) {
|
|
error.message = "There is no key provided for the data you want to insert for an object store without autoIncrement.";
|
|
} else if (key && objectStore.keyPath) {
|
|
error.message = "An external key is provided while the object store expects a keyPath key.";
|
|
} else if (typeof possibleKey !== "string"
|
|
&& typeof possibleKey !== "number"
|
|
&& typeof possibleKey !== "Date"
|
|
&& !linq2indexedDB.prototype.utilities.isArray(possibleKey)) {
|
|
error.message = "The provided key isn't a valid key (must be an array, string, date or number).";
|
|
}
|
|
}
|
|
|
|
if ((ex.READ_ONLY_ERR && ex.code == ex.READ_ONLY_ERR) || ex.name == "ReadOnlyError") {
|
|
error.type = "ReadOnlyError";
|
|
error.message = "You are trying to insert data in a readonly transaction.";
|
|
}
|
|
|
|
if (ex.name == "TransactionInactiveError") {
|
|
error.type = "TransactionInactiveError";
|
|
error.message = "You are trying to insert data on an inactieve transaction. (The transaction was already aborted or committed)";
|
|
}
|
|
|
|
if ((ex.DATA_CLONE_ERR && ex.code == ex.DATA_CLONE_ERR) || ex.name == "DataCloneError") {
|
|
error.type = "DataCloneError";
|
|
error.message = "The data you are trying to insert could not be cloned. Your data probably contains a function which can not be cloned by default. Try using the serialize method to insert the data.";
|
|
}
|
|
|
|
if ((ex.INVALID_STATE_ERR && ex.code == ex.INVALID_STATE_ERR) || (ex.NOT_ALLOWED_ERR && ex.code == ex.NOT_ALLOWED_ERR) || ex.name == "InvalidStateError") {
|
|
error.type = "InvalidStateError";
|
|
error.message = "You are trying to insert data on a removed object store.";
|
|
}
|
|
linq2indexedDB.prototype.utilities.logError(error);
|
|
linq2indexedDB.prototype.core.abortTransaction(objectStore.transaction);
|
|
pw.error(this, error);
|
|
}
|
|
},
|
|
update: function (pw, objectStore, data, key) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Update Started", objectStore, data, key);
|
|
|
|
try {
|
|
var req;
|
|
if (key /*&& !store.keyPath*/) {
|
|
req = handlers.IDBRequest(objectStore.put(data, key));
|
|
} else {
|
|
/*if (key) linq2indexedDB.prototype.utilities.log("Key can't be provided when a keyPath is defined on the object store", store, key, data);*/
|
|
req = handlers.IDBRequest(objectStore.put(data));
|
|
}
|
|
req.then(function (args /*result, e*/) {
|
|
var result = args[0];
|
|
var e = args[1];
|
|
|
|
if (objectStore.keyPath && data[objectStore.keyPath] === undefined) {
|
|
data[objectStore.keyPath] = result;
|
|
}
|
|
|
|
linq2indexedDB.prototype.core.dbDataChanged.fire({ type: dataEvents.dataUpdated, data: data, objectStore: objectStore });
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Update completed", data, result, objectStore.transaction, e);
|
|
pw.complete(this, [data, result, objectStore.transaction, e]);
|
|
}, function (args /*error, e*/) {
|
|
var err = internal.wrapError(args[1], "update");
|
|
linq2indexedDB.prototype.core.abortTransaction(objectStore.transaction);
|
|
linq2indexedDB.prototype.utilities.logError(err);
|
|
pw.error(this, err);
|
|
});
|
|
} catch (ex) {
|
|
var error = internal.wrapException(ex, "update");
|
|
|
|
if (error.code == ex.DATA_ERR || ex.name == "DataError") {
|
|
error.type = "DataError";
|
|
var possibleKey = key;
|
|
if (!possibleKey && objectStore.keyPath) {
|
|
possibleKey = data[objectStore.keyPath];
|
|
}
|
|
if (!possibleKey) {
|
|
error.message = "There is no key provided for the data you want to update for an object store without autoIncrement.";
|
|
} else if (key && objectStore.keyPath) {
|
|
error.message = "An external key is provided while the object store expects a keyPath key.";
|
|
} else if (typeof possibleKey !== "string"
|
|
&& typeof possibleKey !== "number"
|
|
&& typeof possibleKey !== "Date"
|
|
&& !linq2indexedDB.prototype.utilities.isArray(possibleKey)) {
|
|
error.message = "The provided key isn't a valid key (must be an array, string, date or number).";
|
|
}
|
|
}
|
|
|
|
if ((ex.READ_ONLY_ERR && ex.code == ex.READ_ONLY_ERR) || ex.name == "ReadOnlyError") {
|
|
error.type = "ReadOnlyError";
|
|
error.message = "You are trying to update data in a readonly transaction.";
|
|
}
|
|
|
|
if (ex.name == "TransactionInactiveError") {
|
|
error.type = "TransactionInactiveError";
|
|
error.message = "You are trying to update data on an inactieve transaction. (The transaction was already aborted or committed)";
|
|
}
|
|
|
|
if ((ex.DATA_CLONE_ERR && ex.code == ex.DATA_CLONE_ERR) || ex.name == "DataCloneError") {
|
|
error.type = "DataCloneError";
|
|
error.message = "The data you are trying to update could not be cloned. Your data probably contains a function which can not be cloned by default. Try using the serialize method to update the data.";
|
|
}
|
|
|
|
if ((ex.INVALID_STATE_ERR && ex.code == ex.INVALID_STATE_ERR) || (ex.NOT_ALLOWED_ERR && ex.code == ex.NOT_ALLOWED_ERR) || ex.name == "InvalidStateError") {
|
|
error.type = "InvalidStateError";
|
|
error.message = "You are trying to update data on a removed object store.";
|
|
}
|
|
|
|
linq2indexedDB.prototype.utilities.logError(error);
|
|
linq2indexedDB.prototype.core.abortTransaction(objectStore.transaction);
|
|
pw.error(this, error);
|
|
}
|
|
},
|
|
remove: function (pw, objectStore, key) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Remove Started", objectStore, key);
|
|
|
|
try {
|
|
handlers.IDBRequest(objectStore["delete"](key)).then(function (args /*result, e*/) {
|
|
var result = args[0];
|
|
var e = args[1];
|
|
|
|
linq2indexedDB.prototype.core.dbDataChanged.fire({ type: dataEvents.dataRemoved, data: key, objectStore: objectStore });
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Remove completed", result, objectStore.transaction, e);
|
|
pw.complete(this, [result, objectStore.transaction, e]);
|
|
},
|
|
function (args /*error, e*/) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.error, "Remove error", args);
|
|
pw.error(this, args);
|
|
});
|
|
} catch (ex) {
|
|
var error = internal.wrapException(ex, "delete");
|
|
|
|
if ((ex.READ_ONLY_ERR && ex.code == ex.READ_ONLY_ERR) || ex.name == "ReadOnlyError") {
|
|
error.type = "ReadOnlyError";
|
|
error.message = "You are trying to remove data in a readonly transaction.";
|
|
}
|
|
|
|
if (ex.name == "TransactionInactiveError") {
|
|
error.type = "TransactionInactiveError";
|
|
error.message = "You are trying to remove data on an inactieve transaction. (The transaction was already aborted or committed)";
|
|
}
|
|
|
|
if ((ex.INVALID_STATE_ERR && ex.code == ex.INVALID_STATE_ERR) || (ex.NOT_ALLOWED_ERR && ex.code == ex.NOT_ALLOWED_ERR) || ex.name == "InvalidStateError") {
|
|
error.type = "InvalidStateError";
|
|
error.message = "You are trying to remove data on a removed object store.";
|
|
}
|
|
|
|
linq2indexedDB.prototype.utilities.logError(error);
|
|
linq2indexedDB.prototype.core.abortTransaction(objectStore.transaction);
|
|
pw.error(this, error);
|
|
}
|
|
},
|
|
clear: function (pw, objectStore) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Clear Started", objectStore);
|
|
try {
|
|
handlers.IDBRequest(objectStore.clear()).then(function (args /*result, e*/) {
|
|
var result = args[0];
|
|
var e = args[1];
|
|
|
|
linq2indexedDB.prototype.core.dbDataChanged.fire({ type: dataEvents.objectStoreCleared, objectStore: objectStore });
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Clear completed", result, objectStore.transaction, e);
|
|
pw.complete(this, [result, objectStore.transaction, e]);
|
|
},
|
|
function (args /*error, e*/) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.error, "Clear error", args);
|
|
pw.error(this, args);
|
|
});
|
|
} catch (ex) {
|
|
var error = internal.wrapException(ex, "clear");
|
|
|
|
if ((ex.READ_ONLY_ERR && ex.code == ex.READ_ONLY_ERR) || ex.name == "ReadOnlyError") {
|
|
error.type = "ReadOnlyError";
|
|
error.message = "You are trying to clear data in a readonly transaction.";
|
|
}
|
|
|
|
if (ex.name == "TransactionInactiveError") {
|
|
error.type = "TransactionInactiveError";
|
|
error.message = "You are trying to clear data on an inactieve transaction. (The transaction was already aborted or committed)";
|
|
}
|
|
|
|
if ((ex.INVALID_STATE_ERR && ex.code == ex.INVALID_STATE_ERR) || (ex.NOT_ALLOWED_ERR && ex.code == ex.NOT_ALLOWED_ERR) || ex.name == "InvalidStateError") {
|
|
error.type = "InvalidStateError";
|
|
error.message = "You are trying to clear data on a removed object store.";
|
|
}
|
|
|
|
linq2indexedDB.prototype.utilities.logError(error);
|
|
linq2indexedDB.prototype.core.abortTransaction(objectStore.transaction);
|
|
pw.error(this, error);
|
|
}
|
|
},
|
|
deleteDb: function (pw, name) {
|
|
try {
|
|
if (typeof (window.indexedDB.deleteDatabase) != "undefined") {
|
|
|
|
handlers.IDBBlockedRequest(window.indexedDB.deleteDatabase(name)).then(function (args /*result, e*/) {
|
|
var result = args[0];
|
|
var e = args[1];
|
|
|
|
linq2indexedDB.prototype.core.dbStructureChanged.fire({ type: dbEvents.databaseRemoved });
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Delete Database Promise completed", result, e, name);
|
|
pw.complete(this, [result, e, name]);
|
|
}, function (args /*error, e*/) {
|
|
var error = args[0];
|
|
var e = args[1];
|
|
|
|
// added for FF, If a db gets deleted that doesn't exist an errorCode 6 ('NOT_ALLOWED_ERR') is given
|
|
if (e.currentTarget && e.currentTarget.errorCode == 6) {
|
|
linq2indexedDB.prototype.core.dbStructureChanged.fire({ type: dbEvents.databaseRemoved });
|
|
pw.complete(this, [error, e, name]);
|
|
} else if (implementation == implementations.SHIM
|
|
&& e.message == "Database does not exist") {
|
|
linq2indexedDB.prototype.core.dbStructureChanged.fire({ type: dbEvents.databaseRemoved });
|
|
pw.complete(this, [error, e, name]);
|
|
} else {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.error, "Delete Database Promise error", error, e);
|
|
pw.error(this, [error, e]);
|
|
}
|
|
}, function (args /*result, e*/) {
|
|
if (args[0] == "blocked") {
|
|
linq2indexedDB.prototype.core.dbStructureChanged.fire({ type: dbEvents.databaseBlocked });
|
|
}
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Delete Database Promise blocked", args /*result*/);
|
|
pw.progress(this, args /*[result, e]*/);
|
|
});
|
|
} else {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Delete Database function not found", name);
|
|
// Workaround for older versions of chrome and FireFox
|
|
// Doesn't delete the database, but clears him
|
|
linq2indexedDB.prototype.core.db(name, -1).then(function (args /*result, e*/) {
|
|
var result = args[0];
|
|
var e = args[1];
|
|
|
|
linq2indexedDB.prototype.core.dbStructureChanged.fire({ type: dbEvents.databaseRemoved });
|
|
pw.complete(this, [result, e, name]);
|
|
},
|
|
function (args /*error, e*/) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.error, "Clear Promise error", args /*error, e*/);
|
|
pw.error(this, args /*[error, e]*/);
|
|
},
|
|
function (args /*dbConnection, event*/) {
|
|
var dbConnection = args[0];
|
|
var event = args[1];
|
|
|
|
// When an upgradeneeded event is thrown, create the non-existing object stores
|
|
if (event.type == "upgradeneeded") {
|
|
for (var i = 0; i < dbConnection.objectStoreNames.length; i++) {
|
|
linq2indexedDB.prototype.core.deleteObjectStore(dbConnection.txn, dbConnection.objectStoreNames[i]);
|
|
}
|
|
linq2indexedDB.prototype.core.closeDatabaseConnection(dbConnection);
|
|
}
|
|
});
|
|
}
|
|
} catch (ex) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.exception, "Delete Database Promise exception", ex);
|
|
pw.error(this, [ex.message, ex]);
|
|
}
|
|
},
|
|
getDatabaseVersion: function (db)
|
|
{
|
|
var dbVersion = parseInt(db.version);
|
|
if (isNaN(dbVersion) || dbVersion < 0) {
|
|
return 0;
|
|
} else {
|
|
return dbVersion;
|
|
}
|
|
},
|
|
wrapException: function (exception, method) {
|
|
return {
|
|
code: exception.code,
|
|
severity: linq2indexedDB.prototype.utilities.severity.exception,
|
|
orignialError: exception,
|
|
method: method,
|
|
type: "unknown"
|
|
};
|
|
},
|
|
wrapError: function (error, method) {
|
|
return {
|
|
severity: linq2indexedDB.prototype.utilities.severity.error,
|
|
orignialError: error,
|
|
type: (error.target && error.target.error && error.target.error.name) ? error.target.error.name : "unknown",
|
|
method: method
|
|
};
|
|
}
|
|
};
|
|
|
|
linq2indexedDB.prototype.core = {
|
|
db: function (name, version) {
|
|
return linq2indexedDB.prototype.utilities.promiseWrapper(function (pw) {
|
|
internal.db(pw, name, version);
|
|
});
|
|
},
|
|
transaction: function (db, objectStoreNames, transactionType, autoGenerateAllowed) {
|
|
return linq2indexedDB.prototype.utilities.promiseWrapper(function (pw) {
|
|
if (db.then) {
|
|
db.then(function (args /*db, e*/) {
|
|
// Timeout necessary for letting it work on win8. If not, progress event triggers before listeners are coupled
|
|
if (isMetroApp) {
|
|
setTimeout(function () {
|
|
internal.transaction(pw, args[0], objectStoreNames, transactionType, autoGenerateAllowed);
|
|
}, 1);
|
|
} else {
|
|
internal.transaction(pw, args[0], objectStoreNames, transactionType, autoGenerateAllowed);
|
|
}
|
|
},
|
|
function (args /*error, e*/) {
|
|
pw.error(this, args);
|
|
},
|
|
function (args /**/) {
|
|
pw.progress(this, args);
|
|
});
|
|
} else {
|
|
if (isMetroApp) {
|
|
// Timeout necessary for letting it work on win8. If not, progress event triggers before listeners are coupled
|
|
setTimeout(function() {
|
|
internal.transaction(pw, db, objectStoreNames, transactionType, autoGenerateAllowed);
|
|
}, 1);
|
|
} else {
|
|
internal.transaction(pw, db, objectStoreNames, transactionType, autoGenerateAllowed);
|
|
}
|
|
}
|
|
});
|
|
},
|
|
objectStore: function (transaction, objectStoreName) {
|
|
return linq2indexedDB.prototype.utilities.promiseWrapper(function (pw) {
|
|
if (transaction.then) {
|
|
transaction.then(function (/*txn, e*/) {
|
|
// transaction completed
|
|
// TODO: what todo in this case?
|
|
}, function (args /*error, e*/) {
|
|
pw.error(this, args);
|
|
}, function (args /*txn, e*/) {
|
|
internal.objectStore(pw, args[0], objectStoreName);
|
|
});
|
|
} else {
|
|
internal.objectStore(pw, transaction, objectStoreName);
|
|
}
|
|
});
|
|
},
|
|
createObjectStore: function (transaction, objectStoreName, objectStoreOptions) {
|
|
return linq2indexedDB.prototype.utilities.promiseWrapper(function (pw) {
|
|
if (transaction.then) {
|
|
transaction.then(function (/*txn, e*/) {
|
|
// txn completed
|
|
// TODO: what todo in this case?
|
|
},
|
|
function (args /*error, e*/) {
|
|
// txn error or abort
|
|
pw.error(this, args);
|
|
},
|
|
function (args /*txn, e*/) {
|
|
internal.createObjectStore(pw, args[0], objectStoreName, objectStoreOptions);
|
|
});
|
|
} else {
|
|
internal.createObjectStore(pw, transaction, objectStoreName, objectStoreOptions);
|
|
}
|
|
});
|
|
},
|
|
deleteObjectStore: function (transaction, objectStoreName) {
|
|
return linq2indexedDB.prototype.utilities.promiseWrapper(function (pw) {
|
|
if (transaction.then) {
|
|
transaction.then(function (/*txn, e*/) {
|
|
// txn completed
|
|
// TODO: what todo in this case?
|
|
}, function (args /*error, e*/) {
|
|
// txn error
|
|
pw.error(this, args);
|
|
},
|
|
function (args /*txn, e*/) {
|
|
internal.deleteObjectStore(pw, args[0], objectStoreName);
|
|
});
|
|
} else {
|
|
internal.deleteObjectStore(pw, transaction, objectStoreName);
|
|
}
|
|
});
|
|
},
|
|
index: function (objectStore, propertyName, autoGenerateAllowed) {
|
|
return linq2indexedDB.prototype.utilities.promiseWrapper(function (pw) {
|
|
if (objectStore.then) {
|
|
objectStore.then(function (args /*txn, objectStore*/) {
|
|
internal.index(pw, args[1], propertyName, autoGenerateAllowed);
|
|
}, function (args /*error, e*/) {
|
|
// store error
|
|
pw.error(this, args);
|
|
});
|
|
} else {
|
|
internal.index(pw, objectStore, propertyName, autoGenerateAllowed);
|
|
}
|
|
});
|
|
},
|
|
createIndex: function (objectStore, propertyName, indexOptions) {
|
|
return linq2indexedDB.prototype.utilities.promiseWrapper(function (pw) {
|
|
if (objectStore.then) {
|
|
objectStore.then(function (args/*txn, objectStore*/) {
|
|
internal.createIndex(pw, args[1], propertyName, indexOptions);
|
|
}, function (args /*error, e*/) {
|
|
// store error
|
|
pw.error(this, args);
|
|
});
|
|
} else {
|
|
internal.createIndex(pw, objectStore, propertyName, indexOptions);
|
|
}
|
|
});
|
|
},
|
|
deleteIndex: function (objectStore, propertyName) {
|
|
return linq2indexedDB.prototype.utilities.promiseWrapper(function (pw) {
|
|
if (objectStore.then) {
|
|
objectStore.then(function (args/*txn, objectStore*/) {
|
|
internal.deleteIndex(pw, args[1], propertyName);
|
|
}, function (args /*error, e*/) {
|
|
// store error
|
|
pw.error(this, args);
|
|
});
|
|
} else {
|
|
internal.deleteIndex(pw, objectStore, propertyName);
|
|
}
|
|
});
|
|
},
|
|
cursor: function (source, range, direction) {
|
|
return linq2indexedDB.prototype.utilities.promiseWrapper(function (pw) {
|
|
if (source.then) {
|
|
source.then(function (args /*txn, source*/) {
|
|
internal.cursor(pw, args[1], range, direction);
|
|
}, function (args /*error, e*/) {
|
|
// store or index error
|
|
pw.error(this, args);
|
|
});
|
|
} else {
|
|
internal.cursor(pw, source, range, direction);
|
|
}
|
|
});
|
|
},
|
|
keyCursor: function (index, range, direction) {
|
|
return linq2indexedDB.prototype.utilities.promiseWrapper(function (pw) {
|
|
if (index.then) {
|
|
index.then(function (args /*txn, index, store*/) {
|
|
internal.keyCursor(pw, args[1], range, direction);
|
|
}, function (args /*error, e*/) {
|
|
// index error
|
|
pw.error(this, args);
|
|
});
|
|
} else {
|
|
internal.keyCursor(pw, index, range, direction);
|
|
}
|
|
});
|
|
},
|
|
get: function (source, key) {
|
|
return linq2indexedDB.prototype.utilities.promiseWrapper(function (pw) {
|
|
if (source.then) {
|
|
source.then(function (args /*txn, source*/) {
|
|
internal.get(pw, args[1], key);
|
|
}, function (args /*error, e*/) {
|
|
// store or index error
|
|
pw.error(this, args);
|
|
});
|
|
} else {
|
|
internal.get(pw, source, key);
|
|
}
|
|
});
|
|
},
|
|
count: function (source) {
|
|
return linq2indexedDB.prototype.utilities.promiseWrapper(function (pw) {
|
|
if (source.then) {
|
|
source.then(function (args /*txn, source*/) {
|
|
internal.count(pw, args[1]);
|
|
}, function (args /*error, e*/) {
|
|
// store or index error
|
|
pw.error(this, args);
|
|
});
|
|
} else {
|
|
internal.count(pw, source);
|
|
}
|
|
});
|
|
},
|
|
getKey: function (index, key) {
|
|
return linq2indexedDB.prototype.utilities.promiseWrapper(function (pw) {
|
|
if (index.then) {
|
|
index.then(function (args /*txn, index, objectStore*/) {
|
|
internal.getKey(pw, args[1], key);
|
|
}, function (args /*error, e*/) {
|
|
// index error
|
|
pw.error(this, args);
|
|
});
|
|
} else {
|
|
internal.getKey(pw, index, key);
|
|
}
|
|
});
|
|
},
|
|
insert: function (objectStore, data, key) {
|
|
return linq2indexedDB.prototype.utilities.promiseWrapper(function (pw) {
|
|
if (objectStore.then) {
|
|
objectStore.then(function (args /*txn, store*/) {
|
|
internal.insert(pw, args[1], data, key);
|
|
}, function (args /*error, e*/) {
|
|
// store error
|
|
pw.error(this, args);
|
|
});
|
|
} else {
|
|
internal.insert(pw, objectStore, data, key);
|
|
}
|
|
});
|
|
},
|
|
update: function (objectStore, data, key) {
|
|
return linq2indexedDB.prototype.utilities.promiseWrapper(function (pw) {
|
|
if (objectStore.then) {
|
|
objectStore.then(function (args /*txn, store*/) {
|
|
internal.update(pw, args[1], data, key);
|
|
}, function (args /*error, e*/) {
|
|
// store error
|
|
pw.error(this, args);
|
|
});
|
|
} else {
|
|
internal.update(pw, objectStore, data, key);
|
|
}
|
|
});
|
|
},
|
|
remove: function (objectStore, key) {
|
|
return linq2indexedDB.prototype.utilities.promiseWrapper(function (pw) {
|
|
if (objectStore.then) {
|
|
objectStore.then(function (args /*txn, store*/) {
|
|
internal.remove(pw, args[1], key);
|
|
}, function (args /*error, e*/) {
|
|
// store error
|
|
pw.error(this, args);
|
|
});
|
|
} else {
|
|
internal.remove(pw, objectStore, key);
|
|
}
|
|
});
|
|
},
|
|
clear: function (objectStore) {
|
|
return linq2indexedDB.prototype.utilities.promiseWrapper(function (pw) {
|
|
if (objectStore.then) {
|
|
objectStore.then(function (args /*txn, store*/) {
|
|
internal.clear(pw, args[1]);
|
|
}, function (args /*error, e*/) {
|
|
// store error
|
|
pw.error(this, args);
|
|
});
|
|
} else {
|
|
internal.clear(pw, objectStore);
|
|
}
|
|
});
|
|
},
|
|
deleteDb: function (name) {
|
|
return linq2indexedDB.prototype.utilities.promiseWrapper(function (pw) {
|
|
internal.deleteDb(pw, name);
|
|
});
|
|
},
|
|
closeDatabaseConnection: function (target) {
|
|
var db;
|
|
if (target instanceof IDBCursor) {
|
|
target = target.source;
|
|
}
|
|
|
|
if (target instanceof IDBDatabase) {
|
|
db = target;
|
|
} else if (target instanceof IDBTransaction) {
|
|
db = target.db;
|
|
} else if (target instanceof IDBObjectStore || target instanceof IDBRequest) {
|
|
db = target.transaction.db;
|
|
} else if (target instanceof IDBIndex) {
|
|
db = target.objectStore.transaction.db;
|
|
}
|
|
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Close database Connection: ", db);
|
|
db.close();
|
|
},
|
|
abortTransaction: function (transaction) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Abort transaction: " + transaction);
|
|
// Calling the abort, blocks the database in IE10
|
|
if (implementation != implementations.MICROSOFT) {
|
|
transaction.abort();
|
|
linq2indexedDB.prototype.core.closeDatabaseConnection(transaction);
|
|
}
|
|
},
|
|
transactionTypes: transactionTypes,
|
|
dbStructureChanged: new eventTarget(),
|
|
dbDataChanged: new eventTarget(),
|
|
databaseEvents: dbEvents,
|
|
dataEvents: dataEvents,
|
|
implementation: implementation,
|
|
implementations: implementations
|
|
};
|
|
|
|
if (implementation == implementations.SHIM) {
|
|
linq2indexedDB.prototype.core.indexSuffix = "IIndex";
|
|
} else {
|
|
|
|
linq2indexedDB.prototype.core.indexSuffix = "-Index";
|
|
}
|
|
|
|
// Region Functions
|
|
|
|
function initializeIndexedDb() {
|
|
if (window === 'undefined') {
|
|
return implementations.NONE;
|
|
}
|
|
|
|
if (window.indexedDB) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Native implementation", window.indexedDB);
|
|
return implementations.NATIVE;
|
|
} else {
|
|
// Initialising the window.indexedDB Object for FireFox
|
|
if (window.mozIndexedDB) {
|
|
window.indexedDB = window.mozIndexedDB;
|
|
|
|
if (typeof window.IDBTransaction.READ_ONLY === "number"
|
|
&& typeof window.IDBTransaction.READ_WRITE === "number"
|
|
&& typeof window.IDBTransaction.VERSION_CHANGE === "number") {
|
|
transactionTypes.READ_ONLY = window.IDBTransaction.READ_ONLY;
|
|
transactionTypes.READ_WRITE = window.IDBTransaction.READ_WRITE;
|
|
transactionTypes.VERSION_CHANGE = window.IDBTransaction.VERSION_CHANGE;
|
|
}
|
|
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "FireFox Initialized", window.indexedDB);
|
|
return implementations.MOZILLA;
|
|
}
|
|
|
|
// Initialising the window.indexedDB Object for Chrome
|
|
else if (window.webkitIndexedDB) {
|
|
if (!window.indexedDB) window.indexedDB = window.webkitIndexedDB;
|
|
if (!window.IDBCursor) window.IDBCursor = window.webkitIDBCursor;
|
|
if (!window.IDBDatabase) window.IDBDatabase = window.webkitIDBDatabase; //if (!window.IDBDatabaseError) window.IDBDatabaseError = window.webkitIDBDatabaseError
|
|
if (!window.IDBDatabaseException) window.IDBDatabaseException = window.webkitIDBDatabaseException;
|
|
if (!window.IDBFactory) window.IDBFactory = window.webkitIDBFactory;
|
|
if (!window.IDBIndex) window.IDBIndex = window.webkitIDBIndex;
|
|
if (!window.IDBKeyRange) window.IDBKeyRange = window.webkitIDBKeyRange;
|
|
if (!window.IDBObjectStore) window.IDBObjectStore = window.webkitIDBObjectStore;
|
|
if (!window.IDBRequest) window.IDBRequest = window.webkitIDBRequest;
|
|
if (!window.IDBTransaction) window.IDBTransaction = window.webkitIDBTransaction;
|
|
if (!window.IDBOpenDBRequest) window.IDBOpenDBRequest = window.webkitIDBOpenDBRequest;
|
|
if (typeof window.IDBTransaction.READ_ONLY === "number"
|
|
&& typeof window.IDBTransaction.READ_WRITE === "number"
|
|
&& typeof window.IDBTransaction.VERSION_CHANGE === "number") {
|
|
transactionTypes.READ_ONLY = window.IDBTransaction.READ_ONLY;
|
|
transactionTypes.READ_WRITE = window.IDBTransaction.READ_WRITE;
|
|
transactionTypes.VERSION_CHANGE = window.IDBTransaction.VERSION_CHANGE;
|
|
}
|
|
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Chrome Initialized", window.indexedDB);
|
|
return implementations.GOOGLE;
|
|
}
|
|
|
|
// Initialiseing the window.indexedDB Object for IE 10 preview 3+
|
|
else if (window.msIndexedDB) {
|
|
window.indexedDB = window.msIndexedDB;
|
|
|
|
transactionTypes.READ_ONLY = 0;
|
|
transactionTypes.READ_WRITE = 1;
|
|
transactionTypes.VERSION_CHANGE = 2;
|
|
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "IE10+ Initialized", window.indexedDB);
|
|
return implementations.MICROSOFT;
|
|
}
|
|
|
|
// Initialising the window.indexedDB Object for IE 8 & 9
|
|
else if (navigator.appName == 'Microsoft Internet Explorer') {
|
|
try {
|
|
window.indexedDB = new ActiveXObject("SQLCE.Factory.4.0");
|
|
window.indexedDBSync = new ActiveXObject("SQLCE.FactorySync.4.0");
|
|
} catch (ex) {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Initializing IE prototype exception", ex);
|
|
}
|
|
|
|
if (window.JSON) {
|
|
window.indexedDB.json = window.JSON;
|
|
window.indexedDBSync.json = window.JSON;
|
|
} else {
|
|
var jsonObject = {
|
|
parse: function (txt) {
|
|
if (txt === "[]") return [];
|
|
if (txt === "{}") return {};
|
|
throw { message: "Unrecognized JSON to parse: " + txt };
|
|
}
|
|
};
|
|
window.indexedDB.json = jsonObject;
|
|
window.indexedDBSync.json = jsonObject;
|
|
}
|
|
|
|
// Add some interface-level constants and methods.
|
|
window.IDBDatabaseException = {
|
|
UNKNOWN_ERR: 0,
|
|
NON_TRANSIENT_ERR: 1,
|
|
NOT_FOUND_ERR: 2,
|
|
CONSTRAINT_ERR: 3,
|
|
DATA_ERR: 4,
|
|
NOT_ALLOWED_ERR: 5,
|
|
SERIAL_ERR: 11,
|
|
RECOVERABLE_ERR: 21,
|
|
TRANSIENT_ERR: 31,
|
|
TIMEOUT_ERR: 32,
|
|
DEADLOCK_ERR: 33
|
|
};
|
|
|
|
window.IDBKeyRange = {
|
|
SINGLE: 0,
|
|
LEFT_OPEN: 1,
|
|
RIGHT_OPEN: 2,
|
|
LEFT_BOUND: 4,
|
|
RIGHT_BOUND: 8
|
|
};
|
|
|
|
window.IDBRequest = {
|
|
INITIAL: 0,
|
|
LOADING: 1,
|
|
DONE: 2
|
|
};
|
|
|
|
window.IDBTransaction = {
|
|
READ_ONLY: 0,
|
|
READ_WRITE: 1,
|
|
VERSION_CHANGE: 2
|
|
};
|
|
|
|
transactionTypes.READ_ONLY = 0;
|
|
transactionTypes.READ_WRITE = 1;
|
|
transactionTypes.VERSION_CHANGE = 2;
|
|
|
|
window.IDBKeyRange.only = function (value) {
|
|
return window.indexedDB.range.only(value);
|
|
};
|
|
|
|
window.IDBKeyRange.leftBound = function (bound, open) {
|
|
return window.indexedDB.range.lowerBound(bound, open);
|
|
};
|
|
|
|
window.IDBKeyRange.rightBound = function (bound, open) {
|
|
return window.indexedDB.range.upperBound(bound, open);
|
|
};
|
|
|
|
window.IDBKeyRange.bound = function (left, right, openLeft, openRight) {
|
|
return window.indexedDB.range.bound(left, right, openLeft, openRight);
|
|
};
|
|
|
|
window.IDBKeyRange.lowerBound = function (left, openLeft) {
|
|
return window.IDBKeyRange.leftBound(left, openLeft);
|
|
};
|
|
|
|
return implementations.MICROSOFTPROTOTYPE;
|
|
} else if (window.shimIndexedDB) {
|
|
window.indexedDB = window.shimIndexedDB;
|
|
|
|
return implementations.SHIM;
|
|
} else {
|
|
linq2indexedDB.prototype.utilities.log(linq2indexedDB.prototype.utilities.severity.information, "Your browser doesn't support indexedDB.");
|
|
return implementations.NONE;
|
|
}
|
|
}
|
|
};
|
|
|
|
function deferredHandler(handler, request) {
|
|
return linq2indexedDB.prototype.utilities.promiseWrapper(function (pw) {
|
|
try {
|
|
handler(pw, request);
|
|
} catch (e) {
|
|
e.type = "exception";
|
|
pw.error(request, [e.message, e]);
|
|
}
|
|
finally {
|
|
request = null;
|
|
}
|
|
});
|
|
};
|
|
|
|
function IDBSuccessHandler(pw, request) {
|
|
request.onsuccess = function (e) {
|
|
pw.complete(e.target, [e.target.result, e]);
|
|
};
|
|
};
|
|
|
|
function IDBErrorHandler(pw, request) {
|
|
request.onerror = function (e) {
|
|
pw.error(e.target, [e.target.errorCode, e]);
|
|
};
|
|
};
|
|
|
|
function IDBAbortHandler(pw, request) {
|
|
request.onabort = function (e) {
|
|
pw.error(e.target, [e.target.errorCode, e]);
|
|
};
|
|
};
|
|
|
|
function IDBVersionChangeHandler(pw, request) {
|
|
request.onversionchange = function (e) {
|
|
pw.progress(e.target, [e.target.result, e]);
|
|
};
|
|
};
|
|
|
|
function IDBCompleteHandler(pw, request) {
|
|
request.oncomplete = function (e) {
|
|
pw.complete(e.target, [e.target, e]);
|
|
};
|
|
};
|
|
|
|
function IDBRequestHandler(pw, request) {
|
|
IDBSuccessHandler(pw, request);
|
|
IDBErrorHandler(pw, request);
|
|
};
|
|
|
|
function IDBCursorRequestHandler(pw, request) {
|
|
request.onsuccess = function (e) {
|
|
if (!e.target.result) {
|
|
pw.complete(e.target, [e.target.result, e]);
|
|
} else {
|
|
pw.progress(e.target, [e.target.result, e]);
|
|
}
|
|
};
|
|
IDBErrorHandler(pw, request);
|
|
};
|
|
|
|
function IDBBlockedRequestHandler(pw, request) {
|
|
IDBRequestHandler(pw, request);
|
|
request.onblocked = function (e) {
|
|
pw.progress(e.target, ["blocked", e]);
|
|
};
|
|
};
|
|
|
|
function IDBOpenDbRequestHandler(pw, request) {
|
|
IDBBlockedRequestHandler(pw, request);
|
|
request.onupgradeneeded = function (e) {
|
|
pw.progress(e.target, [e.target.transaction, e]);
|
|
};
|
|
};
|
|
|
|
function IDBDatabaseHandler(pw, database) {
|
|
IDBAbortHandler(pw, database);
|
|
IDBErrorHandler(pw, database);
|
|
IDBVersionChangeHandler(pw, database);
|
|
};
|
|
|
|
function IDBTransactionHandler(pw, txn) {
|
|
IDBCompleteHandler(pw, txn);
|
|
IDBAbortHandler(pw, txn);
|
|
IDBErrorHandler(pw, txn);
|
|
};
|
|
|
|
})(window, typeof Windows !== "undefined");
|
|
window.linq2indexedDB = linq2indexedDB;
|
|
|
|
} else {
|
|
// Web Worker Thread
|
|
onmessage = function (event) {
|
|
var data = event.data.data;
|
|
var filtersString = event.data.filters || "[]";
|
|
var sortClauses = event.data.sortClauses || [];
|
|
var filters = JSON.parse(filtersString, linq2indexedDB.prototype.utilities.deserialize);
|
|
var returnData = linq2indexedDB.prototype.utilities.filterSort(data, filters, sortClauses);
|
|
|
|
postMessage(returnData);
|
|
return;
|
|
};
|
|
}
|
|
|
|
// Extend array for Opera
|
|
//Array.prototype.contains = function (obj) {
|
|
// return this.indexOf(obj) > -1;
|
|
//};
|