use Proxy for db

This commit is contained in:
tophf 2022-01-22 21:42:55 +03:00
parent c95f74e089
commit 155de766e9
6 changed files with 46 additions and 33 deletions

View File

@ -38,11 +38,7 @@ addAPI(/** @namespace API */ {
}, },
}))(), }))(),
/** @type IDBObjectStore */ drafts: db.open('drafts'),
drafts: new Proxy({}, {
get: (_, cmd) => (...args) => db.exec.call('drafts', cmd, ...args),
}),
styles: styleMan, styles: styleMan,
sync: syncMan, sync: syncMan,
updater: updateMan, updater: updateMan,

View File

@ -4,6 +4,8 @@
/* exported createChromeStorageDB */ /* exported createChromeStorageDB */
function createChromeStorageDB(PREFIX) { function createChromeStorageDB(PREFIX) {
let INC; let INC;
const isMain = !PREFIX;
if (!PREFIX) PREFIX = 'style-';
return { return {
@ -19,7 +21,9 @@ function createChromeStorageDB(PREFIX) {
const all = await chromeLocal.get(); const all = await chromeLocal.get();
if (!INC) prepareInc(all); if (!INC) prepareInc(all);
return Object.entries(all) return Object.entries(all)
.map(([key, val]) => key.startsWith(PREFIX) && Number(key.slice(PREFIX.length)) && val) .map(([key, val]) => key.startsWith(PREFIX) &&
(!isMain || Number(key.slice(PREFIX.length))) &&
val)
.filter(Boolean); .filter(Boolean);
}, },

View File

@ -11,16 +11,28 @@
/* exported db */ /* exported db */
const db = (() => { const db = (() => {
const DATABASE = 'stylish'; let exec = async (...args) => (
const STORE = 'styles'; exec = await tryUsingIndexedDB().catch(useChromeStorage)
)(...args);
const DB = 'stylish';
const FALLBACK = 'dbInChromeStorage'; const FALLBACK = 'dbInChromeStorage';
const dbApi = { const proxies = {};
async exec(...args) { const proxyHandler = {
dbApi.exec = await tryUsingIndexedDB().catch(useChromeStorage); get: ({dbName}, cmd) => (...args) => exec(dbName, cmd, ...args),
return dbApi.exec(...args); };
}, const getProxy = (dbName = DB) =>
/** @type {IDBObjectStore | {putMany: function(items:?[]):Promise<?[]>}} */
proxies[dbName] || (
proxies[dbName] = new Proxy({dbName}, proxyHandler)
);
const getStoreName = dbName =>
dbName === DB
? 'styles'
: 'data';
return {
styles: getProxy(),
open: getProxy,
}; };
return dbApi;
async function tryUsingIndexedDB() { async function tryUsingIndexedDB() {
// we use chrome.storage.local fallback if IndexedDB doesn't save data, // we use chrome.storage.local fallback if IndexedDB doesn't save data,
@ -40,9 +52,9 @@ const db = (() => {
async function testDB() { async function testDB() {
const id = `${performance.now()}.${Math.random()}.${Date.now()}`; const id = `${performance.now()}.${Math.random()}.${Date.now()}`;
await dbExecIndexedDB('put', {id}); await dbExecIndexedDB(DB, 'put', {id});
const e = await dbExecIndexedDB('get', id); const e = await dbExecIndexedDB(DB, 'get', id);
await dbExecIndexedDB('delete', e.id); // throws if `e` or id is null await dbExecIndexedDB(DB, 'delete', e.id); // throws if `e` or id is null
} }
async function useChromeStorage(err) { async function useChromeStorage(err) {
@ -53,17 +65,17 @@ const db = (() => {
} }
await require(['/background/db-chrome-storage']); /* global createChromeStorageDB */ await require(['/background/db-chrome-storage']); /* global createChromeStorageDB */
const BASES = {}; const BASES = {};
return function dbExecChromeStorage(method, ...args) { return (dbName, method, ...args) => (
const prefix = Object(this) instanceof String ? `${this}-` : 'style-'; BASES[dbName] || (
const baseApi = BASES[prefix] || (BASES[prefix] = createChromeStorageDB(prefix)); BASES[dbName] = createChromeStorageDB(dbName !== DB && `${dbName}-`)
return baseApi[method](...args); )
}; )[method](...args);
} }
async function dbExecIndexedDB(method, ...args) { async function dbExecIndexedDB(dbName, method, ...args) {
const mode = method.startsWith('get') ? 'readonly' : 'readwrite'; const mode = method.startsWith('get') ? 'readonly' : 'readwrite';
const dbName = Object(this) instanceof String ? `${this}` : DATABASE; const storeName = getStoreName(dbName);
const store = (await open(dbName)).transaction([STORE], mode).objectStore(STORE); const store = (await open(dbName)).transaction([storeName], mode).objectStore(storeName);
const fn = method === 'putMany' ? putMany : storeRequest; const fn = method === 'putMany' ? putMany : storeRequest;
return fn(store, method, ...args); return fn(store, method, ...args);
} }
@ -92,7 +104,8 @@ const db = (() => {
function create(event) { function create(event) {
if (event.oldVersion === 0) { if (event.oldVersion === 0) {
event.target.result.createObjectStore(STORE, { const idb = event.target.result;
idb.createObjectStore(getStoreName(idb.name), {
keyPath: 'id', keyPath: 'id',
autoIncrement: true, autoIncrement: true,
}); });

View File

@ -105,7 +105,7 @@ const styleMan = (() => {
if (ready.then) await ready; if (ready.then) await ready;
const data = id2data(id); const data = id2data(id);
const {style, appliesTo} = data; const {style, appliesTo} = data;
await db.exec('delete', id); db.styles.delete(id);
if (reason !== 'sync') { if (reason !== 'sync') {
API.sync.delete(style._id, Date.now()); API.sync.delete(style._id, Date.now());
} }
@ -251,7 +251,7 @@ const styleMan = (() => {
await usercssMan.buildCode(style); await usercssMan.buildCode(style);
} }
} }
const events = await db.exec('putMany', items); const events = await db.styles.putMany(items);
return Promise.all(items.map((item, i) => return Promise.all(items.map((item, i) =>
handleSave(item, {reason: 'import'}, events[i]) handleSave(item, {reason: 'import'}, events[i])
)); ));
@ -437,7 +437,7 @@ const styleMan = (() => {
async function saveStyle(style, handlingOptions) { async function saveStyle(style, handlingOptions) {
beforeSave(style); beforeSave(style);
const newId = await db.exec('put', style); const newId = await db.styles.put(style);
return handleSave(style, handlingOptions, newId); return handleSave(style, handlingOptions, newId);
} }
@ -477,10 +477,10 @@ const styleMan = (() => {
} }
async function init() { async function init() {
const styles = await db.exec('getAll') || []; const styles = await db.styles.getAll() || [];
const updated = await Promise.all(styles.map(fixKnownProblems).filter(Boolean)); const updated = await Promise.all(styles.map(fixKnownProblems).filter(Boolean));
if (updated.length) { if (updated.length) {
await db.exec('putMany', updated); await db.styles.putMany(updated);
} }
styles.forEach(storeInMap); styles.forEach(storeInMap);
ready = true; ready = true;

View File

@ -209,7 +209,7 @@ const syncMan = (() => {
} }
} }
if (diff < 0) { if (diff < 0) {
doc.id = await db.exec('put', doc); doc.id = await db.styles.put(doc);
uuidIndex.set(doc._id, doc.id); uuidIndex.set(doc._id, doc.id);
return styleUtil.handleSave(doc, {reason: 'sync'}); return styleUtil.handleSave(doc, {reason: 'sync'});
} }

View File

@ -234,7 +234,7 @@ const updateMan = (() => {
if (err && etag && !style.etag) { if (err && etag && !style.etag) {
// first check of ETAG, gonna write it directly to DB as it's too trivial to sync or announce // first check of ETAG, gonna write it directly to DB as it's too trivial to sync or announce
style.etag = etag; style.etag = etag;
await db.exec('put', style); await db.styles.put(style);
} }
return err return err
? Promise.reject(err) ? Promise.reject(err)