Compare commits

..

11 Commits

Author SHA1 Message Date
Timothée Rebours 68279ccdf0 add version to changelog 11 months ago
Timothée Rebours 7b4b6856e1 4.0.4 11 months ago
Timothée Rebours a2469d14e9 add thanks in changelog 11 months ago
Timothée Rebours 6ed0db96d7 update Changelog 11 months ago
tex0l 1eeda8f1a6
Merge pull request #44 from RobMayer/update-types 11 months ago
tex0l bc10dded1a
Merge pull request #51 from seald/feat/clean-native-node-modules-imports 11 months ago
tex0l 60929bb9fc Fix typo lib/storage.js 11 months ago
Timothée Rebours 45aee76fea add mention that polyfills of util and events are still necessary 11 months ago
Timothée Rebours ff79ebfee2 add changelog 11 months ago
Timothée Rebours c9640889a0 remove 'path' imports 11 months ago
Rob Mayer 43d6285831 added explicit types to update query 1 year ago
  1. 10
      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. 12
      index.d.ts
  7. 11
      lib/persistence.js
  8. 20
      lib/storage.js
  9. 4
      package-lock.json
  10. 2
      package.json
  11. 3
      test/cursor.async.test.js
  12. 3
      test/cursor.test.js
  13. 3
      test/db.async.test.js
  14. 3
      test/db.test.js
  15. 3
      test/executor.async.test.js
  16. 3
      test/executor.test.js
  17. 4
      test/persistence.async.test.js
  18. 3
      test/persistence.test.js

@ -6,10 +6,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres
to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased
## [4.0.4] - 2024-01-11
### Fixed
- Explicitly import `buffer` [#34](https://github.com/seald/nedb/pull/34).
- Fix `Cursor`'s typings [#45](https://github.com/seald/nedb/issues/45)
- Explicitly import `buffer` [#34](https://github.com/seald/nedb/pull/34), thanks [maxdaniel98](https://github.com/maxdaniel98).
- 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 [#51](https://github.com/seald/nedb/pull/51).
- Explicit return/callback type for update based on options [#44](https://github.com/seald/nedb/pull/44), thanks [RobMayer](https://github.com/RobMayer).
## [4.0.3] - 2023-12-13
### Fixed
@ -76,7 +78,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`;

@ -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

@ -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)

@ -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<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.
* @param {string} filename
@ -176,3 +187,5 @@ module.exports.unlinkAsync = unlinkAsync
module.exports.mkdirAsync = mkdirAsync
module.exports.ensureDatafileIntegrityAsync = ensureDatafileIntegrityAsync
module.exports.ensureParentDirectoryExistsAsync = ensureParentDirectoryExistsAsync

@ -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<void|string>}
* @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

12
index.d.ts vendored

@ -105,25 +105,25 @@ declare class Nedb<Schema = Record<string, any>> extends EventEmitter {
projection?: any
): Nedb.Cursor<T>;
update<T extends Schema>(
update<T extends Schema, O extends Nedb.UpdateOptions>(
query: any,
updateQuery: any,
options?: Nedb.UpdateOptions,
options?: O,
callback?: (
err: Error | null,
numberOfUpdated: number,
affectedDocuments: Document<T> | Document<T>[] | null,
affectedDocuments: O['returnUpdatedDocs'] extends true ? O['multi'] extends true ? Document<T>[] | null : Document<T> | null : null,
upsert: boolean | null
) => void
): void;
updateAsync<T extends Schema>(
updateAsync<T extends Schema, O extends Nedb.UpdateOptions>(
query: any,
updateQuery: any,
options?: Nedb.UpdateOptions
options?: O
): Promise<{
numAffected: number;
affectedDocuments: Document<T> | Document<T>[] | null;
affectedDocuments: O['returnUpdatedDocs'] extends true ? O['multi'] extends true ? Document<T>[] | null : Document<T> | null : null;
upsert: boolean;
}>;

@ -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<void>}
* @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)
}
}

@ -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<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
module.exports.existsAsync = existsAsync
@ -297,3 +313,5 @@ module.exports.flushToStorageAsync = flushToStorageAsync
module.exports.ensureDatafileIntegrityAsync = ensureDatafileIntegrityAsync
module.exports.ensureFileDoesntExistAsync = ensureFileDoesntExistAsync
module.exports.ensureParentDirectoryExistsAsync = ensureParentDirectoryExistsAsync

4
package-lock.json generated

@ -1,12 +1,12 @@
{
"name": "@seald-io/nedb",
"version": "4.0.3",
"version": "4.0.4",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@seald-io/nedb",
"version": "4.0.3",
"version": "4.0.4",
"license": "MIT",
"dependencies": {
"@seald-io/binary-search-tree": "^1.0.3",

@ -1,6 +1,6 @@
{
"name": "@seald-io/nedb",
"version": "4.0.3",
"version": "4.0.4",
"files": [
"lib/**/*.js",
"browser-version/**/*.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)

@ -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)

@ -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)

@ -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)

@ -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)

@ -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)

@ -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)
})

@ -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)

Loading…
Cancel
Save