Reputation: 823
I am using Safari 12.1 and working on IndexedDB with javascript.
I need to get all indexedDB database names but safari does not support indexedDB.databases() function
whilst it is supported in chrome
so how can I get all indexedDB databases in Safari?
Please help.
Upvotes: 2
Views: 4749
Reputation: 45
The solution from @jamesmfriedman threw errors for me in Firefox, and when the IF statement was disabled would also throw errors in Chrome.
I stumbled across a PROXY method of intercepting method calls (from https://javascript.plainenglish.io/javascript-how-to-intercept-function-and-method-calls-b9fd6507ff02), and integrated it into the polyfill. This code works great in both Chrome and Firefox as of 2021-09-01.
/**
* Polyfill for indexedDB.databases()
* Safari and some other older browsers that support indexedDB do NOT
* Support enumerating existing databases. This is problematic when it
* comes time to cleanup, otherwise we could litter their device with
* unreferenceable database handles forcing a nuclear browser clear all history.
*/
// eslint-disable-next-line func-names
(function () {
// if (window.indexedDB && typeof window.indexedDB.databases === 'undefined') {
const LOCALSTORAGE_CACHE_KEY = 'indexedDBDatabases';
// Helper function from plainenglish.io to use a proxy to intercept.
// Original at https://javascript.plainenglish.io/javascript-how-to-intercept-function-and-method-calls-b9fd6507ff02
const interceptMethodCalls = (obj, fnName, fn) => new Proxy(obj, {
get(target, prop) {
if (prop === fnName && typeof target[prop] === 'function') {
return new Proxy(target[prop], {
apply: (target2, thisArg, argumentsList) => {
fn(prop, argumentsList);
return Reflect.apply(target2, thisArg, argumentsList);
},
});
}
return Reflect.get(target, prop);
},
});
// Store a key value map of databases
const getFromStorage = () => JSON.parse(window.localStorage[LOCALSTORAGE_CACHE_KEY] || '{}');
// Write the database to local storage
const writeToStorage = (value) => {
window.localStorage[LOCALSTORAGE_CACHE_KEY] = JSON.stringify(value);
};
IDBFactory.prototype.databases = () => Promise.resolve(
Object.entries(getFromStorage()).reduce((acc, [name, version]) => {
acc.push({ name, version });
return acc;
}, []),
);
// Intercept the existing open handler to write our DBs names
// and versions to localStorage
interceptMethodCalls(IDBFactory.prototype, 'open', (fnName, args) => {
const dbName = args[0];
const version = args[1] || 1;
const existing = getFromStorage();
writeToStorage({ ...existing, [dbName]: version });
});
// Intercept the existing deleteDatabase handler remove our
// dbNames from localStorage
interceptMethodCalls(IDBFactory.prototype, 'deleteDatabase', (fnName, args) => {
const dbName = args[0];
const existing = getFromStorage();
delete existing[dbName];
writeToStorage(existing);
});
// }
}());
Upvotes: 0
Reputation: 653
/**
* Polyfill for indexedDB.databases()
* Safari and some other older browsers that support indexedDB do NOT
* Support enumerating existing databases. This is problematic when it
* comes time to cleanup, otherwise we could litter their device with
* unreferenceable database handles forcing a nuclear browser clear all history.
*/
(function () {
if (window.indexedDB && typeof window.indexedDB.databases === 'undefined') {
const LOCALSTORAGE_CACHE_KEY = 'indexedDBDatabases';
// Store a key value map of databases
const getFromStorage = () =>
JSON.parse(window.localStorage[LOCALSTORAGE_CACHE_KEY] || '{}');
// Write the database to local storage
const writeToStorage = value =>
(window.localStorage[LOCALSTORAGE_CACHE_KEY] = JSON.stringify(value));
IDBFactory.prototype.databases = () =>
Promise.resolve(
Object.entries(getFromStorage()).reduce((acc, [name, version]) => {
acc.push({ name, version });
return acc;
}, [])
);
// Intercept the existing open handler to write our DBs names
// and versions to localStorage
const open = IDBFactory.prototype.open;
IDBFactory.prototype.open = function (...args) {
const dbName = args[0];
const version = args[1] || 1;
const existing = getFromStorage();
writeToStorage({ ...existing, [dbName]: version });
return open.apply(this, args);
};
// Intercept the existing deleteDatabase handler remove our
// dbNames from localStorage
const deleteDatabase = IDBFactory.prototype.deleteDatabase;
IDBFactory.prototype.deleteDatabase = function (...args) {
const dbName = args[0];
const existing = getFromStorage();
delete existing[dbName];
writeToStorage(existing);
return deleteDatabase.apply(this, args);
};
}
})();
Upvotes: 1
Reputation: 1192
Looks better on safari v13.0.1 from august 29, 2019, so try the Safari Technology Preview version.
please check:
https://caniuse.com/#feat=indexeddb
https://github.com/dfahlander/Dexie.js/issues
Upvotes: 1