mirror of
				https://github.com/flynx/pWiki.git
				synced 2025-11-03 12:30:07 +00:00 
			
		
		
		
	
		
			
	
	
		
			185 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			185 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
								 | 
							
								function promisifyRequest(request) {
							 | 
						|||
| 
								 | 
							
								    return new Promise((resolve, reject) => {
							 | 
						|||
| 
								 | 
							
								        // @ts-ignore - file size hacks
							 | 
						|||
| 
								 | 
							
								        request.oncomplete = request.onsuccess = () => resolve(request.result);
							 | 
						|||
| 
								 | 
							
								        // @ts-ignore - file size hacks
							 | 
						|||
| 
								 | 
							
								        request.onabort = request.onerror = () => reject(request.error);
							 | 
						|||
| 
								 | 
							
								    });
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								function createStore(dbName, storeName) {
							 | 
						|||
| 
								 | 
							
								    const request = indexedDB.open(dbName);
							 | 
						|||
| 
								 | 
							
								    request.onupgradeneeded = () => request.result.createObjectStore(storeName);
							 | 
						|||
| 
								 | 
							
								    const dbp = promisifyRequest(request);
							 | 
						|||
| 
								 | 
							
								    return (txMode, callback) => dbp.then((db) => callback(db.transaction(storeName, txMode).objectStore(storeName)));
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								let defaultGetStoreFunc;
							 | 
						|||
| 
								 | 
							
								function defaultGetStore() {
							 | 
						|||
| 
								 | 
							
								    if (!defaultGetStoreFunc) {
							 | 
						|||
| 
								 | 
							
								        defaultGetStoreFunc = createStore('keyval-store', 'keyval');
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								    return defaultGetStoreFunc;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								/**
							 | 
						|||
| 
								 | 
							
								 * Get a value by its key.
							 | 
						|||
| 
								 | 
							
								 *
							 | 
						|||
| 
								 | 
							
								 * @param key
							 | 
						|||
| 
								 | 
							
								 * @param customStore Method to get a custom store. Use with caution (see the docs).
							 | 
						|||
| 
								 | 
							
								 */
							 | 
						|||
| 
								 | 
							
								function get(key, customStore = defaultGetStore()) {
							 | 
						|||
| 
								 | 
							
								    return customStore('readonly', (store) => promisifyRequest(store.get(key)));
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								/**
							 | 
						|||
| 
								 | 
							
								 * Set a value with a key.
							 | 
						|||
| 
								 | 
							
								 *
							 | 
						|||
| 
								 | 
							
								 * @param key
							 | 
						|||
| 
								 | 
							
								 * @param value
							 | 
						|||
| 
								 | 
							
								 * @param customStore Method to get a custom store. Use with caution (see the docs).
							 | 
						|||
| 
								 | 
							
								 */
							 | 
						|||
| 
								 | 
							
								function set(key, value, customStore = defaultGetStore()) {
							 | 
						|||
| 
								 | 
							
								    return customStore('readwrite', (store) => {
							 | 
						|||
| 
								 | 
							
								        store.put(value, key);
							 | 
						|||
| 
								 | 
							
								        return promisifyRequest(store.transaction);
							 | 
						|||
| 
								 | 
							
								    });
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								/**
							 | 
						|||
| 
								 | 
							
								 * Set multiple values at once. This is faster than calling set() multiple times.
							 | 
						|||
| 
								 | 
							
								 * It's also atomic – if one of the pairs can't be added, none will be added.
							 | 
						|||
| 
								 | 
							
								 *
							 | 
						|||
| 
								 | 
							
								 * @param entries Array of entries, where each entry is an array of `[key, value]`.
							 | 
						|||
| 
								 | 
							
								 * @param customStore Method to get a custom store. Use with caution (see the docs).
							 | 
						|||
| 
								 | 
							
								 */
							 | 
						|||
| 
								 | 
							
								function setMany(entries, customStore = defaultGetStore()) {
							 | 
						|||
| 
								 | 
							
								    return customStore('readwrite', (store) => {
							 | 
						|||
| 
								 | 
							
								        entries.forEach((entry) => store.put(entry[1], entry[0]));
							 | 
						|||
| 
								 | 
							
								        return promisifyRequest(store.transaction);
							 | 
						|||
| 
								 | 
							
								    });
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								/**
							 | 
						|||
| 
								 | 
							
								 * Get multiple values by their keys
							 | 
						|||
| 
								 | 
							
								 *
							 | 
						|||
| 
								 | 
							
								 * @param keys
							 | 
						|||
| 
								 | 
							
								 * @param customStore Method to get a custom store. Use with caution (see the docs).
							 | 
						|||
| 
								 | 
							
								 */
							 | 
						|||
| 
								 | 
							
								function getMany(keys, customStore = defaultGetStore()) {
							 | 
						|||
| 
								 | 
							
								    return customStore('readonly', (store) => Promise.all(keys.map((key) => promisifyRequest(store.get(key)))));
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								/**
							 | 
						|||
| 
								 | 
							
								 * Update a value. This lets you see the old value and update it as an atomic operation.
							 | 
						|||
| 
								 | 
							
								 *
							 | 
						|||
| 
								 | 
							
								 * @param key
							 | 
						|||
| 
								 | 
							
								 * @param updater A callback that takes the old value and returns a new value.
							 | 
						|||
| 
								 | 
							
								 * @param customStore Method to get a custom store. Use with caution (see the docs).
							 | 
						|||
| 
								 | 
							
								 */
							 | 
						|||
| 
								 | 
							
								function update(key, updater, customStore = defaultGetStore()) {
							 | 
						|||
| 
								 | 
							
								    return customStore('readwrite', (store) => 
							 | 
						|||
| 
								 | 
							
								    // Need to create the promise manually.
							 | 
						|||
| 
								 | 
							
								    // If I try to chain promises, the transaction closes in browsers
							 | 
						|||
| 
								 | 
							
								    // that use a promise polyfill (IE10/11).
							 | 
						|||
| 
								 | 
							
								    new Promise((resolve, reject) => {
							 | 
						|||
| 
								 | 
							
								        store.get(key).onsuccess = function () {
							 | 
						|||
| 
								 | 
							
								            try {
							 | 
						|||
| 
								 | 
							
								                store.put(updater(this.result), key);
							 | 
						|||
| 
								 | 
							
								                resolve(promisifyRequest(store.transaction));
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								            catch (err) {
							 | 
						|||
| 
								 | 
							
								                reject(err);
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								        };
							 | 
						|||
| 
								 | 
							
								    }));
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								/**
							 | 
						|||
| 
								 | 
							
								 * Delete a particular key from the store.
							 | 
						|||
| 
								 | 
							
								 *
							 | 
						|||
| 
								 | 
							
								 * @param key
							 | 
						|||
| 
								 | 
							
								 * @param customStore Method to get a custom store. Use with caution (see the docs).
							 | 
						|||
| 
								 | 
							
								 */
							 | 
						|||
| 
								 | 
							
								function del(key, customStore = defaultGetStore()) {
							 | 
						|||
| 
								 | 
							
								    return customStore('readwrite', (store) => {
							 | 
						|||
| 
								 | 
							
								        store.delete(key);
							 | 
						|||
| 
								 | 
							
								        return promisifyRequest(store.transaction);
							 | 
						|||
| 
								 | 
							
								    });
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								/**
							 | 
						|||
| 
								 | 
							
								 * Delete multiple keys at once.
							 | 
						|||
| 
								 | 
							
								 *
							 | 
						|||
| 
								 | 
							
								 * @param keys List of keys to delete.
							 | 
						|||
| 
								 | 
							
								 * @param customStore Method to get a custom store. Use with caution (see the docs).
							 | 
						|||
| 
								 | 
							
								 */
							 | 
						|||
| 
								 | 
							
								function delMany(keys, customStore = defaultGetStore()) {
							 | 
						|||
| 
								 | 
							
								    return customStore('readwrite', (store) => {
							 | 
						|||
| 
								 | 
							
								        keys.forEach((key) => store.delete(key));
							 | 
						|||
| 
								 | 
							
								        return promisifyRequest(store.transaction);
							 | 
						|||
| 
								 | 
							
								    });
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								/**
							 | 
						|||
| 
								 | 
							
								 * Clear all values in the store.
							 | 
						|||
| 
								 | 
							
								 *
							 | 
						|||
| 
								 | 
							
								 * @param customStore Method to get a custom store. Use with caution (see the docs).
							 | 
						|||
| 
								 | 
							
								 */
							 | 
						|||
| 
								 | 
							
								function clear(customStore = defaultGetStore()) {
							 | 
						|||
| 
								 | 
							
								    return customStore('readwrite', (store) => {
							 | 
						|||
| 
								 | 
							
								        store.clear();
							 | 
						|||
| 
								 | 
							
								        return promisifyRequest(store.transaction);
							 | 
						|||
| 
								 | 
							
								    });
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								function eachCursor(store, callback) {
							 | 
						|||
| 
								 | 
							
								    store.openCursor().onsuccess = function () {
							 | 
						|||
| 
								 | 
							
								        if (!this.result)
							 | 
						|||
| 
								 | 
							
								            return;
							 | 
						|||
| 
								 | 
							
								        callback(this.result);
							 | 
						|||
| 
								 | 
							
								        this.result.continue();
							 | 
						|||
| 
								 | 
							
								    };
							 | 
						|||
| 
								 | 
							
								    return promisifyRequest(store.transaction);
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								/**
							 | 
						|||
| 
								 | 
							
								 * Get all keys in the store.
							 | 
						|||
| 
								 | 
							
								 *
							 | 
						|||
| 
								 | 
							
								 * @param customStore Method to get a custom store. Use with caution (see the docs).
							 | 
						|||
| 
								 | 
							
								 */
							 | 
						|||
| 
								 | 
							
								function keys(customStore = defaultGetStore()) {
							 | 
						|||
| 
								 | 
							
								    return customStore('readonly', (store) => {
							 | 
						|||
| 
								 | 
							
								        // Fast path for modern browsers
							 | 
						|||
| 
								 | 
							
								        if (store.getAllKeys) {
							 | 
						|||
| 
								 | 
							
								            return promisifyRequest(store.getAllKeys());
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        const items = [];
							 | 
						|||
| 
								 | 
							
								        return eachCursor(store, (cursor) => items.push(cursor.key)).then(() => items);
							 | 
						|||
| 
								 | 
							
								    });
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								/**
							 | 
						|||
| 
								 | 
							
								 * Get all values in the store.
							 | 
						|||
| 
								 | 
							
								 *
							 | 
						|||
| 
								 | 
							
								 * @param customStore Method to get a custom store. Use with caution (see the docs).
							 | 
						|||
| 
								 | 
							
								 */
							 | 
						|||
| 
								 | 
							
								function values(customStore = defaultGetStore()) {
							 | 
						|||
| 
								 | 
							
								    return customStore('readonly', (store) => {
							 | 
						|||
| 
								 | 
							
								        // Fast path for modern browsers
							 | 
						|||
| 
								 | 
							
								        if (store.getAll) {
							 | 
						|||
| 
								 | 
							
								            return promisifyRequest(store.getAll());
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        const items = [];
							 | 
						|||
| 
								 | 
							
								        return eachCursor(store, (cursor) => items.push(cursor.value)).then(() => items);
							 | 
						|||
| 
								 | 
							
								    });
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								/**
							 | 
						|||
| 
								 | 
							
								 * Get all entries in the store. Each entry is an array of `[key, value]`.
							 | 
						|||
| 
								 | 
							
								 *
							 | 
						|||
| 
								 | 
							
								 * @param customStore Method to get a custom store. Use with caution (see the docs).
							 | 
						|||
| 
								 | 
							
								 */
							 | 
						|||
| 
								 | 
							
								function entries(customStore = defaultGetStore()) {
							 | 
						|||
| 
								 | 
							
								    return customStore('readonly', (store) => {
							 | 
						|||
| 
								 | 
							
								        // Fast path for modern browsers
							 | 
						|||
| 
								 | 
							
								        // (although, hopefully we'll get a simpler path some day)
							 | 
						|||
| 
								 | 
							
								        if (store.getAll && store.getAllKeys) {
							 | 
						|||
| 
								 | 
							
								            return Promise.all([
							 | 
						|||
| 
								 | 
							
								                promisifyRequest(store.getAllKeys()),
							 | 
						|||
| 
								 | 
							
								                promisifyRequest(store.getAll()),
							 | 
						|||
| 
								 | 
							
								            ]).then(([keys, values]) => keys.map((key, i) => [key, values[i]]));
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        const items = [];
							 | 
						|||
| 
								 | 
							
								        return customStore('readonly', (store) => eachCursor(store, (cursor) => items.push([cursor.key, cursor.value])).then(() => items));
							 | 
						|||
| 
								 | 
							
								    });
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								export { clear, createStore, del, delMany, entries, get, getMany, keys, promisifyRequest, set, setMany, update, values };
							 |