/** * Way data is stored for this database * * This version is the browser version and uses [localforage]{@link https://github.com/localForage/localForage} which chooses the best option depending on user browser (IndexedDB then WebSQL then localStorage). * @module storageBrowser * @see module:storage * @see module:storageReactNative * @private */ const localforage = require('localforage') // Configure localforage to display NeDB name for now. Would be a good idea to let user use his own app name const store = localforage.createInstance({ name: 'NeDB', storeName: 'nedbdata' }) /** * Returns Promise if file exists. * * @param {string} file * @return {Promise} * @async * @alias module:storageBrowser.existsAsync */ const existsAsync = async file => { try { const value = await store.getItem(file) if (value !== null) return true // Even if value is undefined, localforage returns null return false } catch (error) { return false } } /** * Moves the item from one path to another. * @param {string} oldPath * @param {string} newPath * @return {Promise} * @alias module:storageBrowser.renameAsync * @async */ const renameAsync = async (oldPath, newPath) => { try { const value = await store.getItem(oldPath) if (value === null) await store.removeItem(newPath) else { await store.setItem(newPath, value) await store.removeItem(oldPath) } } catch (err) { console.warn('An error happened while renaming, skip') } } /** * Saves the item at given path. * @param {string} file * @param {string} data * @param {object} [options] * @return {Promise} * @alias module:storageBrowser.writeFileAsync * @async */ const writeFileAsync = async (file, data, options) => { // Options do not matter in browser setup try { await store.setItem(file, data) } catch (error) { console.warn('An error happened while writing, skip') } } /** * Append to the item at given path. * @function * @param {string} filename * @param {string} toAppend * @param {object} [options] * @return {Promise} * @alias module:storageBrowser.appendFileAsync * @async */ const appendFileAsync = async (filename, toAppend, options) => { // Options do not matter in browser setup try { const contents = (await store.getItem(filename)) || '' await store.setItem(filename, contents + toAppend) } catch (error) { console.warn('An error happened appending to file writing, skip') } } /** * Read data at given path. * @function * @param {string} filename * @param {object} [options] * @return {Promise} * @alias module:storageBrowser.readFileAsync * @async */ const readFileAsync = async (filename, options) => { try { return (await store.getItem(filename)) || '' } catch (error) { console.warn('An error happened while reading, skip') return '' } } /** * Async version of {@link module:storageBrowser.unlink}. * @function * @param {string} filename * @return {Promise} * @async * @alias module:storageBrowser.unlink */ const unlinkAsync = async filename => { try { await store.removeItem(filename) } catch (error) { console.warn('An error happened while unlinking, skip') } } /** * Shim for {@link module:storage.mkdirAsync}, nothing to do, no directories will be used on the browser. * @function * @param {string} path * @param {object} [options] * @return {Promise} * @alias module:storageBrowser.mkdirAsync * @async */ const mkdirAsync = (path, options) => Promise.resolve() /** * Shim for {@link module:storage.ensureParentDirectoryExistsAsync}, nothing to do, no directories will be used on the browser. * @function * @param {string} file * @param {number} [mode] * @return {Promise} * @alias module:storageBrowser.ensureParentDirectoryExistsAsync * @async */ const ensureParentDirectoryExistsAsync = async (file, mode) => Promise.resolve() /** * Shim for {@link module:storage.ensureDatafileIntegrityAsync}, nothing to do, no data corruption possible in the browser. * @param {string} filename * @return {Promise} * @alias module:storageBrowser.ensureDatafileIntegrityAsync */ const ensureDatafileIntegrityAsync = (filename) => Promise.resolve() /** * Fully write or rewrite the datafile, immune to crashes during the write operation (data will not be lost) * * @param {string} filename * @param {string[]} lines * @return {Promise} * @alias module:storageBrowser.crashSafeWriteFileLinesAsync */ const crashSafeWriteFileLinesAsync = async (filename, lines) => { lines.push('') // Add final new line await writeFileAsync(filename, lines.join('\n')) } // Interface module.exports.existsAsync = existsAsync module.exports.renameAsync = renameAsync module.exports.writeFileAsync = writeFileAsync module.exports.crashSafeWriteFileLinesAsync = crashSafeWriteFileLinesAsync module.exports.appendFileAsync = appendFileAsync module.exports.readFileAsync = readFileAsync module.exports.unlinkAsync = unlinkAsync module.exports.mkdirAsync = mkdirAsync module.exports.ensureDatafileIntegrityAsync = ensureDatafileIntegrityAsync module.exports.ensureParentDirectoryExistsAsync = ensureParentDirectoryExistsAsync