Files
grin-web-wallet/scripts/database.js
2024-12-20 18:08:44 -08:00

1759 lines
43 KiB
JavaScript
Executable File

// Use strict
"use strict";
// Classes
// Database class
class Database {
// Public
// Initialize
static initialize() {
// Set instance to invalid
Database.instance = Database.INVALID;
// Set object store locks
Database.objectStoreLocks = new Set();
// Set object store unlock event index
Database.objectStoreUnlockEventIndex = 0;
// Return promise
return new Promise(function(resolve, reject) {
// Try
try {
// Request database
var databaseRequest = indexedDB.open(Database.NAME, Database.VERSION);
}
// Catch errors
catch(error) {
// Reject error
reject("Failed to create and/or open database.");
// Return
return;
}
// Database request on error
databaseRequest["onerror"] = function() {
// Reject
reject();
};
// Database request on upgrade needed
databaseRequest["onupgradeneeded"] = function(event) {
// Get database
var database = event["target"]["result"];
// Get database transaction
var databaseTransaction = event["target"]["transaction"];
// Get current version
var currentVersion = event["oldVersion"];
// Database on error
database["onerror"] = function() {
// Reject
reject();
};
// Check if new databases exists
if(typeof Database.newDatabases !== "undefined") {
// Go through all new databases
for(var i = 0; i < Database.newDatabases["length"]; ++i)
// Create new database
Database.newDatabases[i](database, currentVersion, databaseTransaction);
}
};
// Database request on success
databaseRequest["onsuccess"] = function(event) {
// Set instance
Database.instance = event["target"]["result"];
// Check if critical initialization functions don't exist
if(typeof Database.criticalInitializationFunctions === "undefined")
// Create critical initialzation functions
Database.criticalInitializationFunctions = [];
// Run all critical initialization functions
Promise.all(Database.criticalInitializationFunctions.map(function(criticalInitializationFunction) {
// Return performing critical initialization function
return criticalInitializationFunction();
})).then(function() {
// Check if initialization functions don't exist
if(typeof Database.initializationFunctions === "undefined")
// Create initialization functions
Database.initializationFunctions = [];
// Run all initialization functions
Promise.all(Database.initializationFunctions.map(function(initializationFunction) {
// Return performing initialization function
return initializationFunction();
})).then(function() {
// Resolve
resolve();
// Catch errors
}).catch(function(error) {
// Reject
reject();
});
// Catch errors
}).catch(function(error) {
// Reject
reject();
});
};
});
}
// Create database
static createDatabase(newDatabase) {
// Check if new databases don't exist
if(typeof Database.newDatabases === "undefined")
// Create new databases
Database.newDatabases = [];
// Append new database to list
Database.newDatabases.push(newDatabase);
}
// Once initialized
static onceInitialized(initializationFunction, isCritical = false) {
// Check if critical
if(isCritical === true) {
// Check if critical initialization functions don't exist
if(typeof Database.criticalInitializationFunctions === "undefined")
// Create critical initialization functions
Database.criticalInitializationFunctions = [];
// Append critical initialization function to list
Database.criticalInitializationFunctions.push(initializationFunction);
}
// Otherwise
else {
// Check if initialization functions don't exist
if(typeof Database.initializationFunctions === "undefined")
// Create initialization functions
Database.initializationFunctions = [];
// Append initialization function to list
Database.initializationFunctions.push(initializationFunction);
}
}
// Create transaction
static createTransaction(objectStoreNames, type = Database.READ_MODE, durability = Database.RELAXED_DURABILITY, autocomplete = true) {
// Check if object stores names isn't an array
if(Array.isArray(objectStoreNames) === false) {
// Make object store names an array
objectStoreNames = [objectStoreNames];
}
// Initialize locked object stores
var lockedObjectStores = [];
// Return promise
return new Promise(function(resolve, reject) {
// Return locking all specified object stores
return Promise.all(objectStoreNames.map(function(objectStoreName) {
// Return promise
return new Promise(function(resolve, reject) {
// Check if object store is locked
if(Database.objectStoreLocks.has(objectStoreName) === true) {
// Get current unlock event index
var index = Database.objectStoreUnlockEventIndex++;
// Check if current unlock event index is at the max safe integer
if(index === Number.MAX_SAFE_INTEGER)
// Reset unlock event index
Database.objectStoreUnlockEventIndex = 0;
// Database object store unlock index event
$(Database.instance).on(Database.OBJECT_STORE_UNLOCK_EVENT + "." + index.toFixed(), function(event, unlockedObjectStoreName) {
// Check if object store is unlocked
if(objectStoreName === unlockedObjectStoreName && Database.objectStoreLocks.has(objectStoreName) === false) {
// Turn off database object store unlock index event
$(Database.instance).off(Database.OBJECT_STORE_UNLOCK_EVENT + "." + index.toFixed());
// Lock object store
Database.objectStoreLocks.add(objectStoreName);
// Append locked object store to list
lockedObjectStores.push(objectStoreName);
// Resolve
resolve();
}
});
}
// Otherwise
else {
// Lock object store
Database.objectStoreLocks.add(objectStoreName);
// Append locked object store to list
lockedObjectStores.push(objectStoreName);
// Resolve
resolve();
}
});
})).then(function() {
// Try
try {
// Create transaction
var transaction = Database.instance.transaction(objectStoreNames, type, {
// Durability
"durability": durability
});
}
// Catch errors
catch(error) {
// Go through all locked object stores
for(var i = 0; i < lockedObjectStores["length"]; ++i) {
// Get object store
var objectStoreName = lockedObjectStores[i];
// Check if object store is locked
if(Database.objectStoreLocks.has(objectStoreName) === true) {
// Unlock object store
Database.objectStoreLocks.delete(objectStoreName);
// Trigger object store unlock event
$(Database.instance).trigger(Database.OBJECT_STORE_UNLOCK_EVENT, objectStoreName);
}
}
// Reject
reject();
// Return
return;
}
// Check if autocomplete
if(autocomplete === true) {
// Transaction complete, abort, or error event
$(transaction).on("complete abort error", function() {
// Unlock locked object stores
Database.unlockObjectStores(lockedObjectStores);
});
}
// Create database transaction
var databaseTransaction = new DatabaseTransaction(transaction, lockedObjectStores, autocomplete);
// Resolve database transaction
resolve(databaseTransaction);
});
});
}
// Commit transaction
static commitTransaction(transaction) {
// Return promise
return new Promise(function(resolve, reject) {
// Check if transaction is completed
if(transaction.isCompleted() === true) {
// Check if transaction isn't autocomplete
if(transaction.getAutocomplete() === false) {
// Unlock transaction's object stores
Database.unlockObjectStores(transaction.getObjectStoreNames());
}
// Resolve
resolve();
}
// Otherwise check if transaction is aborted
else if(transaction.isAborted() === true) {
// Check if transaction isn't autocomplete
if(transaction.getAutocomplete() === false) {
// Unlock transaction's object stores
Database.unlockObjectStores(transaction.getObjectStoreNames());
}
// Reject
reject();
}
// Otherwise
else {
// Transaction on complete
transaction.getTransaction()["oncomplete"] = function() {
// Check if transaction isn't autocomplete
if(transaction.getAutocomplete() === false) {
// Unlock transaction's object stores
Database.unlockObjectStores(transaction.getObjectStoreNames());
}
// Resolve
resolve();
};
// Transaction on error
transaction.getTransaction()["onerror"] = function() {
// Check if transaction isn't autocomplete
if(transaction.getAutocomplete() === false) {
// Unlock transaction's object stores
Database.unlockObjectStores(transaction.getObjectStoreNames());
}
// Reject
reject();
};
// Transaction on abort
transaction.getTransaction()["onabort"] = function() {
// Check if transaction isn't autocomplete
if(transaction.getAutocomplete() === false) {
// Unlock transaction's object stores
Database.unlockObjectStores(transaction.getObjectStoreNames());
}
// Reject
reject();
};
// Try
try {
// Commit transaction
transaction.getTransaction().commit();
}
// Catch errors
catch(error) {
}
}
});
}
// Cancel transaction
static abortTransaction(transaction) {
// Return promise
return new Promise(function(resolve, reject) {
// Check if transaction is aborted
if(transaction.isAborted() === true) {
// Check if transaction isn't autocomplete
if(transaction.getAutocomplete() === false) {
// Unlock transaction's object stores
Database.unlockObjectStores(transaction.getObjectStoreNames());
}
// Resolve
resolve();
}
// Otherwise check if transaction is completed
else if(transaction.isCompleted() === true) {
// Check if transaction isn't autocomplete
if(transaction.getAutocomplete() === false) {
// Unlock transaction's object stores
Database.unlockObjectStores(transaction.getObjectStoreNames());
}
// Reject
reject();
}
// Otherwise
else {
// Transaction on abort
transaction.getTransaction()["onabort"] = function() {
// Check if transaction isn't autocomplete
if(transaction.getAutocomplete() === false) {
// Unlock transaction's object stores
Database.unlockObjectStores(transaction.getObjectStoreNames());
}
// Resolve
resolve();
};
// Transaction on error
transaction.getTransaction()["onerror"] = function() {
// Check if transaction isn't autocomplete
if(transaction.getAutocomplete() === false) {
// Unlock transaction's object stores
Database.unlockObjectStores(transaction.getObjectStoreNames());
}
// Reject
reject();
};
// Transaction on complete
transaction.getTransaction()["oncomplete"] = function() {
// Check if transaction isn't autocomplete
if(transaction.getAutocomplete() === false) {
// Unlock transaction's object stores
Database.unlockObjectStores(transaction.getObjectStoreNames());
}
// Reject
reject();
};
// Try
try {
// Abort transaction
transaction.getTransaction().abort();
}
// Catch errors
catch(error) {
}
}
});
}
// Get count
static getCount(objectStoreName, index = Database.NO_INDEX, range = Database.NO_RANGE, transaction = Database.CREATE_NEW_TRANSACTION) {
// Return promise
return new Promise(function(resolve, reject) {
// Check if instance is invalid
if(Database.instance === Database.INVALID) {
// Reject error
reject("Invalid database.");
// Return
return;
}
// Initialize count
var count;
// Get if creating a new transaction
var createNewTransaction = transaction === Database.CREATE_NEW_TRANSACTION;
// Get current transaction
var getCurrentTransaction = new Promise(function(resolve, reject) {
// Check if creating a new transaction
if(createNewTransaction === true) {
// Return creating a transaction
return Database.createTransaction(objectStoreName, Database.READ_MODE).then(function(transaction) {
// Resolve transaction
resolve(transaction);
// Catch error
}).catch(function(error) {
// Reject error
reject(error);
});
}
// Otherwise
else {
// Resolve transaction
resolve(transaction);
}
});
// Return getting current transaction
return getCurrentTransaction.then(function(currentTransaction) {
// Check if creating a new transaction
if(createNewTransaction === true) {
// Current transaction on complete
currentTransaction.getTransaction()["oncomplete"] = function() {
// Resolve count
resolve(count);
};
}
// Current transaction on error
currentTransaction.getTransaction()["onerror"] = function(error) {
// Reject
reject();
};
// Current transaction on abort
currentTransaction.getTransaction()["onabort"] = function() {
// Reject
reject();
};
// Get the object store
var objectStore = currentTransaction.getTransaction().objectStore(objectStoreName);
// Create count request to get count from the object store
var countRequest = (index === Database.NO_INDEX) ? objectStore.count(range) : objectStore.index(index).count(range);
// Count request on success
countRequest["onsuccess"] = function(event) {
// Get result
var result = event["target"]["result"];
// Get count from result
count = result;
// Check if not creating a new transaction
if(createNewTransaction === false)
// Resolve count
resolve(count);
};
// Catch errors
}).catch(function(error) {
// Reject
reject();
});
});
}
// Get key paths
static getKeyPaths(objectStoreName, transaction = Database.CREATE_NEW_TRANSACTION) {
// Return promise
return new Promise(function(resolve, reject) {
// Check if instance is invalid
if(Database.instance === Database.INVALID) {
// Reject error
reject("Invalid database.");
// Return
return;
}
// Initialize key paths
var keyPaths = [];
// Get if creating a new transaction
var createNewTransaction = transaction === Database.CREATE_NEW_TRANSACTION;
// Get current transaction
var getCurrentTransaction = new Promise(function(resolve, reject) {
// Check if creating a new transaction
if(createNewTransaction === true) {
// Return creating a transaction
return Database.createTransaction(objectStoreName, Database.READ_MODE).then(function(transaction) {
// Resolve transaction
resolve(transaction);
// Catch error
}).catch(function(error) {
// Reject error
reject(error);
});
}
// Otherwise
else {
// Resolve transaction
resolve(transaction);
}
});
// Return getting current transaction
return getCurrentTransaction.then(function(currentTransaction) {
// Check if creating a new transaction
if(createNewTransaction === true) {
// Current transaction on complete
currentTransaction.getTransaction()["oncomplete"] = function() {
// Resolve key paths
resolve(keyPaths);
};
}
// Current transaction on error
currentTransaction.getTransaction()["onerror"] = function() {
// Reject
reject();
};
// Current transaction on abort
currentTransaction.getTransaction()["onabort"] = function() {
// Reject
reject();
};
// Create key cursor request to read from the object store
var keyCursorRequest = currentTransaction.getTransaction().objectStore(objectStoreName).openKeyCursor();
// Key cursor request on success
keyCursorRequest["onsuccess"] = function(event) {
// Get result
var result = event["target"]["result"];
// Check if result exists
if(result !== Database.NO_RECORDS_MATCH_CURSOR_RESULT) {
// Get key path from result
var keyPath = result["key"];
// Append key path to key paths
keyPaths.push(result["key"]);
// Get next result
result.continue();
}
// Otherwise check if not creating a new transaction
else if(createNewTransaction === false)
// Resolve key paths
resolve(keyPaths);
};
// Catch errors
}).catch(function(error) {
// Reject
reject();
});
});
}
// Get results
static getResults(objectStoreName, startPosition = Database.GET_ALL_RESULTS, count = Database.GET_ALL_RESULTS, index = Database.NO_INDEX, range = Database.NO_RANGE, direction = Database.FORWARD_DIRECTION, transaction = Database.CREATE_NEW_TRANSACTION) {
// Return promise
return new Promise(function(resolve, reject) {
// Check if instance is invalid
if(Database.instance === Database.INVALID) {
// Reject error
reject("Invalid database.");
// Return
return;
}
// Check if start position or count is invalid
if(startPosition < 0 || count < 0) {
// Reject error
reject("Invalid parameters.");
// Return
return;
}
// Initialize results
var results = [];
// Check if count is zero
if(count === 0) {
// Resolve results
resolve(results);
// Return
return;
}
// Get if creating a new transaction
var createNewTransaction = transaction === Database.CREATE_NEW_TRANSACTION;
// Get current transaction
var getCurrentTransaction = new Promise(function(resolve, reject) {
// Check if creating a new transaction
if(createNewTransaction === true) {
// Return creating a transaction
return Database.createTransaction(objectStoreName, Database.READ_MODE).then(function(transaction) {
// Resolve transaction
resolve(transaction);
// Catch error
}).catch(function(error) {
// Reject error
reject(error);
});
}
// Otherwise
else {
// Resolve transaction
resolve(transaction);
}
});
// Return getting current transaction
return getCurrentTransaction.then(function(currentTransaction) {
// Check if creating a new transaction
if(createNewTransaction === true) {
// Current transaction on complete
currentTransaction.getTransaction()["oncomplete"] = function() {
// Resolve results
resolve(results);
};
}
// Current transaction on error
currentTransaction.getTransaction()["onerror"] = function() {
// Reject
reject();
};
// Current transaction on abort
currentTransaction.getTransaction()["onabort"] = function() {
// Reject
reject();
};
// Get the object store
var objectStore = currentTransaction.getTransaction().objectStore(objectStoreName);
// Create cursor request to read from the object store
var cursorRequest = (index === Database.NO_INDEX) ? objectStore.openKeyCursor(range, direction) : objectStore.index(index).openKeyCursor(range, direction);
// Cursor request on success
var firstResult = true;
cursorRequest["onsuccess"] = function(event) {
// Get result
var result = event["target"]["result"];
// Check if result exists
if(result !== Database.NO_RECORDS_MATCH_CURSOR_RESULT) {
// Check if at the first result
if(firstResult === true) {
// Clear first result
firstResult = false;
// Check if a start position is provided and it's not zero
if(startPosition !== Database.GET_ALL_RESULTS && startPosition !== 0) {
// Advance result to start position
result.advance(startPosition);
// Return
return;
}
}
// Get key path from result
var keyPath = result["primaryKey"];
// Create get request to read from the object store using the key path
var getRequest = objectStore.get(keyPath);
// Get request on success
getRequest["onsuccess"] = function(event) {
// Get request's result
var requestsResult = event["target"]["result"];
// Check if request's result exists
if(requestsResult !== Database.NO_RECORDS_MATCH_GET_RESULT) {
// Set key path in result
requestsResult[Database.KEY_PATH_NAME] = keyPath;
// Append result to results
results.push(requestsResult);
}
// Check if not creating a new transaction, a count is provided, and it's currently at the count
if(createNewTransaction === false && count !== Database.GET_ALL_RESULTS && count === 0)
// Resolve results
resolve(results);
};
// Check if a count isn't provided and currently not at the count
if(count === Database.GET_ALL_RESULTS || --count > 0)
// Get next result
result.continue();
}
// Otherwise check if not creating a new transaction
else if(createNewTransaction === false)
// Resolve results
resolve(results);
};
// Catch errors
}).catch(function(error) {
// Reject
reject();
});
});
}
// Get result
static getResult(objectStoreName, keyPath, transaction = Database.CREATE_NEW_TRANSACTION) {
// Return promise
return new Promise(function(resolve, reject) {
// Check if instance is invalid
if(Database.instance === Database.INVALID) {
// Reject error
reject("Invalid database.");
// Return
return;
}
// Initialize result
var result = Database.RESULT_NOT_FOUND;
// Get if creating a new transaction
var createNewTransaction = transaction === Database.CREATE_NEW_TRANSACTION;
// Get current transaction
var getCurrentTransaction = new Promise(function(resolve, reject) {
// Check if creating a new transaction
if(createNewTransaction === true) {
// Return creating a transaction
return Database.createTransaction(objectStoreName, Database.READ_MODE).then(function(transaction) {
// Resolve transaction
resolve(transaction);
// Catch error
}).catch(function(error) {
// Reject error
reject(error);
});
}
// Otherwise
else {
// Resolve transaction
resolve(transaction);
}
});
// Return getting current transaction
return getCurrentTransaction.then(function(currentTransaction) {
// Check if creating a new transaction
if(createNewTransaction === true) {
// Current transaction on complete
currentTransaction.getTransaction()["oncomplete"] = function() {
// Resolve result
resolve(result);
};
}
// Current transaction on error
currentTransaction.getTransaction()["onerror"] = function() {
// Reject
reject();
};
// Current transaction on abort
currentTransaction.getTransaction()["onabort"] = function() {
// Reject
reject();
};
// Create get request to read from the object store using the key path
var getRequest = currentTransaction.getTransaction().objectStore(objectStoreName).get(keyPath);
// Get request on success
getRequest["onsuccess"] = function(event) {
// Get request's result
var requestsResult = event["target"]["result"];
// Check if request's result exists
if(requestsResult !== Database.NO_RECORDS_MATCH_GET_RESULT) {
// Set result to request's result
result = requestsResult;
// Set key path in result
result[Database.KEY_PATH_NAME] = keyPath;
}
// Check if not creating a new transaction
if(createNewTransaction === false)
// Resolve result
resolve(result);
};
// Catch errors
}).catch(function(error) {
// Reject
reject();
});
});
}
// Save results
static saveResults(objectStoreName, results, resultsKeyPaths = [], transaction = Database.CREATE_NEW_TRANSACTION, durability = Database.RELAXED_DURABILITY) {
// Return promise
return new Promise(function(resolve, reject) {
// Check if instance is invalid
if(Database.instance === Database.INVALID) {
// Reject error
reject("Invalid database.");
// Return
return;
}
// Initialize new key paths
var newKeyPaths = [];
// Get if creating a new transaction
var createNewTransaction = transaction === Database.CREATE_NEW_TRANSACTION;
// Get current transaction
var getCurrentTransaction = new Promise(function(resolve, reject) {
// Check if creating a new transaction
if(createNewTransaction === true) {
// Return creating a transaction
return Database.createTransaction(objectStoreName, Database.READ_AND_WRITE_MODE, durability).then(function(transaction) {
// Resolve transaction
resolve(transaction);
// Catch error
}).catch(function(error) {
// Reject error
reject(error);
});
}
// Otherwise
else {
// Resolve transaction
resolve(transaction);
}
});
// Return getting current transaction
return getCurrentTransaction.then(function(currentTransaction) {
// Check if creating a new transaction
if(createNewTransaction === true) {
// Current transaction on complete
currentTransaction.getTransaction()["oncomplete"] = function() {
// Resolve new key paths
resolve(newKeyPaths);
};
}
// Current transaction on error
currentTransaction.getTransaction()["onerror"] = function() {
// Reject
reject();
};
// Current transaction on abort
currentTransaction.getTransaction()["onabort"] = function() {
// Reject
reject();
};
// Get the object store
var objectStore = currentTransaction.getTransaction().objectStore(objectStoreName);
// Go through all result
for(var i = 0, j = 0; i < results["length"]; ++i) {
// Check if result includes a key path
if(i < resultsKeyPaths["length"]) {
// Create put request to write to the object store
var putRequest = objectStore.put(results[i], resultsKeyPaths[i]);
}
// Otherwise
else {
// Create put request to write to the object store
var putRequest = objectStore.put(results[i]);
}
// Put request on success
putRequest["onsuccess"] = function(event) {
// Get key path from result
var keyPath = event["target"]["result"];
// Appen key path to list
newKeyPaths.push(keyPath);
// Check if not creating a new transaction
if(createNewTransaction === false) {
// Check if all put requests were completed
if(++j === results["length"])
// Resolve new key paths
resolve(newKeyPaths);
}
};
}
// Catch errors
}).catch(function(error) {
// Reject
reject();
});
});
}
// Save result
static saveResult(objectStoreName, result, keyPath = Database.CREATE_NEW_KEY_PATH, transaction = Database.CREATE_NEW_TRANSACTION, durability = Database.RELAXED_DURABILITY) {
// Return promise
return new Promise(function(resolve, reject) {
// Check if instance is invalid
if(Database.instance === Database.INVALID) {
// Reject error
reject("Invalid database.");
// Return
return;
}
// Initialize new key path
var newKeyPath;
// Get if creating a new transaction
var createNewTransaction = transaction === Database.CREATE_NEW_TRANSACTION;
// Get current transaction
var getCurrentTransaction = new Promise(function(resolve, reject) {
// Check if creating a new transaction
if(createNewTransaction === true) {
// Return creating a transaction
return Database.createTransaction(objectStoreName, Database.READ_AND_WRITE_MODE, durability).then(function(transaction) {
// Resolve transaction
resolve(transaction);
// Catch error
}).catch(function(error) {
// Reject error
reject(error);
});
}
// Otherwise
else {
// Resolve transaction
resolve(transaction);
}
});
// Return getting current transaction
return getCurrentTransaction.then(function(currentTransaction) {
// Check if creating a new transaction
if(createNewTransaction === true) {
// Current transaction on complete
currentTransaction.getTransaction()["oncomplete"] = function() {
// Resolve new key path
resolve(newKeyPath);
};
}
// Current transaction on error
currentTransaction.getTransaction()["onerror"] = function() {
// Reject
reject();
};
// Current transaction on abort
currentTransaction.getTransaction()["onabort"] = function() {
// Reject
reject();
};
// Create put request to write to the object store
var putRequest = currentTransaction.getTransaction().objectStore(objectStoreName).put(result, keyPath);
// Put request on success
putRequest["onsuccess"] = function(event) {
// Get key path from result
var keyPath = event["target"]["result"];
// Set new key path to key path
newKeyPath = keyPath;
// Check if not creating a new transaction
if(createNewTransaction === false)
// Resolve new key path
resolve(newKeyPath);
};
// Catch errors
}).catch(function(error) {
// Reject
reject();
});
});
}
// Delete results
static deleteResults(objectStoreName, transaction = Database.CREATE_NEW_TRANSACTION, durability = Database.RELAXED_DURABILITY) {
// Return promise
return new Promise(function(resolve, reject) {
// Check if instance is invalid
if(Database.instance === Database.INVALID) {
// Reject error
reject("Invalid database.");
// Return
return;
}
// Get if creating a new transaction
var createNewTransaction = transaction === Database.CREATE_NEW_TRANSACTION;
// Get current transaction
var getCurrentTransaction = new Promise(function(resolve, reject) {
// Check if creating a new transaction
if(createNewTransaction === true) {
// Return creating a transaction
return Database.createTransaction(objectStoreName, Database.READ_AND_WRITE_MODE, durability).then(function(transaction) {
// Resolve transaction
resolve(transaction);
// Catch error
}).catch(function(error) {
// Reject error
reject(error);
});
}
// Otherwise
else {
// Resolve transaction
resolve(transaction);
}
});
// Return getting current transaction
return getCurrentTransaction.then(function(currentTransaction) {
// Check if creating a new transaction
if(createNewTransaction === true) {
// Current transaction on complete
currentTransaction.getTransaction()["oncomplete"] = function() {
// Resolve
resolve();
};
}
// Current transaction on error
currentTransaction.getTransaction()["onerror"] = function() {
// Reject
reject();
};
// Current transaction on abort
currentTransaction.getTransaction()["onabort"] = function() {
// Reject
reject();
};
// Create clear request to delete everything from the object store
var clearRequest = currentTransaction.getTransaction().objectStore(objectStoreName).clear();
// Check if not creating a new transaction
if(createNewTransaction === false) {
// Clear request on success
clearRequest["onsuccess"] = function(event) {
// Resolve
resolve();
};
}
// Catch errors
}).catch(function(error) {
// Reject
reject();
});
});
}
// Delete results with value
static deleteResultsWithValue(objectStoreName, index, range, transaction = Database.CREATE_NEW_TRANSACTION, durability = Database.RELAXED_DURABILITY) {
// Return promise
return new Promise(function(resolve, reject) {
// Check if instance is invalid
if(Database.instance === Database.INVALID) {
// Reject error
reject("Invalid database.");
// Return
return;
}
// Get if creating a new transaction
var createNewTransaction = transaction === Database.CREATE_NEW_TRANSACTION;
// Get current transaction
var getCurrentTransaction = new Promise(function(resolve, reject) {
// Check if creating a new transaction
if(createNewTransaction === true) {
// Return creating a transaction
return Database.createTransaction(objectStoreName, Database.READ_AND_WRITE_MODE, durability).then(function(transaction) {
// Resolve transaction
resolve(transaction);
// Catch error
}).catch(function(error) {
// Reject error
reject(error);
});
}
// Otherwise
else {
// Resolve transaction
resolve(transaction);
}
});
// Return getting current transaction
return getCurrentTransaction.then(function(currentTransaction) {
// Check if creating a new transaction
if(createNewTransaction === true) {
// Current transaction on complete
currentTransaction.getTransaction()["oncomplete"] = function() {
// Resolve
resolve();
};
}
// Current transaction on error
currentTransaction.getTransaction()["onerror"] = function() {
// Reject
reject();
};
// Current transaction on abort
currentTransaction.getTransaction()["onabort"] = function() {
// Reject
reject();
};
// Get the object store
var objectStore = currentTransaction.getTransaction().objectStore(objectStoreName);
// Create cursor request to write to the object store
var cursorRequest = objectStore.index(index).openCursor(range);
// Cursor request on success
cursorRequest["onsuccess"] = function(event) {
// Get result
var result = event["target"]["result"];
// Check if result exists
if(result !== Database.NO_RECORDS_MATCH_CURSOR_RESULT) {
// Delete result
result.delete();
// Get next result
result.continue();
}
// Otherwise check if not creating a new transaction
else if(createNewTransaction === false)
// Resolve
resolve();
};
// Catch errors
}).catch(function(error) {
// Reject
reject();
});
});
}
// Delete result
static deleteResult(objectStoreName, keyPath, transaction = Database.CREATE_NEW_TRANSACTION, durability = Database.RELAXED_DURABILITY) {
// Return promise
return new Promise(function(resolve, reject) {
// Check if instance is invalid
if(Database.instance === Database.INVALID) {
// Reject error
reject("Invalid database.");
// Return
return;
}
// Get if creating a new transaction
var createNewTransaction = transaction === Database.CREATE_NEW_TRANSACTION;
// Get current transaction
var getCurrentTransaction = new Promise(function(resolve, reject) {
// Check if creating a new transaction
if(createNewTransaction === true) {
// Return creating a transaction
return Database.createTransaction(objectStoreName, Database.READ_AND_WRITE_MODE, durability).then(function(transaction) {
// Resolve transaction
resolve(transaction);
// Catch error
}).catch(function(error) {
// Reject error
reject(error);
});
}
// Otherwise
else {
// Resolve transaction
resolve(transaction);
}
});
// Return getting current transaction
return getCurrentTransaction.then(function(currentTransaction) {
// Check if creating a new transaction
if(createNewTransaction === true) {
// Current transaction on complete
currentTransaction.getTransaction()["oncomplete"] = function() {
// Resolve
resolve();
};
}
// Current transaction on error
currentTransaction.getTransaction()["onerror"] = function() {
// Reject
reject();
};
// Current transaction on abort
currentTransaction.getTransaction()["onabort"] = function() {
// Reject
reject();
};
// Create delete request to delete from the object store using the key path
var deleteRequest = currentTransaction.getTransaction().objectStore(objectStoreName).delete(keyPath);
// Check if not creating a new transaction
if(createNewTransaction === false) {
// Delete request on success
deleteRequest["onsuccess"] = function(event) {
// Resolve
resolve();
};
}
// Catch errors
}).catch(function(error) {
// Reject
reject();
});
});
}
// To key path
static toKeyPath(string) {
// Return string as a key path
return string.replace(Database.INVALID_KEY_PATH_PATTERN, Database.INVALID_KEY_PATH_REPLACEMENT);
}
// Result not found
static get RESULT_NOT_FOUND() {
// Return result not found
return null;
}
// Create new key path
static get CREATE_NEW_KEY_PATH() {
// Return create new key path
return undefined;
}
// Read mode
static get READ_MODE() {
// Return read mode
return "readonly";
}
// Read and write mode
static get READ_AND_WRITE_MODE() {
// Return read and write mode
return "readwrite";
}
// Key path name
static get KEY_PATH_NAME() {
// Return key path name
return "Key Path";
}
// Get all results
static get GET_ALL_RESULTS() {
// Return get all results
return null;
}
// No index
static get NO_INDEX() {
// Return no index
return null;
}
// Create new transaction
static get CREATE_NEW_TRANSACTION() {
// Return create new transaction
return null;
}
// No range
static get NO_RANGE() {
// Return no range
return null;
}
// Forward direction
static get FORWARD_DIRECTION() {
// Return forward direction
return "next";
}
// Backward direction
static get BACKWARD_DIRECTION() {
// Return backward direction
return "prev";
}
// No current version
static get NO_CURRENT_VERSION() {
// Return no current version
return 0;
}
// Relaxed durability
static get RELAXED_DURABILITY() {
// Return relaxed durability
return "relaxed";
}
// Strict durability
static get STRICT_DURABILITY() {
// Return strict durability
return "strict";
}
// Private
// Unlock object stores
static unlockObjectStores(objectStoreNames) {
// Go through all of the object stores
for(var i = 0; i < objectStoreNames["length"]; ++i) {
// Get object store
let objectStoreName = objectStoreNames[i];
// Check if object store is locked
if(Database.objectStoreLocks.has(objectStoreName) === true) {
// Set timeout
setTimeout(function() {
// Unlock object store
Database.objectStoreLocks.delete(objectStoreName);
// Trigger object store unlock event
$(Database.instance).trigger(Database.OBJECT_STORE_UNLOCK_EVENT, objectStoreName);
}, 0);
}
}
}
// Invaid key path pattern
static get INVALID_KEY_PATH_PATTERN() {
// Return invalid key path pattern
return /[ ']/gu;
}
// Invalid key path replacement
static get INVALID_KEY_PATH_REPLACEMENT() {
// Return invalid key path replacement
return "";
}
// Invalid
static get INVALID() {
// Return invalid
return null;
}
// Name
static get NAME() {
// Return name
return "Database";
}
// Version one
static get VERSION_ONE() {
// Return version one
return 1;
}
// Version
static get VERSION() {
// Return version
return 2;
}
// No records match get result
static get NO_RECORDS_MATCH_GET_RESULT() {
// Return no records match get result
return undefined;
}
// No records match cursor result
static get NO_RECORDS_MATCH_CURSOR_RESULT() {
// Return no records match cursor result
return null;
}
// Object store unlock event
static get OBJECT_STORE_UNLOCK_EVENT() {
// Return object store unlock event
return "DatabaseObjectStoreUnlockEvent";
}
}
// Main function
// Set global object's database
globalThis["Database"] = Database;