diff --git a/CHANGELOG.md b/CHANGELOG.md index a696c7ee..9563d474 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### Fixed - Explicitly import `buffer` [#34](https://github.com/seald/nedb/pull/34). - Fix `Cursor`'s typings [#45](https://github.com/seald/nedb/issues/45) +- Removes unnecessary uses of the native `path` module for the browser and React-Native version by replacing the internal `Persistance.ensureDirectoryExistsAsync` static method with `Persistance.ensureParentDirectoryExistsAsync` so that any `path` functions are used only in Node.js where it is necessary, as it is not necessary for the browser and React-Native. ## [4.0.3] - 2023-12-13 ### Fixed @@ -76,7 +77,7 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - `Persistence#persistCachedDatabase` replaced with `Persistence#persistCachedDatabaseAsync`; - `Persistence#persistNewState` replaced with `Persistence#persistNewStateAsync`; - `Persistence#treatRawStream` replaced with `Persistence#treatRawStreamAsync`; - - `Persistence.ensureDirectoryExists` replaced with `Persistence#ensureDirectoryExistsAsync`; + - `Persistence.ensureDirectoryExists` replaced with `Persistence.ensureDirectoryExistsAsync`; - Cursor: - `Cursor#_exec` replaced with `Cursor#_execAsync`; - `Cursor#project` replaced with `Cursor#_project`; diff --git a/README.md b/README.md index b7dd39fe..1e92b894 100755 --- a/README.md +++ b/README.md @@ -838,6 +838,10 @@ This is done for: the repo because it is unmaintained). It isn't used in the browser nor react-native versions, therefore it is shimmed with an empty object. +However, the `browser` and `react-native` versions rely on node native modules and therefore must be polyfilled: +- `util` with https://github.com/browserify/node-util. +- `events` with https://github.com/browserify/events. + ## Performance ### Speed diff --git a/benchmarks/commonUtilities.js b/benchmarks/commonUtilities.js index 81a66970..04d315f4 100755 --- a/benchmarks/commonUtilities.js +++ b/benchmarks/commonUtilities.js @@ -2,7 +2,6 @@ * Functions that are used in several benchmark tests */ const fs = require('fs') -const path = require('path') const Datastore = require('../lib/datastore') const Persistence = require('../lib/persistence') const { callbackify } = require('util') @@ -46,7 +45,7 @@ module.exports.getConfiguration = function (benchDb) { * Ensure the workspace stat and the db datafile is empty */ module.exports.prepareDb = function (filename, cb) { - callbackify((dirname) => Persistence.ensureDirectoryExistsAsync(dirname))(path.dirname(filename), function () { + callbackify((filename) => Persistence.ensureParentDirectoryExistsAsync(filename))(filename, function () { fs.access(filename, fs.constants.FS_OK, function (err) { if (!err) { fs.unlink(filename, cb) diff --git a/browser-version/lib/storage.browser.js b/browser-version/lib/storage.browser.js index 1548a076..9a7898f5 100755 --- a/browser-version/lib/storage.browser.js +++ b/browser-version/lib/storage.browser.js @@ -138,6 +138,17 @@ const unlinkAsync = async filename => { */ 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 @@ -176,3 +187,5 @@ module.exports.unlinkAsync = unlinkAsync module.exports.mkdirAsync = mkdirAsync module.exports.ensureDatafileIntegrityAsync = ensureDatafileIntegrityAsync + +module.exports.ensureParentDirectoryExistsAsync = ensureParentDirectoryExistsAsync diff --git a/browser-version/lib/storage.react-native.js b/browser-version/lib/storage.react-native.js index 13048229..528af379 100755 --- a/browser-version/lib/storage.react-native.js +++ b/browser-version/lib/storage.react-native.js @@ -253,6 +253,17 @@ const crashSafeWriteFileLinesAsync = async (filename, lines) => { */ const crashSafeWriteFileLines = callbackify(crashSafeWriteFileLinesAsync) +/** + * 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() + // Interface module.exports.exists = exists module.exports.existsAsync = existsAsync @@ -280,3 +291,5 @@ module.exports.mkdirAsync = mkdirAsync module.exports.ensureDatafileIntegrity = ensureDatafileIntegrity module.exports.ensureDatafileIntegrityAsync = ensureDatafileIntegrityAsync + +module.exports.ensureParentDirectoryExistsAsync = ensureParentDirectoryExistsAsync diff --git a/lib/persistence.js b/lib/persistence.js index ba359a53..f8c7c167 100755 --- a/lib/persistence.js +++ b/lib/persistence.js @@ -1,4 +1,3 @@ -const path = require('path') const { deprecate } = require('util') const byline = require('./byline') const customUtils = require('./customUtils.js') @@ -308,7 +307,7 @@ class Persistence { // In-memory only datastore if (this.inMemoryOnly) return - await Persistence.ensureDirectoryExistsAsync(path.dirname(this.filename), this.modes.dirMode) + await Persistence.ensureParentDirectoryExistsAsync(this.filename, this.modes.dirMode) await storage.ensureDatafileIntegrityAsync(this.filename, this.modes.fileMode) let treatedData @@ -372,12 +371,8 @@ class Persistence { * @return {Promise} * @private */ - static async ensureDirectoryExistsAsync (dir, mode = DEFAULT_DIR_MODE) { - const parsedDir = path.parse(path.resolve(dir)) - // this is because on Windows mkdir throws a permission error when called on the root directory of a volume - if (process.platform !== 'win32' || parsedDir.dir !== parsedDir.root || parsedDir.base !== '') { - await storage.mkdirAsync(dir, { recursive: true, mode }) - } + static async ensureParentDirectoryExistsAsync (dir, mode = DEFAULT_DIR_MODE) { + return storage.ensureParentDirectoryExistsAsync(dir, mode) } } diff --git a/lib/storage.js b/lib/storage.js index 957fcc91..c8fec6dd 100755 --- a/lib/storage.js +++ b/lib/storage.js @@ -1,6 +1,6 @@ /** * Way data is stored for this database. - * This version is the Node.js/Node Webkit version. + * This version is the Node.js version. * It's essentially fs, mkdirp and crash safe write and read functions. * * @see module:storageBrowser @@ -271,6 +271,22 @@ const ensureDatafileIntegrityAsync = async (filename, mode = DEFAULT_FILE_MODE) else await renameAsync(tempFilename, filename) } +/** + * Check if a file's parent directory exists and create it on the fly if it is not the case. + * @param {string} filename + * @param {number} mode + * @return {Promise} + * @private + */ +const ensureParentDirectoryExistsAsync = async (filename, mode) => { + const dir = path.dirname(filename) + const parsedDir = path.parse(path.resolve(dir)) + // this is because on Windows mkdir throws a permission error when called on the root directory of a volume + if (process.platform !== 'win32' || parsedDir.dir !== parsedDir.root || parsedDir.base !== '') { + await mkdirAsync(dir, { recursive: true, mode }) + } +} + // Interface module.exports.existsAsync = existsAsync @@ -297,3 +313,5 @@ module.exports.flushToStorageAsync = flushToStorageAsync module.exports.ensureDatafileIntegrityAsync = ensureDatafileIntegrityAsync module.exports.ensureFileDoesntExistAsync = ensureFileDoesntExistAsync + +module.exports.ensureParentDirectoryExistsAsync = ensureParentDirectoryExistsAsync diff --git a/test/cursor.async.test.js b/test/cursor.async.test.js index ec9b2f61..97452601 100755 --- a/test/cursor.async.test.js +++ b/test/cursor.async.test.js @@ -2,7 +2,6 @@ const testDb = 'workspace/test.db' const { promises: fs } = require('fs') const assert = require('assert').strict -const path = require('path') const Datastore = require('../lib/datastore') const Persistence = require('../lib/persistence') const Cursor = require('../lib/cursor') @@ -15,7 +14,7 @@ describe('Cursor Async', function () { d = new Datastore({ filename: testDb }) assert.equal(d.filename, testDb) assert.equal(d.inMemoryOnly, false) - await Persistence.ensureDirectoryExistsAsync(path.dirname(testDb)) + await Persistence.ensureParentDirectoryExistsAsync(testDb) if (await exists(testDb)) await fs.unlink(testDb) await d.loadDatabaseAsync() assert.equal(d.getAllData().length, 0) diff --git a/test/cursor.test.js b/test/cursor.test.js index c767ac47..b555d78d 100755 --- a/test/cursor.test.js +++ b/test/cursor.test.js @@ -2,7 +2,6 @@ const chai = require('chai') const testDb = 'workspace/test.db' const fs = require('fs') -const path = require('path') const { each, waterfall } = require('./utils.test.js') const Datastore = require('../lib/datastore') const Persistence = require('../lib/persistence') @@ -22,7 +21,7 @@ describe('Cursor', function () { waterfall([ function (cb) { - callbackify((dirname) => Persistence.ensureDirectoryExistsAsync(dirname))(path.dirname(testDb), function () { + callbackify((filename) => Persistence.ensureParentDirectoryExistsAsync(filename))(testDb, function () { fs.access(testDb, fs.constants.F_OK, function (err) { if (!err) { fs.unlink(testDb, cb) diff --git a/test/db.async.test.js b/test/db.async.test.js index a6033e7f..e0f303cc 100644 --- a/test/db.async.test.js +++ b/test/db.async.test.js @@ -1,7 +1,6 @@ /* eslint-env mocha */ const testDb = 'workspace/test.db' const { promises: fs } = require('fs') -const path = require('path') const assert = require('assert').strict const model = require('../lib/model') const Datastore = require('../lib/datastore') @@ -17,7 +16,7 @@ describe('Database async', function () { d = new Datastore({ filename: testDb }) assert.equal(d.filename, testDb) assert.equal(d.inMemoryOnly, false) - await Persistence.ensureDirectoryExistsAsync(path.dirname(testDb)) + await Persistence.ensureParentDirectoryExistsAsync(testDb) if (await exists(testDb)) await fs.unlink(testDb) await d.loadDatabaseAsync() assert.equal(d.getAllData().length, 0) diff --git a/test/db.test.js b/test/db.test.js index 67966ff6..cfee4eb6 100755 --- a/test/db.test.js +++ b/test/db.test.js @@ -2,7 +2,6 @@ const chai = require('chai') const testDb = 'workspace/test.db' const fs = require('fs') -const path = require('path') const { apply, each, waterfall } = require('./utils.test.js') const model = require('../lib/model') const Datastore = require('../lib/datastore') @@ -23,7 +22,7 @@ describe('Database', function () { waterfall([ function (cb) { - callbackify((dirname) => Persistence.ensureDirectoryExistsAsync(dirname))(path.dirname(testDb), function () { + callbackify((filename) => Persistence.ensureParentDirectoryExistsAsync(filename))(testDb, function () { fs.access(testDb, fs.constants.FS_OK, function (err) { if (!err) { fs.unlink(testDb, cb) diff --git a/test/executor.async.test.js b/test/executor.async.test.js index d8354004..5f362894 100755 --- a/test/executor.async.test.js +++ b/test/executor.async.test.js @@ -2,7 +2,6 @@ const testDb = 'workspace/test.db' const { promises: fs } = require('fs') const assert = require('assert').strict -const path = require('path') const Datastore = require('../lib/datastore') const Persistence = require('../lib/persistence') const { exists } = require('./utils.test.js') @@ -53,7 +52,7 @@ describe('Executor async', function () { d = new Datastore({ filename: testDb }) assert.equal(d.filename, testDb) assert.equal(d.inMemoryOnly, false) - await Persistence.ensureDirectoryExistsAsync(path.dirname(testDb)) + await Persistence.ensureParentDirectoryExistsAsync(testDb) if (await exists(testDb)) await fs.unlink(testDb) await d.loadDatabaseAsync() assert.equal(d.getAllData().length, 0) diff --git a/test/executor.test.js b/test/executor.test.js index 64fb0f73..09ffdfcc 100755 --- a/test/executor.test.js +++ b/test/executor.test.js @@ -2,7 +2,6 @@ const chai = require('chai') const testDb = 'workspace/test.db' const fs = require('fs') -const path = require('path') const { waterfall } = require('./utils.test.js') const Datastore = require('../lib/datastore') const Persistence = require('../lib/persistence') @@ -154,7 +153,7 @@ describe('Executor', function () { waterfall([ function (cb) { - callbackify((dirname) => Persistence.ensureDirectoryExistsAsync(dirname))(path.dirname(testDb), function () { + callbackify((filename) => Persistence.ensureParentDirectoryExistsAsync(filename))(testDb, function () { fs.access(testDb, fs.constants.F_OK, function (err) { if (!err) { fs.unlink(testDb, cb) diff --git a/test/persistence.async.test.js b/test/persistence.async.test.js index 241147b7..db51ef53 100755 --- a/test/persistence.async.test.js +++ b/test/persistence.async.test.js @@ -22,7 +22,7 @@ describe('Persistence async', function () { d = new Datastore({ filename: testDb }) assert.equal(d.filename, testDb) assert.equal(d.inMemoryOnly, false) - await Persistence.ensureDirectoryExistsAsync(path.dirname(testDb)) + await Persistence.ensureParentDirectoryExistsAsync(testDb) if (await exists(testDb)) await fs.unlink(testDb) await d.loadDatabaseAsync() assert.equal(d.getAllData().length, 0) @@ -1062,7 +1062,7 @@ describe('permissions', function () { }) it('ensureDirectoryExists forwards mode argument', async () => { - await Persistence.ensureDirectoryExistsAsync(path.dirname(testDb), 0o700) + await Persistence.ensureParentDirectoryExistsAsync(testDb, 0o700) assert.equal(await getMode(path.dirname(testDb)), 0o700) }) diff --git a/test/persistence.test.js b/test/persistence.test.js index c027e0dc..ba9026b9 100755 --- a/test/persistence.test.js +++ b/test/persistence.test.js @@ -2,7 +2,6 @@ const chai = require('chai') const testDb = 'workspace/test.db' const fs = require('fs') -const path = require('path') const { apply, waterfall } = require('./utils.test.js') const model = require('../lib/model') const Datastore = require('../lib/datastore') @@ -27,7 +26,7 @@ describe('Persistence', function () { waterfall([ function (cb) { - callbackify((dirname) => Persistence.ensureDirectoryExistsAsync(dirname))(path.dirname(testDb), function () { + callbackify((filename) => Persistence.ensureParentDirectoryExistsAsync(filename))(testDb, function () { fs.access(testDb, fs.constants.FS_OK, function (err) { if (!err) { fs.unlink(testDb, cb)