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: new Proxy({}, {
get: (_, cmd) => (...args) => db.exec.call('drafts', cmd, ...args),
}),
drafts: db.open('drafts'),
styles: styleMan,
sync: syncMan,
updater: updateMan,

View File

@ -4,6 +4,8 @@
/* exported createChromeStorageDB */
function createChromeStorageDB(PREFIX) {
let INC;
const isMain = !PREFIX;
if (!PREFIX) PREFIX = 'style-';
return {
@ -19,7 +21,9 @@ function createChromeStorageDB(PREFIX) {
const all = await chromeLocal.get();
if (!INC) prepareInc(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);
},

View File

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

View File

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

View File

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

View File

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