add typings

pull/12/head
mehdi 3 years ago
parent cd16711c89
commit fcd1546220
  1. 17
      .github/workflows/github-actions-demo.yml
  2. 117
      index.d.ts
  3. 43
      lib/datastore.js
  4. 268
      package-lock.json
  5. 9
      package.json
  6. 386
      typings-tests.ts

@ -3,13 +3,24 @@ name: Tests
on: [push, pull_request]
jobs:
node-tests:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Node.js 14
uses: actions/setup-node@v2
with:
node-version: 14.x
cache: 'npm'
- run: npm ci
- run: npm run lint
- run: npm run test:typings
node-tests:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x, 14.x, 16.x]
steps:
- uses: actions/checkout@v2
- name: Install Node.js ${{ matrix.node-version }}
@ -18,7 +29,6 @@ jobs:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm ci
- run: npm run lint
- run: npm run test
browser-tests:
@ -34,5 +44,4 @@ jobs:
- name: Install Chrome Stable
uses: browser-actions/setup-chrome@latest
- run: npm ci
- run: npm run lint
- run: npm run test:browser

117
index.d.ts vendored

@ -0,0 +1,117 @@
// Type definitions for @seald-io/nedb 2.1.0
// Project: https://github.com/seald/nedb forked from https://github.com/louischatriot/nedb
// Definitions by: Mehdi Kouhen <https://github.com/arantes555>
// Stefan Steinhart <https://github.com/reppners>
// Anthony Nichols <https://github.com/anthonynichols>
// Alejandro Fernandez Haro <https://github.com/afharo>
// TypeScript Version: 4.4
/// <reference types="node" />
import { EventEmitter } from 'events';
export default Nedb;
declare class Nedb<G = any> extends EventEmitter {
constructor(pathOrOptions?: string | Nedb.DataStoreOptions);
persistence: Nedb.Persistence;
loadDatabase(): void;
getAllData<T extends G>(): T[];
resetIndexes(newData?: any): void;
ensureIndex(options: Nedb.EnsureIndexOptions, callback?: (err: Error | null) => void): void;
removeIndex(fieldName: string, callback?: (err: Error | null) => void): void;
addToIndexes<T extends G>(doc: T | T[]): void;
removeFromIndexes<T extends G>(doc: T | T[]): void;
updateIndexes<T extends G>(oldDoc: T, newDoc: T): void;
updateIndexes<T extends G>(updates: Array<{ oldDoc: T; newDoc: T }>): void;
getCandidates<T extends G>(query: any, dontExpireStaleDocs: boolean, callback?: (err: Error | null, candidates: T[]) => void): void;
insert<T extends G>(newDoc: T, callback?: (err: Error | null, document: T) => void): void;
insert<T extends G>(newDocs: T[], callback?: (err: Error | null, documents: T[]) => void): void;
count(query: any, callback: (err: Error | null, n: number) => void): void;
count(query: any): Nedb.CursorCount;
find<T extends G>(query: any, projection: any, callback?: (err: Error | null, documents: T[]) => void): void;
find<T extends G>(query: any, projection?: any): Nedb.Cursor<T>;
find<T extends G>(query: any, callback: (err: Error | null, documents: T[]) => void): void;
findOne<T extends G>(query: any, projection: any, callback: (err: Error | null, document: T) => void): void;
findOne<T extends G>(query: any, callback: (err: Error | null, document: T) => void): void;
update<T extends G>(query: any, updateQuery: any, options?: Nedb.UpdateOptions, callback?: (err: Error | null, numberOfUpdated: number, affectedDocuments: T | T[] | null, upsert: boolean | null) => void): void;
remove(query: any, options: Nedb.RemoveOptions, callback?: (err: Error | null, n: number) => void): void;
remove(query: any, callback?: (err: Error | null, n: number) => void): void;
addListener(event: 'compaction.done', listener: () => void): this;
on(event: 'compaction.done', listener: () => void): this;
once(event: 'compaction.done', listener: () => void): this;
prependListener(event: 'compaction.done', listener: () => void): this;
prependOnceListener(event: 'compaction.done', listener: () => void): this;
removeListener(event: 'compaction.done', listener: () => void): this;
off(event: 'compaction.done', listener: () => void): this;
listeners(event: 'compaction.done'): Array<() => void>;
rawListeners(event: 'compaction.done'): Array<() => void>;
listenerCount(type: 'compaction.done'): number;
}
declare namespace Nedb {
interface Cursor<T> {
sort(query: any): Cursor<T>;
skip(n: number): Cursor<T>;
limit(n: number): Cursor<T>;
projection(query: any): Cursor<T>;
exec(callback: (err: Error | null, documents: T[]) => void): void;
}
interface CursorCount {
exec(callback: (err: Error | null, count: number) => void): void;
}
interface DataStoreOptions {
filename?: string;
timestampData?: boolean;
inMemoryOnly?: boolean;
nodeWebkitAppName?: boolean;
autoload?: boolean;
onload?(error: Error | null): any;
beforeDeserialization?(line: string): string;
afterSerialization?(line: string): string;
corruptAlertThreshold?: number;
compareStrings?(a: string, b: string): number;
}
interface UpdateOptions {
multi?: boolean;
upsert?: boolean;
returnUpdatedDocs?: boolean;
}
interface RemoveOptions {
multi?: boolean;
}
interface EnsureIndexOptions {
fieldName: string;
unique?: boolean;
sparse?: boolean;
expireAfterSeconds?: number;
}
interface Persistence {
compactDatafile(): void;
setAutocompactionInterval(interval: number): void;
stopAutocompaction(): void;
}
}

@ -14,8 +14,7 @@ class Datastore extends EventEmitter {
* @param {String} [options.filename] Optional, datastore will be in-memory only if not provided
* @param {Boolean} [options.timestampData] Optional, defaults to false. If set to true, createdAt and updatedAt will be created and populated automatically (if not specified by user)
* @param {Boolean} [options.inMemoryOnly] Optional, defaults to false
* @param {String} [options.nodeWebkitAppName] Optional, specify the name of your NW app if you want options.filename to be relative to the directory where
* Node Webkit stores application data such as cookies and local storage (the best place to store data in my opinion)
* @param {String} [options.nodeWebkitAppName] Optional, specify the name of your NW app if you want options.filename to be relative to the directory where Node Webkit stores application data such as cookies and local storage (the best place to store data in my opinion)
* @param {Boolean} [options.autoload] Optional, defaults to false
* @param {Function} [options.onload] Optional, if autoload is used this will be called after the load database with the error object as parameter. If you don't pass it the error will be thrown
* @param {Function} [options.beforeDeserialization] Optional, serialization hooks
@ -112,9 +111,9 @@ class Datastore extends EventEmitter {
* We use an async API for consistency with the rest of the code
* @param {Object} options
* @param {String} options.fieldName
* @param {Boolean} options.unique
* @param {Boolean} options.sparse
* @param {Number} options.expireAfterSeconds - Optional, if set this index becomes a TTL index (only works on Date fields, not arrays of Date)
* @param {Boolean} [options.unique]
* @param {Boolean} [options.sparse]
* @param {Number} [options.expireAfterSeconds] - Optional, if set this index becomes a TTL index (only works on Date fields, not arrays of Date)
* @param {Function} callback Optional callback, signature: err
*/
ensureIndex (options = {}, callback = () => {}) {
@ -321,16 +320,17 @@ class Datastore extends EventEmitter {
/**
* Insert a new document
* Private Use Datastore.insert which has the same signature
* @param {Document} newDoc
* @param {Function} callback Optional callback, signature: err, insertedDoc
*
* @api private Use Datastore.insert which has the same signature
* @private
*/
_insert (newDoc, callback = () => {}) {
let preparedDoc
try {
preparedDoc = this.prepareDocumentForInsertion(newDoc)
preparedDoc = this._prepareDocumentForInsertion(newDoc)
this._insertInCache(preparedDoc)
} catch (e) {
return callback(e)
@ -344,28 +344,29 @@ class Datastore extends EventEmitter {
/**
* Create a new _id that's not already in use
* @private
*/
createNewId () {
_createNewId () {
let attemptId = customUtils.uid(16)
// Try as many times as needed to get an unused _id. As explained in customUtils, the probability of this ever happening is extremely small, so this is O(1)
if (this.indexes._id.getMatching(attemptId).length > 0) attemptId = this.createNewId()
if (this.indexes._id.getMatching(attemptId).length > 0) attemptId = this._createNewId()
return attemptId
}
/**
* Prepare a document (or array of documents) to be inserted in a database
* Meaning adds _id and timestamps if necessary on a copy of newDoc to avoid any side effect on user input
* @api private
* @private
*/
prepareDocumentForInsertion (newDoc) {
_prepareDocumentForInsertion (newDoc) {
let preparedDoc
if (Array.isArray(newDoc)) {
preparedDoc = []
newDoc.forEach(doc => { preparedDoc.push(this.prepareDocumentForInsertion(doc)) })
newDoc.forEach(doc => { preparedDoc.push(this._prepareDocumentForInsertion(doc)) })
} else {
preparedDoc = model.deepCopy(newDoc)
if (preparedDoc._id === undefined) preparedDoc._id = this.createNewId()
if (preparedDoc._id === undefined) preparedDoc._id = this._createNewId()
const now = new Date()
if (this.timestampData && preparedDoc.createdAt === undefined) preparedDoc.createdAt = now
if (this.timestampData && preparedDoc.updatedAt === undefined) preparedDoc.updatedAt = now
@ -377,7 +378,7 @@ class Datastore extends EventEmitter {
/**
* If newDoc is an array of documents, this will insert all documents in the cache
* @api private
* @private
*/
_insertInCache (preparedDoc) {
if (Array.isArray(preparedDoc)) this._insertMultipleDocsInCache(preparedDoc)
@ -387,7 +388,7 @@ class Datastore extends EventEmitter {
/**
* If one insertion fails (e.g. because of a unique constraint), roll back all previous
* inserts and throws the error
* @api private
* @private
*/
_insertMultipleDocsInCache (preparedDocs) {
let failingIndex
@ -418,7 +419,7 @@ class Datastore extends EventEmitter {
/**
* Count all documents matching the query
* @param {Object} query MongoDB-style query
* @param {Query} query MongoDB-style query
* @param {Function} callback Optional callback, signature: err, count
*/
count (query, callback) {
@ -491,7 +492,8 @@ class Datastore extends EventEmitter {
}
/**
* Update all docs matching query
* Update all docs matching query.
* Use Datastore.update which has the same signature
* @param {Object} query
* @param {Object} updateQuery
* @param {Object} options Optional options
@ -513,7 +515,7 @@ class Datastore extends EventEmitter {
* user to check whether an upsert had occured: checking the type of affectedDocuments or running another find query on
* the whole dataset to check its size. Both options being ugly, the breaking change was necessary.
*
* @api private Use Datastore.update which has the same signature
* @private
*/
_update (query, updateQuery, options, cb) {
if (typeof options === 'function') {
@ -614,14 +616,15 @@ class Datastore extends EventEmitter {
}
/**
* Remove all docs matching the query
* Remove all docs matching the query.
* Use Datastore.remove which has the same signature
* For now very naive implementation (similar to update)
* @param {Object} query
* @param {Object} options Optional options
* options.multi If true, can update multiple documents (defaults to false)
* @param {Function} cb Optional callback, signature: err, numRemoved
*
* @api private Use Datastore.remove which has the same signature
* @private
*/
_remove (query, options, cb) {
if (typeof options === 'function') {

268
package-lock.json generated

@ -33,6 +33,7 @@
"standard": "^16.0.3",
"terser-webpack-plugin": "^5.1.2",
"timers-browserify": "^2.0.12",
"ts-node": "^10.3.0",
"webpack": "^5.37.0",
"webpack-cli": "^4.7.0",
"xvfb-maybe": "^0.2.1"
@ -135,6 +136,27 @@
"node": ">=4"
}
},
"node_modules/@cspotcode/source-map-consumer": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz",
"integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==",
"dev": true,
"engines": {
"node": ">= 12"
}
},
"node_modules/@cspotcode/source-map-support": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz",
"integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==",
"dev": true,
"dependencies": {
"@cspotcode/source-map-consumer": "0.8.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@discoveryjs/json-ext": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.3.tgz",
@ -192,6 +214,30 @@
"resolved": "https://registry.npmjs.org/@seald-io/binary-search-tree/-/binary-search-tree-1.0.2.tgz",
"integrity": "sha512-+pYGvPFAk7wUR+ONMOlc6A+LUN4kOCFwyPLjyaeS7wVibADPHWYJNYsNtyIAwjF1AXQkuaXElnIc4XjKt55QZA=="
},
"node_modules/@tsconfig/node10": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz",
"integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==",
"dev": true
},
"node_modules/@tsconfig/node12": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz",
"integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==",
"dev": true
},
"node_modules/@tsconfig/node14": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz",
"integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==",
"dev": true
},
"node_modules/@tsconfig/node16": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz",
"integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==",
"dev": true
},
"node_modules/@types/component-emitter": {
"version": "1.2.10",
"resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.10.tgz",
@ -494,6 +540,15 @@
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
"node_modules/acorn-walk": {
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
"integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
"dev": true,
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@ -565,6 +620,12 @@
"node": ">= 8"
}
},
"node_modules/arg": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
"dev": true
},
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
@ -1110,6 +1171,12 @@
"node": ">= 0.10"
}
},
"node_modules/create-require": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
"dev": true
},
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@ -3163,6 +3230,12 @@
"node": ">=10"
}
},
"node_modules/make-error": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
"dev": true
},
"node_modules/md5": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
@ -4970,6 +5043,68 @@
"node": ">=0.6"
}
},
"node_modules/ts-node": {
"version": "10.3.0",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.3.0.tgz",
"integrity": "sha512-RYIy3i8IgpFH45AX4fQHExrT8BxDeKTdC83QFJkNzkvt8uFB6QJ8XMyhynYiKMLxt9a7yuXaDBZNOYS3XjDcYw==",
"dev": true,
"dependencies": {
"@cspotcode/source-map-support": "0.7.0",
"@tsconfig/node10": "^1.0.7",
"@tsconfig/node12": "^1.0.7",
"@tsconfig/node14": "^1.0.0",
"@tsconfig/node16": "^1.0.2",
"acorn": "^8.4.1",
"acorn-walk": "^8.1.1",
"arg": "^4.1.0",
"create-require": "^1.1.0",
"diff": "^4.0.1",
"make-error": "^1.1.1",
"yn": "3.1.1"
},
"bin": {
"ts-node": "dist/bin.js",
"ts-node-cwd": "dist/bin-cwd.js",
"ts-node-script": "dist/bin-script.js",
"ts-node-transpile-only": "dist/bin-transpile.js",
"ts-script": "dist/bin-script-deprecated.js"
},
"peerDependencies": {
"@swc/core": ">=1.2.50",
"@swc/wasm": ">=1.2.50",
"@types/node": "*",
"typescript": ">=2.7"
},
"peerDependenciesMeta": {
"@swc/core": {
"optional": true
},
"@swc/wasm": {
"optional": true
}
}
},
"node_modules/ts-node/node_modules/acorn": {
"version": "8.5.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz",
"integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==",
"dev": true,
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/ts-node/node_modules/diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
"dev": true,
"engines": {
"node": ">=0.3.1"
}
},
"node_modules/tsconfig-paths": {
"version": "3.9.0",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz",
@ -5025,6 +5160,20 @@
"node": ">= 0.6"
}
},
"node_modules/typescript": {
"version": "4.4.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz",
"integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==",
"dev": true,
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=4.2.0"
}
},
"node_modules/ua-parser-js": {
"version": "0.7.28",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.28.tgz",
@ -5600,6 +5749,15 @@
"node": ">=8"
}
},
"node_modules/yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
"dev": true,
"engines": {
"node": ">=6"
}
},
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
@ -5698,6 +5856,21 @@
}
}
},
"@cspotcode/source-map-consumer": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz",
"integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==",
"dev": true
},
"@cspotcode/source-map-support": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz",
"integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==",
"dev": true,
"requires": {
"@cspotcode/source-map-consumer": "0.8.0"
}
},
"@discoveryjs/json-ext": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.3.tgz",
@ -5748,6 +5921,30 @@
"resolved": "https://registry.npmjs.org/@seald-io/binary-search-tree/-/binary-search-tree-1.0.2.tgz",
"integrity": "sha512-+pYGvPFAk7wUR+ONMOlc6A+LUN4kOCFwyPLjyaeS7wVibADPHWYJNYsNtyIAwjF1AXQkuaXElnIc4XjKt55QZA=="
},
"@tsconfig/node10": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz",
"integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==",
"dev": true
},
"@tsconfig/node12": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz",
"integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==",
"dev": true
},
"@tsconfig/node14": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz",
"integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==",
"dev": true
},
"@tsconfig/node16": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz",
"integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==",
"dev": true
},
"@types/component-emitter": {
"version": "1.2.10",
"resolved": "https://registry.npmjs.org/@types/component-emitter/-/component-emitter-1.2.10.tgz",
@ -6026,6 +6223,12 @@
"dev": true,
"requires": {}
},
"acorn-walk": {
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
"integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
"dev": true
},
"ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@ -6076,6 +6279,12 @@
"picomatch": "^2.0.4"
}
},
"arg": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
"dev": true
},
"argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
@ -6499,6 +6708,12 @@
"vary": "^1"
}
},
"create-require": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
"dev": true
},
"cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@ -8046,6 +8261,12 @@
"yallist": "^4.0.0"
}
},
"make-error": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
"dev": true
},
"md5": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
@ -9389,6 +9610,40 @@
"integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==",
"dev": true
},
"ts-node": {
"version": "10.3.0",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.3.0.tgz",
"integrity": "sha512-RYIy3i8IgpFH45AX4fQHExrT8BxDeKTdC83QFJkNzkvt8uFB6QJ8XMyhynYiKMLxt9a7yuXaDBZNOYS3XjDcYw==",
"dev": true,
"requires": {
"@cspotcode/source-map-support": "0.7.0",
"@tsconfig/node10": "^1.0.7",
"@tsconfig/node12": "^1.0.7",
"@tsconfig/node14": "^1.0.0",
"@tsconfig/node16": "^1.0.2",
"acorn": "^8.4.1",
"acorn-walk": "^8.1.1",
"arg": "^4.1.0",
"create-require": "^1.1.0",
"diff": "^4.0.1",
"make-error": "^1.1.1",
"yn": "3.1.1"
},
"dependencies": {
"acorn": {
"version": "8.5.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz",
"integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==",
"dev": true
},
"diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
"dev": true
}
}
},
"tsconfig-paths": {
"version": "3.9.0",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz",
@ -9432,6 +9687,13 @@
"mime-types": "~2.1.24"
}
},
"typescript": {
"version": "4.4.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz",
"integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==",
"dev": true,
"peer": true
},
"ua-parser-js": {
"version": "0.7.28",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.28.tgz",
@ -9853,6 +10115,12 @@
"is-plain-obj": "^2.1.0"
}
},
"yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
"dev": true
},
"yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",

@ -4,8 +4,10 @@
"files": [
"lib/**/*.js",
"browser-version/**/*.js",
"index.js"
"index.js",
"index.d.ts"
],
"types": "index.d.ts",
"author": {
"name": "Timothée Rebours",
"email": "tim@seald.io",
@ -63,6 +65,7 @@
"standard": "^16.0.3",
"terser-webpack-plugin": "^5.1.2",
"timers-browserify": "^2.0.12",
"ts-node": "^10.3.0",
"webpack": "^5.37.0",
"webpack-cli": "^4.7.0",
"xvfb-maybe": "^0.2.1"
@ -73,6 +76,7 @@
"build:browser": "webpack && webpack --optimization-minimize",
"pretest:browser": "npm run build:browser",
"test:browser": "xvfb-maybe karma start karma.conf.local.js",
"test:typings": "ts-node ./typings-tests.ts",
"prepublishOnly": "npm run build:browser"
},
"main": "index.js",
@ -87,7 +91,8 @@
},
"standard": {
"ignore": [
"browser-version/out"
"browser-version/out",
"**/*.ts"
]
}
}

@ -0,0 +1,386 @@
/**
* Created by stefansteinhart on 31.01.15.
* Modified my arantes555 on 19.10.2021.
*/
import Datastore from './'
import { mkdirSync } from 'fs'
mkdirSync('./workspace/typings/', { recursive: true })
process.chdir('./workspace/typings/')
// Type 1: In-memory only datastore (no need to load the database)
let db = new Datastore()
// Type 2: Persistent datastore with manual loading
db = new Datastore({ filename: 'path/to/datafile' })
db.loadDatabase()
// Type 3: Persistent datastore with automatic loading
db = new Datastore({ filename: 'path/to/datafile', autoload: true })
// You can issue commands right away
// Type 4: Persistent datastore for a Node Webkit app called 'nwtest'
// For example on Linux, the datafile will be ~/.config/nwtest/nedb-data/something.db
db = new Datastore({ filename: 'something.db' })
// Of course you can create multiple datastores if you need several
// collections. In this case it's usually a good idea to use autoload for all collections.
const dbContainer: any = {}
dbContainer.users = new Datastore('path/to/users.db')
dbContainer.robots = new Datastore('path/to/robots.db')
// You need to load each database (here we do it asynchronously)
dbContainer.users.loadDatabase()
dbContainer.robots.loadDatabase()
const doc: any = {
hello: 'world',
n: 5,
today: new Date(),
nedbIsAwesome: true,
notthere: null,
notToBeSaved: undefined, // Will not be saved
fruits: ['apple', 'orange', 'pear'],
infos: { name: 'nedb' }
}
db.insert(doc, (err: Error | null, newDoc: any) => { // Callback is optional
// newDoc is the newly inserted document, including its _id
// newDoc has no key called notToBeSaved since its value was undefined
})
db.insert([{ a: 5 }, { a: 42 }], (err: Error | null, newdocs: any[]) => {
// Two documents were inserted in the database
// newDocs is an array with these documents, augmented with their _id
})
// If there is a unique constraint on field 'a', this will fail
db.insert([{ a: 5 }, { a: 42 }, { a: 5 }], (err: Error | null) => {
// err is a 'uniqueViolated' error
// The database was not modified
})
// Finding all planets in the solar system
db.find({ system: 'solar' }, (err: Error | null, docs: any[]) => {
// docs is an array containing documents Mars, Earth, Jupiter
// If no document is found, docs is equal to []
})
// Finding all planets whose name contain the substring 'ar' using a regular expression
db.find({ planet: /ar/ }, (err: Error | null, docs: any[]) => {
// docs contains Mars and Earth
})
// Finding all inhabited planets in the solar system
db.find({ system: 'solar', inhabited: true }, (err: Error | null, docs: any[]) => {
// docs is an array containing document Earth only
})
// Use the dot-notation to match fields in subdocuments
db.find({ 'humans.genders': 2 }, (err: Error | null, docs: any[]) => {
// docs contains Earth
})
// Use the dot-notation to navigate arrays of subdocuments
db.find({ 'completeData.planets.name': 'Mars' }, (err: Error | null, docs: any[]) => {
// docs contains document 5
})
db.find({ 'completeData.planets.name': 'Jupiter' }, (err: Error | null, docs: any[]) => {
// docs is empty
})
db.find({ 'completeData.planets.0.name': 'Earth' }, (err: Error | null, docs: any[]) => {
// docs contains document 5
// If we had tested against "Mars" docs would be empty because we are matching against a specific array element
})
// You can also deep-compare objects. Don't confuse this with dot-notation!
db.find({ humans: { genders: 2 } }, (err: Error | null, docs: any[]) => {
// docs is empty, because { genders: 2 } is not equal to { genders: 2, eyes: true }
})
// Find all documents in the collection
db.find({}, (err: Error | null, docs: any[]) => {
})
// The same rules apply when you want to only find one document
db.findOne({ _id: 'id1' }, (err: Error | null, doc: any) => {
// doc is the document Mars
// If no document is found, doc is null
})
// $lt, $lte, $gt and $gte work on numbers and strings
db.find({ 'humans.genders': { $gt: 5 } }, (err: Error | null, docs: any[]) => {
// docs contains Omicron Persei 8, whose humans have more than 5 genders (7).
})
// When used with strings, lexicographical order is used
db.find({ planet: { $gt: 'Mercury' } }, (err: Error | null, docs: any[]) => {
// docs contains Omicron Persei 8
})
// Using $in. $nin is used in the same way
db.find({ planet: { $in: ['Earth', 'Jupiter'] } }, (err: Error | null, docs: any[]) => {
// docs contains Earth and Jupiter
})
// Using $exists
db.find({ satellites: { $exists: true } }, (err: Error | null, docs: any[]) => {
// docs contains only Mars
})
// Using $regex with another operator
db.find({ planet: { $regex: /ar/, $nin: ['Jupiter', 'Earth'] } }, (err: Error | null, docs: any[]) => {
// docs only contains Mars because Earth was excluded from the match by $nin
})
// Using an array-specific comparison function
// Note: you can't use nested comparison functions, e.g. { $size: { $lt: 5 } } will throw an error
db.find({ satellites: { $size: 2 } }, (err: Error | null, docs: any[]) => {
// docs contains Mars
})
db.find({ satellites: { $size: 1 } }, (err: Error | null, docs: any[]) => {
// docs is empty
})
// If a document's field is an array, matching it means matching any element of the array
db.find({ satellites: 'Phobos' }, (err: Error | null, docs: any[]) => {
// docs contains Mars. Result would have been the same if query had been { satellites: 'Deimos' }
})
// This also works for queries that use comparison operators
db.find({ satellites: { $lt: 'Amos' } }, (err: Error | null, docs: any[]) => {
// docs is empty since Phobos and Deimos are after Amos in lexicographical order
})
// This also works with the $in and $nin operator
db.find({ satellites: { $in: ['Moon', 'Deimos'] } }, (err: Error | null, docs: any[]) => {
// docs contains Mars (the Earth document is not complete!)
})
db.find({ $or: [{ planet: 'Earth' }, { planet: 'Mars' }] }, (err: Error | null, docs: any[]) => {
// docs contains Earth and Mars
})
db.find({ $not: { planet: 'Earth' } }, (err: Error | null, docs: any[]) => {
// docs contains Mars, Jupiter, Omicron Persei 8
})
db.find({
$where () {
return parseInt(Object.keys(this)[0], 10) > 6
}
}, (err: Error | null, docs: any[]) => {
// docs with more than 6 properties
})
// You can mix normal queries, comparison queries and logical operators
db.find({ $or: [{ planet: 'Earth' }, { planet: 'Mars' }], inhabited: true }, (err: Error | null, docs: any[]) => {
// docs contains Earth
})
// No query used means all results are returned (before the Cursor modifiers)
db.find({}).sort({ planet: 1 }).skip(1).limit(2).exec((err: Error | null, docs: any[]) => {
// docs is [doc3, doc1]
})
// You can sort in reverse order like this
db.find({ system: 'solar' }).sort({ planet: -1 }).exec((err: Error | null, docs: any[]) => {
// docs is [doc1, doc3, doc2]
})
// You can sort on one field, then another, and so on like this:
db.find({}).sort({ firstField: 1, secondField: -1 })
// Same database as above
// Keeping only the given fields
db.find({ planet: 'Mars' }, { planet: 1, system: 1 }, (err: Error | null, docs: any[]) => {
// docs is [{ planet: 'Mars', system: 'solar', _id: 'id1' }]
})
// Keeping only the given fields but removing _id
db.find({ planet: 'Mars' }, { planet: 1, system: 1, _id: 0 }, (err: Error | null, docs: any[]) => {
// docs is [{ planet: 'Mars', system: 'solar' }]
})
// Omitting only the given fields and removing _id
db.find({ planet: 'Mars' }, { planet: 0, system: 0, _id: 0 }, (err: Error | null, docs: any[]) => {
// docs is [{ inhabited: false, satellites: ['Phobos', 'Deimos'] }]
})
// Failure: using both modes at the same time
db.find({ planet: 'Mars' }, { planet: 0, system: 1 }, (err: Error | null, docs: any[]) => {
// err is the error message, docs is undefined
})
// You can also use it in a Cursor way but this syntax is not compatible with MongoDB
// If upstream compatibility is important don't use this method
db.find({ planet: 'Mars' }).projection({ planet: 1, system: 1 }).exec((err: Error | null, docs: any[]) => {
// docs is [{ planet: 'Mars', system: 'solar', _id: 'id1' }]
})
// Count all planets in the solar system
db.count({ system: 'solar' }, (err: Error | null, count: number) => {
// count equals to 3
})
// Count all documents in the datastore
db.count({}, (err: Error | null, count: number) => {
// count equals to 4
})
// Let's use the same example collection as in the "finding document" part
// { _id: 'id1', planet: 'Mars', system: 'solar', inhabited: false }
// { _id: 'id2', planet: 'Earth', system: 'solar', inhabited: true }
// { _id: 'id3', planet: 'Jupiter', system: 'solar', inhabited: false }
// { _id: 'id4', planet: 'Omicron Persia 8', system: 'futurama', inhabited: true }
// Replace a document by another
db.update({ planet: 'Jupiter' }, { planet: 'Pluton' }, {}, (err: Error | null, numReplaced: number) => {
// numReplaced = 1
// The doc #3 has been replaced by { _id: 'id3', planet: 'Pluton' }
// Note that the _id is kept unchanged, and the document has been replaced
// (the 'system' and inhabited fields are not here anymore)
})
// Set an existing field's value
db.update({ system: 'solar' }, { $set: { system: 'solar system' } }, { multi: true }, (err: Error | null, numReplaced: number) => {
// numReplaced = 3
// Field 'system' on Mars, Earth, Jupiter now has value 'solar system'
})
// Setting the value of a non-existing field in a subdocument by using the dot-notation
db.update({ planet: 'Mars' }, { $set: { 'data.satellites': 2, 'data.red': true } }, {}, () => {
// Mars document now is { _id: 'id1', system: 'solar', inhabited: false
// , data: { satellites: 2, red: true }
// }
// Not that to set fields in subdocuments, you HAVE to use dot-notation
// Using object-notation will just replace the top-level field
db.update({ planet: 'Mars' }, { $set: { data: { satellites: 3 } } }, {}, () => {
// Mars document now is { _id: 'id1', system: 'solar', inhabited: false
// , data: { satellites: 3 }
// }
// You lost the "data.red" field which is probably not the intended behavior
})
})
// Deleting a field
db.update({ planet: 'Mars' }, { $unset: { planet: true } }, {}, () => {
// Now the document for Mars doesn't contain the planet field
// You can unset nested fields with the dot notation of course
})
// Upserting a document
db.update({ planet: 'Pluton' }, {
planet: 'Pluton',
inhabited: false
}, { upsert: true }, (err: Error | null, numReplaced: number) => {
// numReplaced = 1, upsert = { _id: 'id5', planet: 'Pluton', inhabited: false }
// A new document { _id: 'id5', planet: 'Pluton', inhabited: false } has been added to the collection
})
// If you upsert with a modifier, the upserted doc is the query modified by the modifier
// This is simpler than it sounds :)
db.update({ planet: 'Pluton' }, { $inc: { distance: 38 } }, { upsert: true }, () => {
// A new document { _id: 'id5', planet: 'Pluton', distance: 38 } has been added to the collection
})
// If we insert a new document { _id: 'id6', fruits: ['apple', 'orange', 'pear'] } in the collection,
// let's see how we can modify the array field atomically
// $push inserts new elements at the end of the array
db.update({ _id: 'id6' }, { $push: { fruits: 'banana' } }, {}, () => {
// Now the fruits array is ['apple', 'orange', 'pear', 'banana']
})
// $pop removes an element from the end (if used with 1) or the front (if used with -1) of the array
db.update({ _id: 'id6' }, { $pop: { fruits: 1 } }, {}, () => {
// Now the fruits array is ['apple', 'orange']
// With { $pop: { fruits: -1 } }, it would have been ['orange', 'pear']
})
// $addToSet adds an element to an array only if it isn't already in it
// Equality is deep-checked (i.e. $addToSet will not insert an object in an array already containing the same object)
// Note that it doesn't check whether the array contained duplicates before or not
db.update({ _id: 'id6' }, { $addToSet: { fruits: 'apple' } }, {}, () => {
// The fruits array didn't change
// If we had used a fruit not in the array, e.g. 'banana', it would have been added to the array
})
// $pull removes all values matching a value or even any NeDB query from the array
db.update({ _id: 'id6' }, { $pull: { fruits: 'apple' } }, {}, () => {
// Now the fruits array is ['orange', 'pear']
})
db.update({ _id: 'id6' }, { $pull: { fruits: { $in: ['apple', 'pear'] } } }, {}, () => {
// Now the fruits array is ['orange']
})
// $each can be used to $push or $addToSet multiple values at once
// This example works the same way with $addToSet
db.update({ _id: 'id6' }, { $push: { fruits: { $each: ['banana', 'orange'] } } }, {}, () => {
// Now the fruits array is ['apple', 'orange', 'pear', 'banana', 'orange']
})
// Let's use the same example collection as in the "finding document" part
// { _id: 'id1', planet: 'Mars', system: 'solar', inhabited: false }
// { _id: 'id2', planet: 'Earth', system: 'solar', inhabited: true }
// { _id: 'id3', planet: 'Jupiter', system: 'solar', inhabited: false }
// { _id: 'id4', planet: 'Omicron Persia 8', system: 'futurama', inhabited: true }
// Remove one document from the collection
// options set to {} since the default for multi is false
db.remove({ _id: 'id2' }, {}, (err: Error | null, numRemoved: number) => {
// numRemoved = 1
})
// Remove multiple documents
db.remove({ system: 'solar' }, { multi: true }, (err: Error | null, numRemoved: number) => {
// numRemoved = 3
// All planets from the solar system were removed
})
db.ensureIndex({ fieldName: 'somefield' }, (err: Error | null) => {
// If there was an error, err is not null
})
// Using a unique constraint with the index
db.ensureIndex({ fieldName: 'somefield', unique: true }, (err: Error | null) => {
})
// Using a sparse unique index
db.ensureIndex({ fieldName: 'somefield', unique: true, sparse: true }, (err: Error | null) => {
})
// Example of using expireAfterSeconds to remove documents 1 hour
// after their creation (db's timestampData option is true here)
db.ensureIndex({ fieldName: 'somefield', expireAfterSeconds: 3600 }, (err: Error | null) => {
})
// Format of the error message when the unique constraint is not met
db.insert({ somefield: 'nedb' }, (err: Error | null) => {
// err is null
db.insert({ somefield: 'nedb' }, (err: Error | null) => {
// err is { errorType: 'uniqueViolated'
// , key: 'name'
// , message: 'Unique constraint violated for key name' }
})
})
// Remove index on field somefield
db.removeIndex('somefield', (err: Error | null) => {
})
db.addListener('compaction.done', () => {})
db.on('compaction.done', () => {})
db.once('compaction.done', () => {})
db.prependListener('compaction.done', () => {})
db.prependOnceListener('compaction.done', () => {})
db.removeListener('compaction.done', () => {})
db.off('compaction.done', () => {})
db.listeners('compaction.done') // $ExpectType (() => void)[]
db.rawListeners('compaction.done') // $ExpectType (() => void)[]
db.listenerCount('compaction.done') // $ExpectType number
Loading…
Cancel
Save