Merge pull request #51 from seald/feat/clean-native-node-modules-imports

Clean & document native node modules imports / polyfills
master
tex0l 11 months ago committed by GitHub
commit bc10dded1a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      CHANGELOG.md
  2. 4
      README.md
  3. 3
      benchmarks/commonUtilities.js
  4. 13
      browser-version/lib/storage.browser.js
  5. 13
      browser-version/lib/storage.react-native.js
  6. 11
      lib/persistence.js
  7. 20
      lib/storage.js
  8. 3
      test/cursor.async.test.js
  9. 3
      test/cursor.test.js
  10. 3
      test/db.async.test.js
  11. 3
      test/db.test.js
  12. 3
      test/executor.async.test.js
  13. 3
      test/executor.test.js
  14. 4
      test/persistence.async.test.js
  15. 3
      test/persistence.test.js

@ -10,6 +10,7 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
### Fixed ### Fixed
- Explicitly import `buffer` [#34](https://github.com/seald/nedb/pull/34). - Explicitly import `buffer` [#34](https://github.com/seald/nedb/pull/34).
- Fix `Cursor`'s typings [#45](https://github.com/seald/nedb/issues/45) - 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 ## [4.0.3] - 2023-12-13
### Fixed ### Fixed
@ -76,7 +77,7 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
- `Persistence#persistCachedDatabase` replaced with `Persistence#persistCachedDatabaseAsync`; - `Persistence#persistCachedDatabase` replaced with `Persistence#persistCachedDatabaseAsync`;
- `Persistence#persistNewState` replaced with `Persistence#persistNewStateAsync`; - `Persistence#persistNewState` replaced with `Persistence#persistNewStateAsync`;
- `Persistence#treatRawStream` replaced with `Persistence#treatRawStreamAsync`; - `Persistence#treatRawStream` replaced with `Persistence#treatRawStreamAsync`;
- `Persistence.ensureDirectoryExists` replaced with `Persistence#ensureDirectoryExistsAsync`; - `Persistence.ensureDirectoryExists` replaced with `Persistence.ensureDirectoryExistsAsync`;
- Cursor: - Cursor:
- `Cursor#_exec` replaced with `Cursor#_execAsync`; - `Cursor#_exec` replaced with `Cursor#_execAsync`;
- `Cursor#project` replaced with `Cursor#_project`; - `Cursor#project` replaced with `Cursor#_project`;

@ -838,6 +838,10 @@ This is done for:
the repo because it is unmaintained). It isn't used in the browser nor 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. 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 ## Performance
### Speed ### Speed

@ -2,7 +2,6 @@
* Functions that are used in several benchmark tests * Functions that are used in several benchmark tests
*/ */
const fs = require('fs') const fs = require('fs')
const path = require('path')
const Datastore = require('../lib/datastore') const Datastore = require('../lib/datastore')
const Persistence = require('../lib/persistence') const Persistence = require('../lib/persistence')
const { callbackify } = require('util') const { callbackify } = require('util')
@ -46,7 +45,7 @@ module.exports.getConfiguration = function (benchDb) {
* Ensure the workspace stat and the db datafile is empty * Ensure the workspace stat and the db datafile is empty
*/ */
module.exports.prepareDb = function (filename, cb) { 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) { fs.access(filename, fs.constants.FS_OK, function (err) {
if (!err) { if (!err) {
fs.unlink(filename, cb) fs.unlink(filename, cb)

@ -138,6 +138,17 @@ const unlinkAsync = async filename => {
*/ */
const mkdirAsync = (path, options) => Promise.resolve() 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<void|string>}
* @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. * Shim for {@link module:storage.ensureDatafileIntegrityAsync}, nothing to do, no data corruption possible in the browser.
* @param {string} filename * @param {string} filename
@ -176,3 +187,5 @@ module.exports.unlinkAsync = unlinkAsync
module.exports.mkdirAsync = mkdirAsync module.exports.mkdirAsync = mkdirAsync
module.exports.ensureDatafileIntegrityAsync = ensureDatafileIntegrityAsync module.exports.ensureDatafileIntegrityAsync = ensureDatafileIntegrityAsync
module.exports.ensureParentDirectoryExistsAsync = ensureParentDirectoryExistsAsync

@ -253,6 +253,17 @@ const crashSafeWriteFileLinesAsync = async (filename, lines) => {
*/ */
const crashSafeWriteFileLines = callbackify(crashSafeWriteFileLinesAsync) 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<void|string>}
* @alias module:storageBrowser.ensureParentDirectoryExistsAsync
* @async
*/
const ensureParentDirectoryExistsAsync = async (file, mode) => Promise.resolve()
// Interface // Interface
module.exports.exists = exists module.exports.exists = exists
module.exports.existsAsync = existsAsync module.exports.existsAsync = existsAsync
@ -280,3 +291,5 @@ module.exports.mkdirAsync = mkdirAsync
module.exports.ensureDatafileIntegrity = ensureDatafileIntegrity module.exports.ensureDatafileIntegrity = ensureDatafileIntegrity
module.exports.ensureDatafileIntegrityAsync = ensureDatafileIntegrityAsync module.exports.ensureDatafileIntegrityAsync = ensureDatafileIntegrityAsync
module.exports.ensureParentDirectoryExistsAsync = ensureParentDirectoryExistsAsync

@ -1,4 +1,3 @@
const path = require('path')
const { deprecate } = require('util') const { deprecate } = require('util')
const byline = require('./byline') const byline = require('./byline')
const customUtils = require('./customUtils.js') const customUtils = require('./customUtils.js')
@ -308,7 +307,7 @@ class Persistence {
// In-memory only datastore // In-memory only datastore
if (this.inMemoryOnly) return 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) await storage.ensureDatafileIntegrityAsync(this.filename, this.modes.fileMode)
let treatedData let treatedData
@ -372,12 +371,8 @@ class Persistence {
* @return {Promise<void>} * @return {Promise<void>}
* @private * @private
*/ */
static async ensureDirectoryExistsAsync (dir, mode = DEFAULT_DIR_MODE) { static async ensureParentDirectoryExistsAsync (dir, mode = DEFAULT_DIR_MODE) {
const parsedDir = path.parse(path.resolve(dir)) return storage.ensureParentDirectoryExistsAsync(dir, mode)
// 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 })
}
} }
} }

@ -1,6 +1,6 @@
/** /**
* Way data is stored for this database. * 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. * It's essentially fs, mkdirp and crash safe write and read functions.
* *
* @see module:storageBrowser * @see module:storageBrowser
@ -271,6 +271,22 @@ const ensureDatafileIntegrityAsync = async (filename, mode = DEFAULT_FILE_MODE)
else await renameAsync(tempFilename, filename) 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<void>}
* @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 // Interface
module.exports.existsAsync = existsAsync module.exports.existsAsync = existsAsync
@ -297,3 +313,5 @@ module.exports.flushToStorageAsync = flushToStorageAsync
module.exports.ensureDatafileIntegrityAsync = ensureDatafileIntegrityAsync module.exports.ensureDatafileIntegrityAsync = ensureDatafileIntegrityAsync
module.exports.ensureFileDoesntExistAsync = ensureFileDoesntExistAsync module.exports.ensureFileDoesntExistAsync = ensureFileDoesntExistAsync
module.exports.ensureParentDirectoryExistsAsync = ensureParentDirectoryExistsAsync

@ -2,7 +2,6 @@
const testDb = 'workspace/test.db' const testDb = 'workspace/test.db'
const { promises: fs } = require('fs') const { promises: fs } = require('fs')
const assert = require('assert').strict const assert = require('assert').strict
const path = require('path')
const Datastore = require('../lib/datastore') const Datastore = require('../lib/datastore')
const Persistence = require('../lib/persistence') const Persistence = require('../lib/persistence')
const Cursor = require('../lib/cursor') const Cursor = require('../lib/cursor')
@ -15,7 +14,7 @@ describe('Cursor Async', function () {
d = new Datastore({ filename: testDb }) d = new Datastore({ filename: testDb })
assert.equal(d.filename, testDb) assert.equal(d.filename, testDb)
assert.equal(d.inMemoryOnly, false) assert.equal(d.inMemoryOnly, false)
await Persistence.ensureDirectoryExistsAsync(path.dirname(testDb)) await Persistence.ensureParentDirectoryExistsAsync(testDb)
if (await exists(testDb)) await fs.unlink(testDb) if (await exists(testDb)) await fs.unlink(testDb)
await d.loadDatabaseAsync() await d.loadDatabaseAsync()
assert.equal(d.getAllData().length, 0) assert.equal(d.getAllData().length, 0)

@ -2,7 +2,6 @@
const chai = require('chai') const chai = require('chai')
const testDb = 'workspace/test.db' const testDb = 'workspace/test.db'
const fs = require('fs') const fs = require('fs')
const path = require('path')
const { each, waterfall } = require('./utils.test.js') const { each, waterfall } = require('./utils.test.js')
const Datastore = require('../lib/datastore') const Datastore = require('../lib/datastore')
const Persistence = require('../lib/persistence') const Persistence = require('../lib/persistence')
@ -22,7 +21,7 @@ describe('Cursor', function () {
waterfall([ waterfall([
function (cb) { 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) { fs.access(testDb, fs.constants.F_OK, function (err) {
if (!err) { if (!err) {
fs.unlink(testDb, cb) fs.unlink(testDb, cb)

@ -1,7 +1,6 @@
/* eslint-env mocha */ /* eslint-env mocha */
const testDb = 'workspace/test.db' const testDb = 'workspace/test.db'
const { promises: fs } = require('fs') const { promises: fs } = require('fs')
const path = require('path')
const assert = require('assert').strict const assert = require('assert').strict
const model = require('../lib/model') const model = require('../lib/model')
const Datastore = require('../lib/datastore') const Datastore = require('../lib/datastore')
@ -17,7 +16,7 @@ describe('Database async', function () {
d = new Datastore({ filename: testDb }) d = new Datastore({ filename: testDb })
assert.equal(d.filename, testDb) assert.equal(d.filename, testDb)
assert.equal(d.inMemoryOnly, false) assert.equal(d.inMemoryOnly, false)
await Persistence.ensureDirectoryExistsAsync(path.dirname(testDb)) await Persistence.ensureParentDirectoryExistsAsync(testDb)
if (await exists(testDb)) await fs.unlink(testDb) if (await exists(testDb)) await fs.unlink(testDb)
await d.loadDatabaseAsync() await d.loadDatabaseAsync()
assert.equal(d.getAllData().length, 0) assert.equal(d.getAllData().length, 0)

@ -2,7 +2,6 @@
const chai = require('chai') const chai = require('chai')
const testDb = 'workspace/test.db' const testDb = 'workspace/test.db'
const fs = require('fs') const fs = require('fs')
const path = require('path')
const { apply, each, waterfall } = require('./utils.test.js') const { apply, each, waterfall } = require('./utils.test.js')
const model = require('../lib/model') const model = require('../lib/model')
const Datastore = require('../lib/datastore') const Datastore = require('../lib/datastore')
@ -23,7 +22,7 @@ describe('Database', function () {
waterfall([ waterfall([
function (cb) { 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) { fs.access(testDb, fs.constants.FS_OK, function (err) {
if (!err) { if (!err) {
fs.unlink(testDb, cb) fs.unlink(testDb, cb)

@ -2,7 +2,6 @@
const testDb = 'workspace/test.db' const testDb = 'workspace/test.db'
const { promises: fs } = require('fs') const { promises: fs } = require('fs')
const assert = require('assert').strict const assert = require('assert').strict
const path = require('path')
const Datastore = require('../lib/datastore') const Datastore = require('../lib/datastore')
const Persistence = require('../lib/persistence') const Persistence = require('../lib/persistence')
const { exists } = require('./utils.test.js') const { exists } = require('./utils.test.js')
@ -53,7 +52,7 @@ describe('Executor async', function () {
d = new Datastore({ filename: testDb }) d = new Datastore({ filename: testDb })
assert.equal(d.filename, testDb) assert.equal(d.filename, testDb)
assert.equal(d.inMemoryOnly, false) assert.equal(d.inMemoryOnly, false)
await Persistence.ensureDirectoryExistsAsync(path.dirname(testDb)) await Persistence.ensureParentDirectoryExistsAsync(testDb)
if (await exists(testDb)) await fs.unlink(testDb) if (await exists(testDb)) await fs.unlink(testDb)
await d.loadDatabaseAsync() await d.loadDatabaseAsync()
assert.equal(d.getAllData().length, 0) assert.equal(d.getAllData().length, 0)

@ -2,7 +2,6 @@
const chai = require('chai') const chai = require('chai')
const testDb = 'workspace/test.db' const testDb = 'workspace/test.db'
const fs = require('fs') const fs = require('fs')
const path = require('path')
const { waterfall } = require('./utils.test.js') const { waterfall } = require('./utils.test.js')
const Datastore = require('../lib/datastore') const Datastore = require('../lib/datastore')
const Persistence = require('../lib/persistence') const Persistence = require('../lib/persistence')
@ -154,7 +153,7 @@ describe('Executor', function () {
waterfall([ waterfall([
function (cb) { 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) { fs.access(testDb, fs.constants.F_OK, function (err) {
if (!err) { if (!err) {
fs.unlink(testDb, cb) fs.unlink(testDb, cb)

@ -22,7 +22,7 @@ describe('Persistence async', function () {
d = new Datastore({ filename: testDb }) d = new Datastore({ filename: testDb })
assert.equal(d.filename, testDb) assert.equal(d.filename, testDb)
assert.equal(d.inMemoryOnly, false) assert.equal(d.inMemoryOnly, false)
await Persistence.ensureDirectoryExistsAsync(path.dirname(testDb)) await Persistence.ensureParentDirectoryExistsAsync(testDb)
if (await exists(testDb)) await fs.unlink(testDb) if (await exists(testDb)) await fs.unlink(testDb)
await d.loadDatabaseAsync() await d.loadDatabaseAsync()
assert.equal(d.getAllData().length, 0) assert.equal(d.getAllData().length, 0)
@ -1062,7 +1062,7 @@ describe('permissions', function () {
}) })
it('ensureDirectoryExists forwards mode argument', async () => { 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) assert.equal(await getMode(path.dirname(testDb)), 0o700)
}) })

@ -2,7 +2,6 @@
const chai = require('chai') const chai = require('chai')
const testDb = 'workspace/test.db' const testDb = 'workspace/test.db'
const fs = require('fs') const fs = require('fs')
const path = require('path')
const { apply, waterfall } = require('./utils.test.js') const { apply, waterfall } = require('./utils.test.js')
const model = require('../lib/model') const model = require('../lib/model')
const Datastore = require('../lib/datastore') const Datastore = require('../lib/datastore')
@ -27,7 +26,7 @@ describe('Persistence', function () {
waterfall([ waterfall([
function (cb) { 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) { fs.access(testDb, fs.constants.FS_OK, function (err) {
if (!err) { if (!err) {
fs.unlink(testDb, cb) fs.unlink(testDb, cb)

Loading…
Cancel
Save