diff --git a/src/database.ts b/src/database.ts index c5cf7a5d..6e370ab8 100644 --- a/src/database.ts +++ b/src/database.ts @@ -23,7 +23,7 @@ if (typeof writev === 'function') { }; } -async function exportAsync(database: Database, path: string) { +async function exportAsync(database: Database, path: string): Promise { const handle = await open(path, 'w'); try { @@ -79,7 +79,7 @@ interface DatabaseOptions { class Database { options: DatabaseOptions; - _models: any; + _models: Record; Model: typeof Model; /** @@ -117,7 +117,7 @@ class Database { * @param {Schema|object} [schema] * @return {Model} */ - model(name: string, schema?: any) { + model(name: string, schema?: Schema | object): Model { if (this._models[name]) { return this._models[name]; } @@ -133,7 +133,7 @@ class Database { * @param {function} [callback] * @return {Promise} */ - load(callback?) { + load(callback?: NodeJSLikeCallback): Bluebird { const { path, onUpgrade, onDowngrade, version: newVersion } = this.options; if (!path) throw new WarehouseError('options.path is required'); @@ -173,14 +173,14 @@ class Database { * @param {function} [callback] * @return {Promise} */ - save(callback?) { + save(callback?: NodeJSLikeCallback): Bluebird{ const { path } = this.options; if (!path) throw new WarehouseError('options.path is required'); return Bluebird.resolve(exportAsync(this, path)).asCallback(callback); } - toJSON() { + toJSON(): { meta: { version: number, warehouse: string }, models: Record } { const models = Object.keys(this._models) .reduce((obj, key) => { const value = this._models[key]; diff --git a/src/document.ts b/src/document.ts index 2c23b2e5..fd4a7401 100644 --- a/src/document.ts +++ b/src/document.ts @@ -1,17 +1,20 @@ import rfdc from 'rfdc'; +import type Model from './model'; +import type Schema from './schema'; const cloneDeep = rfdc(); abstract class Document { - abstract _model; - _id!: any; - abstract _schema; + abstract _model: Model; + _id!: string | number | undefined; + abstract _schema: Schema; + [key: PropertyKey]: any; /** * Document constructor. * * @param {object} data */ - constructor(data) { + constructor(data?: object) { if (data) { Object.assign(this, data); } @@ -23,7 +26,7 @@ abstract class Document { * @param {function} [callback] * @return {Promise} */ - save(callback) { + save(callback?: NodeJSLikeCallback): Promise { return this._model.save(this, callback); } @@ -34,7 +37,7 @@ abstract class Document { * @param {function} [callback] * @return {Promise} */ - update(data, callback) { + update(data: Record, callback?: NodeJSLikeCallback): Promise { return this._model.updateById(this._id, data, callback); } @@ -45,7 +48,7 @@ abstract class Document { * @param {function} [callback] * @return {Promise} */ - replace(data, callback) { + replace(data: object | Document, callback?: NodeJSLikeCallback): Promise { return this._model.replaceById(this._id, data, callback); } @@ -55,7 +58,7 @@ abstract class Document { * @param {function} [callback] * @return {Promise} */ - remove(callback) { + remove(callback?: NodeJSLikeCallback): Promise { return this._model.removeById(this._id, callback); } @@ -64,7 +67,7 @@ abstract class Document { * * @return {object} */ - toObject() { + toObject(): object { const keys = Object.keys(this); const obj = {}; @@ -83,7 +86,7 @@ abstract class Document { * * @return {String} */ - toString() { + toString(): string { return JSON.stringify(this); } @@ -93,13 +96,13 @@ abstract class Document { * @param {String|Object} expr * @return {Document} */ - populate(expr) { + populate(expr: string | any[] | { path?: string; model?: any; [key: PropertyKey]: any }): Document { const stack = this._schema._parsePopulate(expr); return this._model._populate(this, stack); } } -function isGetter(obj, key) { +function isGetter(obj: any, key: PropertyKey): any { return Object.getOwnPropertyDescriptor(obj, key).get; } diff --git a/src/lib/jsonstream/index.ts b/src/lib/jsonstream/index.ts index e028660b..9a5dbf2f 100644 --- a/src/lib/jsonstream/index.ts +++ b/src/lib/jsonstream/index.ts @@ -7,7 +7,7 @@ import Parser from 'jsonparse'; * @param {*} y * @returns {boolean} */ -const check = (x, y) => { +const check = (x, y): boolean => { if (typeof x === 'string') { return y === x; } @@ -27,7 +27,7 @@ const check = (x, y) => { return false; }; -export function parse(path, map = null) { +export function parse(path: string | any[], map = null) { let header, footer; const parser = new Parser(); diff --git a/src/model.ts b/src/model.ts index ea3e4ffa..3f9a0d88 100644 --- a/src/model.ts +++ b/src/model.ts @@ -10,26 +10,27 @@ import * as Types from './types/index'; import WarehouseError from './error'; import PopulationError from './error/population'; import Mutex from './mutex'; +import type Database from './database'; class Model extends EventEmitter { _mutex = new Mutex(); - data: Record = {}; - schema; + data: Record = {}; + schema: Schema; length = 0; Document; Query; - _database; + _database: Database; /** * Model constructor. * * @param {string} name Model name - * @param {Schema|object} [schema] Schema + * @param {Schema|object} [schema_] Schema */ - constructor(public name: string, schema_) { + constructor(public name: string, schema_: Schema | object) { super(); - let schema; + let schema: Schema; // Define schema if (schema_ instanceof Schema) { @@ -50,7 +51,7 @@ class Model extends EventEmitter { class _Document extends Document { _model!: Model; _schema!: Schema; - constructor(data) { + constructor(data: object) { super(data); // Apply getters @@ -86,7 +87,7 @@ class Model extends EventEmitter { * @param {object} data * @return {Document} */ - new(data) { + new(data?: object): Document { return new this.Document(data); } @@ -98,7 +99,7 @@ class Model extends EventEmitter { * @param {boolean} [options.lean=false] Returns a plain JavaScript object * @return {Document|object} */ - findById(id, options_?) { + findById(id: PropertyKey, options_?: Options): Document | Record { const raw = this.data[id]; if (!raw) return; @@ -116,7 +117,7 @@ class Model extends EventEmitter { * @param {*} id * @return {boolean} */ - has(id) { + has(id: PropertyKey): boolean { return Boolean(this.data[id]); } @@ -143,11 +144,11 @@ class Model extends EventEmitter { * @return {Promise} * @private */ - _insertOne(data_) { + _insertOne(data_: Document | object): Promise { const schema = this.schema; // Apply getters - const data = data_ instanceof this.Document ? data_ : this.new(data_); + const data = (data_ instanceof this.Document ? data_ : this.new(data_)) as Document; const id = data._id; // Check ID @@ -181,7 +182,7 @@ class Model extends EventEmitter { * @param {function} [callback] * @return {Promise} */ - insertOne(data, callback?) { + insertOne(data: Document | object, callback?: NodeJSLikeCallback): Promise { return Promise.using(this._acquireWriteLock(), () => this._insertOne(data)).asCallback(callback); } @@ -192,7 +193,7 @@ class Model extends EventEmitter { * @param {function} [callback] * @return {Promise} */ - insert(data, callback) { + insert(data: object | object[], callback?: NodeJSLikeCallback): Promise { if (Array.isArray(data)) { return Promise.mapSeries(data, item => this.insertOne(item)).asCallback(callback); } @@ -207,8 +208,8 @@ class Model extends EventEmitter { * @param {function} [callback] * @return {Promise} */ - save(data, callback) { - const id = data._id; + save(data: Document | object, callback?: NodeJSLikeCallback): Promise { + const id = (data as any)._id; if (!id) return this.insertOne(data, callback); @@ -229,7 +230,7 @@ class Model extends EventEmitter { * @return {Promise} * @private */ - _updateWithStack(id, stack): Promise { + _updateWithStack(id: string | number, stack: any[]): Promise { const schema = this.schema; const data = this.data[id]; @@ -271,7 +272,7 @@ class Model extends EventEmitter { * @param {function} [callback] * @return {Promise} */ - updateById(id, update, callback?) { + updateById(id: string | number, update: Record, callback?: NodeJSLikeCallback): Promise { return Promise.using(this._acquireWriteLock(), () => { const stack = this.schema._parseUpdate(update); return this._updateWithStack(id, stack); @@ -286,8 +287,8 @@ class Model extends EventEmitter { * @param {function} [callback] * @return {Promise} */ - update(query, data, callback?) { - return this.find(query).update(data, callback); + update(query: object, data: object, callback?: NodeJSLikeCallback): Promise { + return (this.find(query) as Query).update(data, callback); } /** @@ -298,17 +299,17 @@ class Model extends EventEmitter { * @return {Promise} * @private */ - _replaceById(id, data_) { + _replaceById(id: string | number, data_: Document | object): Promise { const schema = this.schema; if (!this.has(id)) { return Promise.reject(new WarehouseError('ID `' + id + '` does not exist', WarehouseError.ID_NOT_EXIST)); } - data_._id = id; + (data_ as any)._id = id; // Apply getters - const data = data_ instanceof this.Document ? data_ : this.new(data_); + const data = (data_ instanceof this.Document ? data_ : this.new(data_)) as Document; // Apply setters const result = data.toObject(); @@ -332,7 +333,7 @@ class Model extends EventEmitter { * @param {function} [callback] * @return {Promise} */ - replaceById(id, data, callback?) { + replaceById(id: string | number, data: Document | object, callback?: NodeJSLikeCallback): Promise { return Promise.using(this._acquireWriteLock(), () => this._replaceById(id, data)).asCallback(callback); } @@ -344,19 +345,18 @@ class Model extends EventEmitter { * @param {function} [callback] * @return {Promise} */ - replace(query, data, callback?) { - return this.find(query).replace(data, callback); + replace(query: object, data, callback?: NodeJSLikeCallback): Promise { + return (this.find(query) as Query).replace(data, callback); } /** * Finds a document by its identifier and remove it. * * @param {*} id - * @param {function} [callback] * @return {Promise} * @private */ - _removeById(id) { + _removeById(id: string | number): Promise { const schema = this.schema; const data = this.data[id]; @@ -383,7 +383,7 @@ class Model extends EventEmitter { * @param {function} [callback] * @return {Promise} */ - removeById(id, callback) { + removeById(id: string | number, callback?: NodeJSLikeCallback): Promise { return Promise.using(this._acquireWriteLock(), () => this._removeById(id)).asCallback(callback); } @@ -391,17 +391,17 @@ class Model extends EventEmitter { * Removes matching documents. * * @param {object} query - * @param {object} [callback] + * @param {function} [callback] * @return {Promise} */ - remove(query, callback) { - return this.find(query).remove(callback); + remove(query: object, callback?: NodeJSLikeCallback): Promise { + return (this.find(query) as Query).remove(callback); } /** * Deletes a model. */ - destroy() { + destroy(): void { this._database._models[this.name] = null; } @@ -410,7 +410,7 @@ class Model extends EventEmitter { * * @return {number} */ - count() { + count(): number { return this.length; } @@ -420,7 +420,7 @@ class Model extends EventEmitter { * @param {function} iterator * @param {object} [options] See {@link Model#findById}. */ - forEach(iterator, options?) { + forEach(iterator: (value: any, index: number) => any, options?: Options): void { const keys = Object.keys(this.data); let num = 0; @@ -436,7 +436,7 @@ class Model extends EventEmitter { * @param {Object} [options] See {@link Model#findById}. * @return {Array} */ - toArray(options?) { + toArray(options?: Options): any[] { const result = new Array(this.length); this.forEach((item, i) => { @@ -456,7 +456,7 @@ class Model extends EventEmitter { * @param {Boolean} [options.lean=false] Returns a plain JavaScript object. * @return {Query|Array} */ - find(query, options: { limit?: number; skip?: number; lean?: boolean; } = {}) { + find(query: object, options: Options = {}): Query | any[] { const filter = this.schema._execQuery(query); const keys = Object.keys(this.data); const len = keys.length; @@ -491,11 +491,11 @@ class Model extends EventEmitter { * @param {Boolean} [options.lean=false] Returns a plain JavaScript object. * @return {Document|Object} */ - findOne(query, options_ : { skip?: number; lean?: boolean; } = {}) { + findOne(query: object, options_ : Options = {}): Document | Record { const options = Object.assign(options_, { limit: 1 }); const result = this.find(query, options); - return options.lean ? result[0] : result.data[0]; + return options.lean ? (result as any[])[0] : (result as Query).toArray()[0]; } /** @@ -505,7 +505,7 @@ class Model extends EventEmitter { * @param {String|Number} [order] * @return {Query} */ - sort(orderby, order) { + sort(orderby: string | object, order?: string | number): Query { const sort = parseArgs(orderby, order); const fn = this.schema._execSort(sort); @@ -520,7 +520,7 @@ class Model extends EventEmitter { * @param {Object} [options] See {@link Model#findById}. * @return {Document|Object} */ - eq(i_, options?) { + eq(i_: number, options?: Options): Document | Record { let index = i_ < 0 ? this.length + i_ : i_; const data = this.data; const keys = Object.keys(data); @@ -545,7 +545,7 @@ class Model extends EventEmitter { * @param {Object} [options] See {@link Model#findById}. * @return {Document|Object} */ - first(options) { + first(options?: Options): Document | Record { return this.eq(0, options); } @@ -555,7 +555,7 @@ class Model extends EventEmitter { * @param {Object} [options] See {@link Model#findById}. * @return {Document|Object} */ - last(options) { + last(options?: Options): Document | Record { return this.eq(-1, options); } @@ -566,7 +566,7 @@ class Model extends EventEmitter { * @param {Number} [end] * @return {Query} */ - slice(start_: number, end_?: number) { + slice(start_?: number, end_?: number): Query { const total = this.length; let start = start_ | 0; @@ -605,7 +605,7 @@ class Model extends EventEmitter { * @param {Number} i * @return {Query} */ - limit(i) { + limit(i: number): Query { return this.slice(0, i); } @@ -615,7 +615,7 @@ class Model extends EventEmitter { * @param {Number} i * @return {Query} */ - skip(i) { + skip(i: number): Query { return this.slice(i); } @@ -624,7 +624,7 @@ class Model extends EventEmitter { * * @return {Query} */ - reverse() { + reverse(): Query { return new this.Query(this.toArray().reverse()); } @@ -633,7 +633,7 @@ class Model extends EventEmitter { * * @return {Query} */ - shuffle() { + shuffle(): Query { return new this.Query(shuffle(this.toArray())); } @@ -644,7 +644,7 @@ class Model extends EventEmitter { * @param {Object} [options] * @return {Array} */ - map(iterator, options) { + map(iterator: (value: any, index: number) => T, options?: Options): T[] { const result = new Array(this.length); const keys = Object.keys(this.data); const len = keys.length; @@ -668,10 +668,10 @@ class Model extends EventEmitter { * @param {*} [initial] By default, the initial value is the first document. * @return {*} */ - reduce(iterator, initial) { + reduce(iterator: (pre: any, cur: any, index: number) => T, initial?: T): T { const arr = this.toArray(); const len = this.length; - let i, result; + let i: number, result: any; if (initial === undefined) { i = 1; @@ -696,7 +696,7 @@ class Model extends EventEmitter { * @param {*} [initial] By default, the initial value is the last document. * @return {*} */ - reduceRight(iterator, initial) { + reduceRight(iterator: (pre: any, cur: any, index: number) => T, initial?: T): T { const arr = this.toArray(); const len = this.length; let i, result; @@ -724,10 +724,10 @@ class Model extends EventEmitter { * @param {Object} [options] * @return {Query} */ - filter(iterator, options) { + filter(iterator: (value: any, index: number) => any, options?: Options): Query { const arr = []; - this.forEach((item, i) => { + this.forEach((item: any, i: number) => { if (iterator(item, i)) arr.push(item); }, options); @@ -741,7 +741,7 @@ class Model extends EventEmitter { * @param {Function} iterator * @return {Boolean} */ - every(iterator) { + every(iterator: (value: any, index: number) => any): boolean { const keys = Object.keys(this.data); const len = keys.length; let num = 0; @@ -766,7 +766,7 @@ class Model extends EventEmitter { * @param {Function} iterator * @return {Boolean} */ - some(iterator) { + some(iterator: (value: any, index: number) => any): boolean { const keys = Object.keys(this.data); const len = keys.length; let num = 0; @@ -793,9 +793,9 @@ class Model extends EventEmitter { * @return {Function} * @private */ - _populateGetter(data, model, options) { + _populateGetter(data: string | number, model: Model, options: unknown) { let hasCache = false; - let cache; + let cache: Record | Document; return () => { if (!hasCache) { @@ -816,10 +816,10 @@ class Model extends EventEmitter { * @return {Function} * @private */ - _populateGetterArray(data, model, options) { + _populateGetterArray(data: any[], model: Model, options: Options): () => any[] | Query { const Query = model.Query; let hasCache = false; - let cache; + let cache: any[] | Query; return () => { if (!hasCache) { @@ -830,7 +830,7 @@ class Model extends EventEmitter { } if (options.match) { - cache = new Query(arr).find(options.match, options); + cache = (new Query(arr) as Query).find(options.match, options); } else if (options.skip) { if (options.limit) { arr = arr.slice(options.skip, options.skip + options.limit); @@ -864,7 +864,7 @@ class Model extends EventEmitter { * @return {Object} * @private */ - _populate(data, stack) { + _populate(data: Document, stack: any[]): Document { const models = this._database._models; for (let i = 0, len = stack.length; i < len; i++) { @@ -894,7 +894,7 @@ class Model extends EventEmitter { * @param {String|Object} path * @return {Query} */ - populate(path) { + populate(path: string | any[] | { path?: string; model?: any; [key: PropertyKey]: any }): Query { if (!path) throw new TypeError('path is required'); const stack = this.schema._parsePopulate(path); @@ -913,7 +913,7 @@ class Model extends EventEmitter { * @param {Array} arr * @private */ - _import(arr) { + _import(arr: any[]) { const len = arr.length; const data = this.data; const schema = this.schema; @@ -932,11 +932,11 @@ class Model extends EventEmitter { * @return {String} * @private */ - _export() { + _export(): string { return JSON.stringify(this.toJSON()); } - toJSON() { + toJSON(): any[] { const result = new Array(this.length); const { data, schema } = this; const keys = Object.keys(data); @@ -958,7 +958,7 @@ class Model extends EventEmitter { Model.prototype.get = Model.prototype.findById; -function execHooks(schema, type, event, data) { +function execHooks(schema: Schema, type: string, event: string, data: any): Promise { const hooks = schema.hooks[type][event] as ((data: any) => Promise | void)[]; if (!hooks.length) return Promise.resolve(data); diff --git a/src/mutex.ts b/src/mutex.ts index 6eaa0ab4..dec0dbea 100644 --- a/src/mutex.ts +++ b/src/mutex.ts @@ -6,7 +6,7 @@ class Mutex { this._queue = []; } - lock(fn: () => void) { + lock(fn: () => void): void { if (this._locked) { this._queue.push(fn); return; @@ -16,7 +16,7 @@ class Mutex { fn(); } - unlock() { + unlock(): void { if (!this._locked) return; const next = this._queue.shift(); diff --git a/src/query.ts b/src/query.ts index 0eb8fae4..8a54adba 100644 --- a/src/query.ts +++ b/src/query.ts @@ -1,17 +1,22 @@ import Promise from 'bluebird'; import { parseArgs, shuffle } from './util'; +import type Model from './model'; +import type Schema from './schema'; +import type Document from './document'; abstract class Query { + data: any[]; length: number; - abstract _model; - abstract _schema; + abstract _model: Model; + abstract _schema: Schema; /** * Query constructor. * * @param {Array} data */ - constructor(private data: any[]) { + constructor(data: any[]) { + this.data = data; this.length = data.length; } @@ -53,7 +58,7 @@ abstract class Query { * @param {Number} i * @return {Document|Object} */ - eq(i: number) { + eq(i: number): Document | Record { const index = i < 0 ? this.length + i : i; return this.data[index]; } @@ -63,7 +68,7 @@ abstract class Query { * * @return {Document|Object} */ - first() { + first(): Document | Record { return this.eq(0); } @@ -72,7 +77,7 @@ abstract class Query { * * @return {Document|Object} */ - last() { + last(): Document | Record { return this.eq(-1); } @@ -135,7 +140,7 @@ abstract class Query { * @param {Boolean} [options.lean=false] Returns a plain JavaScript object. * @return {Query|Array} */ - find(query: any, options: { limit?: number; skip?: number; lean?: boolean; } = {}): any[] | Query { + find(query: object, options: Options = {}): any[] | Query { const filter = this._schema._execQuery(query); const { data, length } = this; const { lean = false } = options; @@ -167,7 +172,7 @@ abstract class Query { * @param {Boolean} [options.lean=false] Returns a plain JavaScript object. * @return {Document|Object} */ - findOne(query: any, options: { skip?: number; lean?: boolean; } = {}): any { + findOne(query: object, options: Options = {}): Document | Record { const _options = Object.assign(options, { limit: 1 }); const result = this.find(query, _options); @@ -192,7 +197,7 @@ abstract class Query { * @param {String|Number} [order] * @return {Query} */ - sort(orderby, order): Query { + sort(orderby: string | object, order?: string | number | object): Query { const sort = parseArgs(orderby, order); const fn = this._schema._execSort(sort); @@ -224,9 +229,9 @@ abstract class Query { * @param {*} [initial] By default, the initial value is the first document. * @return {*} */ - reduce(iterator, initial?) { + reduce(iterator: (pre: any, cur: any, index: number) => T, initial?: T): T { const { data, length } = this; - let result, i; + let result: T, i: number; if (initial === undefined) { i = 1; @@ -251,7 +256,7 @@ abstract class Query { * @param {*} [initial] By default, the initial value is the last document. * @return {*} */ - reduceRight(iterator, initial?) { + reduceRight(iterator: (pre: any, cur: any, index: number) => T, initial?: T): T { const { data, length } = this; let result, i; @@ -330,7 +335,7 @@ abstract class Query { * @param {Function} [callback] * @return {Promise} */ - update(data: any, callback?: (err?: any) => void): Promise { + update(data: any, callback?: NodeJSLikeCallback): Promise { const model = this._model; const stack = this._schema._parseUpdate(data); @@ -344,7 +349,7 @@ abstract class Query { * @param {Function} [callback] * @return {Promise} */ - replace(data: any, callback?: (err?: any) => void): Promise { + replace(data: any, callback?: NodeJSLikeCallback): Promise { const model = this._model; return Promise.map(this.data, item => model.replaceById(item._id, data)).asCallback(callback); @@ -356,7 +361,7 @@ abstract class Query { * @param {Function} [callback] * @return {Promise} */ - remove(callback) { + remove(callback?: NodeJSLikeCallback): Promise { const model = this._model; return Promise.mapSeries(this.data, item => model.removeById(item._id)).asCallback(callback); @@ -368,7 +373,7 @@ abstract class Query { * @param {String|Object} expr * @return {Query} */ - populate(expr: any): Query { + populate(expr: string | any[] | { path?: string; model?: any; [key: PropertyKey]: any }): Query { const stack = this._schema._parsePopulate(expr); const { data, length } = this; const model = this._model; diff --git a/src/schema.ts b/src/schema.ts index f9f81590..e6c54840 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -11,12 +11,14 @@ import { isPlainObject } from 'is-plain-object'; * @param {*} data * @return {boolean} */ +type queryFilterCallback = (data: unknown) => boolean; /** * @callback queryCallback * @param {*} data * @return {void} */ +type queryCallback = (data: unknown) => void; /** * @callback queryParseCallback @@ -24,16 +26,21 @@ import { isPlainObject } from 'is-plain-object'; * @param {*} b * @returns {*} */ +type queryParseCallback = (a: unknown, b: unknown) => number; /** * @typedef PopulateResult * @property {string} path * @property {*} model */ +type PopulateResult = { + path: string; + model: any; +}; const builtinTypes = new Set(['String', 'Number', 'Boolean', 'Array', 'Object', 'Date', 'Buffer']); -const getSchemaType = (name, options) => { +const getSchemaType = (name: string, options: Record | { type: any; }) => { const Type = options.type || options; const typeName = Type.name; @@ -44,13 +51,14 @@ const getSchemaType = (name, options) => { return new Type(name, options); }; -const checkHookType = type => { +const checkHookType = (type: string) => { if (type !== 'save' && type !== 'remove') { throw new TypeError('Hook type must be `save` or `remove`!'); } }; -const hookWrapper = fn => { +const hookWrapper = (fn: (callback: NodeJSLikeCallback, options?: Promise.PromisifyOptions) => void) + : (callback?: NodeJSLikeCallback) => Promise => { if (fn.length > 1) { return Promise.promisify(fn); } @@ -61,10 +69,10 @@ const hookWrapper = fn => { /** * @param {Function[]} stack */ -const execSortStack = stack => { +const execSortStack = (stack: Function[]) => { const len = stack.length; - return (a, b) => { + return (a: any, b: any) => { let result; for (let i = 0; i < len; i++) { @@ -76,32 +84,32 @@ const execSortStack = stack => { }; }; -const sortStack = (path_, key, sort) => { +const sortStack = (path_: SchemaType, key: string, sort: string | number) => { const path = path_ || new SchemaType(key); const descending = sort === 'desc' || sort === -1; - return (a, b) => { + return (a: any, b: any) => { const result = path.compare(getProp(a, key), getProp(b, key)); return descending && result ? result * -1 : result; }; }; class UpdateParser { - static updateStackNormal(key, update) { - return data => { setProp(data, key, update); }; + static updateStackNormal(key: string, update: any) { + return (data: any) => { setProp(data, key, update); }; } - static updateStackOperator(path_, ukey, key, update) { + static updateStackOperator(path_: SchemaType, ukey: string | number, key: string, update: any) { const path = path_ || new SchemaType(key); - return data => { + return (data: any) => { const result = path[ukey](getProp(data, key), update, data); setProp(data, key, result); }; } // eslint-disable-next-line no-useless-constructor - constructor(private paths) {} + constructor(private paths: Record>) { } /** * Parses updating expressions and returns a stack. @@ -110,11 +118,11 @@ class UpdateParser { * @param {queryCallback[]} [stack] * @private */ - parseUpdate(updates, prefix = '', stack = []) { + parseUpdate(updates: object, prefix = '', stack: queryCallback[] = []): queryCallback[] { const { paths } = this; const { updateStackOperator } = UpdateParser; const keys = Object.keys(updates); - let path, prefixNoDot; + let path: SchemaType, prefixNoDot: string; if (prefix) { prefixNoDot = prefix.substring(0, prefix.length - 1); @@ -158,7 +166,7 @@ class UpdateParser { */ class QueryParser { // eslint-disable-next-line no-useless-constructor - constructor(private paths) {} + constructor(private paths: Record>) { } /** * @@ -166,10 +174,10 @@ class QueryParser { * @param {*} query * @return {queryFilterCallback} */ - queryStackNormal(name, query) { + queryStackNormal(name: string, query: unknown): queryFilterCallback { const path = this.paths[name] || new SchemaType(name); - return data => path.match(getProp(data, name), query, data); + return (data: unknown) => path.match(getProp(data, name), query, data); } /** @@ -179,7 +187,7 @@ class QueryParser { * @param {*} query * @return {queryFilterCallback} */ - queryStackOperator(qkey, name, query) { + queryStackOperator(qkey: string, name: string, query: any): queryFilterCallback { const path = this.paths[name] || new SchemaType(name); return data => path[qkey](getProp(data, name), query, data); @@ -191,7 +199,7 @@ class QueryParser { * @return {void} * @private */ - $and(arr, stack) { + $and(arr: any[], stack: queryFilterCallback[]): void { for (let i = 0, len = arr.length; i < len; i++) { stack.push(this.execQuery(arr[i])); } @@ -202,7 +210,7 @@ class QueryParser { * @return {queryFilterCallback} * @private */ - $or(query) { + $or(query: any[]): queryFilterCallback { const stack = this.parseQueryArray(query); const len = stack.length; @@ -220,7 +228,7 @@ class QueryParser { * @return {queryFilterCallback} * @private */ - $nor(query) { + $nor(query: any[]): queryFilterCallback { const stack = this.parseQueryArray(query); const len = stack.length; @@ -238,7 +246,7 @@ class QueryParser { * @return {queryFilterCallback} * @private */ - $not(query) { + $not(query: any): queryFilterCallback { const stack = this.parseQuery(query); const len = stack.length; @@ -262,7 +270,7 @@ class QueryParser { * @return {queryFilterCallback} * @private */ - $where(fn) { + $where(fn: (...args: any[]) => boolean): queryFilterCallback { return data => Reflect.apply(fn, data, []); } @@ -273,7 +281,7 @@ class QueryParser { * @return {queryFilterCallback[]} * @private */ - parseQueryArray(arr) { + parseQueryArray(arr: any[]): queryFilterCallback[] { const stack = []; this.$and(arr, stack); return stack; @@ -288,7 +296,7 @@ class QueryParser { * @return {void} * @private */ - parseNormalQuery(queries, prefix, stack = []) { + parseNormalQuery(queries: object, prefix: string, stack: queryFilterCallback[] = []): void { const keys = Object.keys(queries); for (let i = 0, len = keys.length; i < len; i++) { @@ -316,10 +324,10 @@ class QueryParser { * @return {queryFilterCallback[]} * @private */ - parseQuery(queries) { + parseQuery(queries: any): queryFilterCallback[] { /** @type {queryFilterCallback[]} */ - const stack = []; + const stack: queryFilterCallback[] = []; const keys = Object.keys(queries); for (let i = 0, len = keys.length; i < len; i++) { @@ -366,7 +374,7 @@ class QueryParser { * @return {queryFilterCallback} * @private */ - execQuery(query) { + execQuery(query: object): queryFilterCallback { const stack = this.parseQuery(query); const len = stack.length; @@ -392,7 +400,7 @@ class Schema { * * @param {Object} [schema] */ - constructor(schema?) { + constructor(schema?: object) { this.hooks = { pre: { save: [], @@ -422,7 +430,7 @@ class Schema { * @param {Object} schema * @param {String} prefix */ - add(schema: Record, prefix = ''): void { + add(schema: Record, prefix: string = ''): void { const keys = Object.keys(schema); const len = keys.length; @@ -458,7 +466,7 @@ class Schema { } else { switch (typeof obj) { case 'function': - type = getSchemaType(name, {type: obj}); + type = getSchemaType(name, { type: obj }); break; case 'object': @@ -493,7 +501,7 @@ class Schema { * @param {SchemaType} type * @private */ - _updateStack(name: string, type: SchemaType) { + _updateStack(name: string, type: SchemaType): void { const { stacks } = this; stacks.getter.push(data => { @@ -559,7 +567,7 @@ class Schema { * @param {String} type Hook type. One of `save` or `remove`. * @param {Function} fn */ - pre(type, fn) { + pre(type: string, fn: (callback: NodeJSLikeCallback, options?: Promise.PromisifyOptions) => void): void { checkHookType(type); if (typeof fn !== 'function') throw new TypeError('Hook must be a function!'); @@ -572,7 +580,7 @@ class Schema { * @param {String} type Hook type. One of `save` or `remove`. * @param {Function} fn */ - post(type, fn) { + post(type: string, fn: (callback: NodeJSLikeCallback, options?: Promise.PromisifyOptions) => void): void { checkHookType(type); if (typeof fn !== 'function') throw new TypeError('Hook must be a function!'); @@ -585,7 +593,7 @@ class Schema { * @param {String} name * @param {Function} fn */ - method(name, fn) { + method(name: string | number, fn: (...args: any[]) => any) { if (!name) throw new TypeError('Method name is required!'); if (typeof fn !== 'function') { @@ -601,7 +609,7 @@ class Schema { * @param {String} name * @param {Function} fn */ - static(name: string, fn) { + static(name: string, fn: (...args: any[]) => any) { if (!name) throw new TypeError('Method name is required!'); if (typeof fn !== 'function') { @@ -618,7 +626,7 @@ class Schema { * @return {void} * @private */ - _applyGetters(data) { + _applyGetters(data: object): void { const stack = this.stacks.getter; for (let i = 0, len = stack.length; i < len; i++) { @@ -633,7 +641,7 @@ class Schema { * @return {void} * @private */ - _applySetters(data) { + _applySetters(data: object): void { const stack = this.stacks.setter; for (let i = 0, len = stack.length; i < len; i++) { @@ -682,7 +690,7 @@ class Schema { * @return {queryCallback[]} * @private */ - _parseUpdate(updates) { + _parseUpdate(updates): queryCallback[] { return new UpdateParser(this.paths).parseUpdate(updates); } @@ -693,7 +701,7 @@ class Schema { * @return {queryFilterCallback} * @private */ - _execQuery(query) { + _execQuery(query): queryFilterCallback { return new QueryParser(this.paths).execQuery(query); } @@ -707,7 +715,7 @@ class Schema { * @return {queryParseCallback[]} * @private */ - _parseSort(sorts, prefix = '', stack = []) { + _parseSort(sorts: object, prefix: string = '', stack: queryParseCallback[] = []): queryParseCallback[] { const { paths } = this; const keys = Object.keys(sorts); @@ -733,7 +741,7 @@ class Schema { * @return {queryParseCallback} * @private */ - _execSort(sorts) { + _execSort(sorts: object): queryParseCallback { const stack = this._parseSort(sorts); return execSortStack(stack); } @@ -746,7 +754,7 @@ class Schema { * @private */ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types - _parsePopulate(expr) { + _parsePopulate(expr: string | any[] | { path?: string; model?: any; [key: PropertyKey]: any }): PopulateResult[] { const { paths } = this; const arr = []; diff --git a/src/schematype.ts b/src/schematype.ts index 22dea735..5983af70 100644 --- a/src/schematype.ts +++ b/src/schematype.ts @@ -56,7 +56,7 @@ class SchemaType { * @param {Boolean} [options.required=false] * @param {*} [options.default] */ - constructor(public name = '', options?: { required?: boolean; default?: (() => T) | T; }) { + constructor(public name: string = '', options?: { required?: boolean; default?: (() => T) | T; }) { this.options = Object.assign({ required: false }, options); @@ -244,7 +244,7 @@ class SchemaType { * @param {Object} data * @return {Boolean} */ - q$nin(value, query, data?) { + q$nin(value: unknown, query: unknown[], data?: unknown): boolean { return !query.includes(value); } @@ -256,7 +256,7 @@ class SchemaType { * @param {Object} data * @return {*} */ - u$set(value, update, data?) { + u$set(value: unknown, update: T, data?: unknown): T { return update; } @@ -268,7 +268,7 @@ class SchemaType { * @param {Object} data * @return {*} */ - u$unset(value, update, data?) { return update ? undefined : value; } + u$unset(value: T, update: boolean, data?: unknown): T | undefined { return update ? undefined : value; } /** * Renames a field. @@ -278,7 +278,7 @@ class SchemaType { * @param {Object} data * @return {*} */ - u$rename(value, update, data): void { + u$rename(value: unknown, update: unknown, data: unknown): void { if (value !== undefined) setProp(data, update, value); return undefined; } diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 00000000..d7124870 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,8 @@ +type NodeJSLikeCallback = (err: E, result?: R) => void + +interface Options { + lean?: boolean; + skip?: number; + limit?: number; + [key: PropertyKey]: any; +} \ No newline at end of file diff --git a/src/types/array.ts b/src/types/array.ts index 3c51f36f..493dbce5 100644 --- a/src/types/array.ts +++ b/src/types/array.ts @@ -29,10 +29,12 @@ class SchemaTypeArray> extends SchemaType { /** * Casts an array and its child elements. * - * @param {*} value + * @param {*} value_ * @param {Object} data * @return {Array} */ + cast(value_: Exclude, data?: unknown): I[]; + cast(value_?: unknown, data?: unknown): I[] | null | undefined; cast(value_?: unknown, data?: unknown): I[] | null | undefined { value_ = super.cast(value_, data); if (value_ == null) return value_ as null | undefined; @@ -52,7 +54,7 @@ class SchemaTypeArray> extends SchemaType { /** * Validates an array and its child elements. * - * @param {*} value + * @param {*} value_ * @param {Object} data * @return {Array|Error} */ @@ -107,8 +109,10 @@ class SchemaTypeArray> extends SchemaType { * @param {Array} value * @return {Array} */ - parse(value?: unknown[]) { - if (!value) return value; + parse(value: unknown[]): I[]; + parse(): undefined; + parse(value?: unknown[]): I[] | undefined { + if (!value) return value as undefined; const len = value.length; if (!len) return []; @@ -117,7 +121,7 @@ class SchemaTypeArray> extends SchemaType { const child = this.child; for (let i = 0; i < len; i++) { - result[i] = child.parse(value[i]); + result[i] = child.parse(value[i]) as I; } return result; @@ -130,8 +134,10 @@ class SchemaTypeArray> extends SchemaType { * @param {Object} data * @return {Array} */ - value(value?: unknown[], data?: unknown): any[] { - if (!value) return value; + value(value: unknown[], data?: unknown): any[] + value(): undefined; + value(value?: unknown[], data?: unknown): any[] | undefined { + if (!value) return value as undefined; const len = value.length; if (!len) return []; @@ -211,7 +217,7 @@ class SchemaTypeArray> extends SchemaType { * @param {Object} data * @return {Boolean} */ - q$nin(value?: unknown[], query?: unknown[], data?: unknown): boolean { + q$nin(value?: T[], query?: T[], data?: unknown): boolean { if (!value) return true; for (let i = 0, len = query.length; i < len; i++) { @@ -229,7 +235,7 @@ class SchemaTypeArray> extends SchemaType { * @param {Object} data * @return {Boolean} */ - q$all(value?: unknown[], query?: unknown[], data?: unknown): boolean { + q$all(value?: T[], query?: T[], data?: unknown): boolean { if (!value) return false; for (let i = 0, len = query.length; i < len; i++) { @@ -268,7 +274,7 @@ class SchemaTypeArray> extends SchemaType { * @param {Object} data * @return {Array} */ - u$unshift(value?: unknown[], update?: unknown, data?: unknown): any[] { + u$unshift(value?: T[], update?: T | T[], data?: unknown): T[] { if (isArray(update)) { return value ? update.concat(value) : update; } @@ -289,7 +295,7 @@ class SchemaTypeArray> extends SchemaType { * @param {Object} data * @return {Array} */ - u$pull(value?: unknown[], update?: unknown, data?: unknown): any[] { + u$pull(value?: T[], update?: T | T[], data?: unknown): T[] { if (!value) return value; if (isArray(update)) { @@ -307,7 +313,7 @@ class SchemaTypeArray> extends SchemaType { * @param {Object} data * @return {Array} */ - u$shift(value?, update?, data?) { + u$shift(value?: T[], update?: number | boolean, data?: unknown): T[] { if (!value || !update) return value; if (update === true) { @@ -327,7 +333,7 @@ class SchemaTypeArray> extends SchemaType { * @param {Object} data * @return {Array} */ - u$pop(value?, update?, data?) { + u$pop(value?: T[], update?: number | boolean, data?: unknown): T[] { if (!value || !update) return value; const length = value.length; @@ -349,7 +355,7 @@ class SchemaTypeArray> extends SchemaType { * @param {Object} data * @return {Array} */ - u$addToSet(value?: any[], update?, data?) { + u$addToSet(value?: T[], update?: T | T[], data?: unknown): T[] { if (isArray(update)) { if (!value) return update; diff --git a/src/types/boolean.ts b/src/types/boolean.ts index 55330fde..1160dfe2 100644 --- a/src/types/boolean.ts +++ b/src/types/boolean.ts @@ -9,7 +9,7 @@ class SchemaTypeBoolean extends SchemaType { /** * Casts a boolean. * - * @param {*} value + * @param {*} value_ * @param {Object} data * @return {Boolean} */ @@ -24,7 +24,7 @@ class SchemaTypeBoolean extends SchemaType { /** * Validates a boolean. * - * @param {*} value + * @param {*} value_ * @param {Object} data * @return {Boolean|Error} */ diff --git a/src/types/buffer.ts b/src/types/buffer.ts index 73cc157e..7cb1da73 100644 --- a/src/types/buffer.ts +++ b/src/types/buffer.ts @@ -14,7 +14,7 @@ class SchemaTypeBuffer extends SchemaType { * @param {boolean|Function} [options.default] * @param {string} [options.encoding=hex] */ - constructor(name: string, options?) { + constructor(name: string, options?: Partial['options']> & { encoding?: BufferEncoding; }) { super(name, Object.assign({ encoding: 'hex' }, options)); @@ -23,11 +23,13 @@ class SchemaTypeBuffer extends SchemaType { /** * Casts data. * - * @param {*} value + * @param {*} value_ * @param {Object} data * @return {Buffer} */ - cast(value_?: unknown, data?): Buffer | null | undefined { + cast(value_: WithImplicitCoercion | string>, data?: unknown): Buffer; + cast(value_?: unknown, data?: unknown): Buffer | null | undefined; + cast(value_?: unknown, data?: unknown): Buffer | null | undefined { const value = super.cast(value_, data); if (value == null || Buffer.isBuffer(value)) return value as Buffer | null | undefined; @@ -38,11 +40,11 @@ class SchemaTypeBuffer extends SchemaType { /** * Validates data. * - * @param {*} value + * @param {*} value_ * @param {Object} data * @return {Buffer} */ - validate(value_: unknown, data?): Buffer { + validate(value_: unknown, data?: unknown): Buffer { const value = super.validate(value_, data); if (!Buffer.isBuffer(value)) { @@ -73,7 +75,9 @@ class SchemaTypeBuffer extends SchemaType { * @param {*} value * @return {Boolean} */ - parse(value?) { + parse(value: WithImplicitCoercion | string>): Buffer; + parse(value?: unknown): Buffer | null | undefined; + parse(value?: any): Buffer | null | undefined { return value ? Buffer.from(value, this.options.encoding) : value; } @@ -81,9 +85,9 @@ class SchemaTypeBuffer extends SchemaType { * Transforms data into number to compress the size of database files. * * @param {Buffer} value - * @return {Number} + * @return {String} */ - value(value?: Buffer) { + value(value?: Buffer): string { return Buffer.isBuffer(value) ? value.toString(this.options.encoding) : value; } diff --git a/src/types/cuid.ts b/src/types/cuid.ts index 49b057c6..476cfa0c 100644 --- a/src/types/cuid.ts +++ b/src/types/cuid.ts @@ -14,7 +14,7 @@ class SchemaTypeCUID extends SchemaType { * @param {String} value * @return {String} */ - cast(value?) { + cast(value?: string): string { if (value == null && this.options.required) { return cuid(); } @@ -28,7 +28,7 @@ class SchemaTypeCUID extends SchemaType { * @param {*} value * @return {String|Error} */ - validate(value?) { + validate(value?: string): string { if (value && (value[0] !== 'c' || value.length !== 25)) { throw new ValidationError(`\`${value}\` is not a valid CUID`); } diff --git a/src/types/date.ts b/src/types/date.ts index 40727b87..636e29be 100644 --- a/src/types/date.ts +++ b/src/types/date.ts @@ -9,14 +9,12 @@ class SchemaTypeDate extends SchemaType { /** * Casts data. * - * @param {*} value + * @param {*} value_ * @return {Date | null | undefined} */ - cast(value_?): Date | null | undefined; - cast(value_: Date): Date; - cast(value_: null): Date | null; - cast(value_: undefined): Date | undefined; - cast(value_: unknown): Date | null | undefined { + cast(value_: Date | number | string): Date; + cast(value_?: unknown): Date | null | undefined; + cast(value_?: unknown): Date | null | undefined { const value = super.cast(value_, null); if (value == null || value instanceof Date) return value as Date | null | undefined; @@ -27,18 +25,18 @@ class SchemaTypeDate extends SchemaType { /** * Validates data. * - * @param {*} value + * @param {*} value_ * @param {Object} data * @return {Date|Error} */ - validate(value_, data?) { + validate(value_: unknown, data?: unknown): Date { const value = super.validate(value_, data); if (value != null && (!(value instanceof Date) || isNaN(value.getTime()))) { throw new ValidationError(`\`${value}\` is not a valid date!`); } - return value; + return value as Date; } /** @@ -63,9 +61,9 @@ class SchemaTypeDate extends SchemaType { * @param {Date} b * @return {Number} */ - compare(a?, b?) { + compare(a?: Date, b?: Date): number { if (a) { - return b ? a - b : 1; + return b ? (a as unknown as number) - (b as unknown as number) : 1; } return b ? -1 : 0; @@ -77,7 +75,9 @@ class SchemaTypeDate extends SchemaType { * @param {*} value * @return {Date} */ - parse(value?) { + parse(value: string | number | Date): Date; + parse(): undefined; + parse(value?: string | number | Date): Date | undefined { if (value) return new Date(value); } @@ -87,8 +87,10 @@ class SchemaTypeDate extends SchemaType { * @param {Date} value * @return {String} */ - value(value?) { - return value ? value.toISOString() : value; + value(value: Date): string; + value(): undefined; + value(value?: Date): string | undefined { + return value ? value.toISOString() : value as undefined; } /** @@ -98,7 +100,7 @@ class SchemaTypeDate extends SchemaType { * @param {Number} query * @return {Boolean} */ - q$day(value, query) { + q$day(value: Date | undefined, query: number): boolean { return value ? value.getDate() === query : false; } @@ -109,7 +111,7 @@ class SchemaTypeDate extends SchemaType { * @param {Number} query * @return {Boolean} */ - q$month(value, query) { + q$month(value: Date | undefined, query: number): boolean { return value ? value.getMonth() === query : false; } @@ -120,7 +122,7 @@ class SchemaTypeDate extends SchemaType { * @param {Number} query * @return {Boolean} */ - q$year(value, query) { + q$year(value: Date | undefined, query: number): boolean { return value ? value.getFullYear() === query : false; } @@ -131,7 +133,7 @@ class SchemaTypeDate extends SchemaType { * @param {Number} update * @return {Date} */ - u$inc(value, update) { + u$inc(value: Date | undefined, update: number): Date { if (value) return new Date(value.getTime() + update); } @@ -142,7 +144,7 @@ class SchemaTypeDate extends SchemaType { * @param {Number} update * @return {Date} */ - u$dec(value, update) { + u$dec(value: Date | undefined, update: number): Date { if (value) return new Date(value.getTime() - update); } } diff --git a/src/types/enum.ts b/src/types/enum.ts index 1a96d88c..42ee6c26 100644 --- a/src/types/enum.ts +++ b/src/types/enum.ts @@ -15,7 +15,7 @@ class SchemaTypeEnum extends SchemaType { * @param {Array} options.elements * @param {*} [options.default] */ - constructor(name, options) { + constructor(name: string, options?: Partial['options']> & { elements?: any[] }) { super(name, Object.assign({ elements: [] }, options)); @@ -24,11 +24,11 @@ class SchemaTypeEnum extends SchemaType { /** * Validates data. The value must be one of elements set in the options. * - * @param {*} value + * @param {*} value_ * @param {Object} data * @return {*} */ - validate(value_, data?) { + validate(value_: unknown, data?: unknown) { const value = super.validate(value_, data); const elements = this.options.elements; diff --git a/src/types/integer.ts b/src/types/integer.ts index 97b74d5e..c5400212 100644 --- a/src/types/integer.ts +++ b/src/types/integer.ts @@ -9,11 +9,11 @@ class SchemaTypeInteger extends SchemaTypeNumber { /** * Casts a integer. * - * @param {*} value + * @param {*} value_ * @param {Object} data * @return {Number} */ - cast(value_?, data?): number { + cast(value_?: unknown, data?: unknown): number { const value = super.cast(value_, data); return parseInt(value as any, 10); @@ -22,11 +22,11 @@ class SchemaTypeInteger extends SchemaTypeNumber { /** * Validates an integer. * - * @param {*} value + * @param {*} value_ * @param {Object} data * @return {Number|Error} */ - validate(value_?, data?): number { + validate(value_?: unknown, data?: unknown): number { const value = super.validate(value_, data); if (!Number.isInteger(value)) { diff --git a/src/types/number.ts b/src/types/number.ts index 83dcbe2c..fdae9c87 100644 --- a/src/types/number.ts +++ b/src/types/number.ts @@ -13,7 +13,9 @@ class SchemaTypeNumber extends SchemaType { * @param {Object} data * @return {Number} */ - cast(value_?, data?): number | null | undefined { + cast(value_: Exclude, data?: unknown): number; + cast(value_?: unknown, data?: unknown): number | null | undefined; + cast(value_?: unknown, data?: unknown): number | null | undefined { const value = super.cast(value_, data); if (value == null || typeof value === 'number') return value as number | null | undefined; @@ -28,14 +30,14 @@ class SchemaTypeNumber extends SchemaType { * @param {Object} data * @return {Number|Error} */ - validate(value_?, data?) { + validate(value_?: unknown, data?: unknown): number { const value = super.validate(value_, data); if (value !== undefined && (typeof value !== 'number' || isNaN(value))) { throw new ValidationError(`\`${value}\` is not a number!`); } - return value; + return value as number; } /** @@ -45,7 +47,7 @@ class SchemaTypeNumber extends SchemaType { * @param {Number} update * @return {Number} */ - u$inc(value, update) { + u$inc(value: number | undefined, update: number): number { return value ? value + update : update; } @@ -56,7 +58,7 @@ class SchemaTypeNumber extends SchemaType { * @param {Number} update * @return {Number} */ - u$dec(value, update) { + u$dec(value: number | undefined, update: number): number { return value ? value - update : -update; } @@ -67,7 +69,7 @@ class SchemaTypeNumber extends SchemaType { * @param {Number} update * @return {Number} */ - u$mul(value, update) { + u$mul(value: number | undefined, update: number): number { return value ? value * update : 0; } @@ -78,7 +80,7 @@ class SchemaTypeNumber extends SchemaType { * @param {Number} update * @return {Number} */ - u$div(value, update) { + u$div(value: number | undefined, update: number): number { return value ? value / update : 0; } @@ -89,7 +91,7 @@ class SchemaTypeNumber extends SchemaType { * @param {Number} update * @return {Number} */ - u$mod(value, update) { + u$mod(value: number | undefined, update: number): number { return value ? value % update : 0; } @@ -100,7 +102,7 @@ class SchemaTypeNumber extends SchemaType { * @param {Number} update * @return {Number} */ - u$max(value, update) { + u$max(value: number | undefined, update: number): number { return update > value ? update : value; } @@ -111,7 +113,7 @@ class SchemaTypeNumber extends SchemaType { * @param {Number} update * @return {Number} */ - u$min(value, update) { + u$min(value: number | undefined, update: number): number { return update < value ? update : value; } } diff --git a/src/types/object.ts b/src/types/object.ts index 840fa20c..7024288d 100644 --- a/src/types/object.ts +++ b/src/types/object.ts @@ -12,7 +12,7 @@ class SchemaTypeObject extends SchemaType> { * @param {Boolean} [options.required=false] * @param {Object|Function} [options.default={}] */ - constructor(name?, options?) { + constructor(name?: string, options?: Partial>['options']>) { super(name, Object.assign({ default: {} }, options)); } } diff --git a/src/types/string.ts b/src/types/string.ts index 589ee085..1156078e 100644 --- a/src/types/string.ts +++ b/src/types/string.ts @@ -9,32 +9,34 @@ class SchemaTypeString extends SchemaType { /** * Casts a string. * - * @param {*} value + * @param {*} value_ * @param {Object} data * @return {String} */ - cast(value_?, data?) { + cast(value_: { toString(): string }, data?: unknown): string; + cast(value_?: unknown, data?: unknown): string | null | undefined; + cast(value_?: unknown, data?: unknown): string | null | undefined { const value = super.cast(value_, data); - if (value == null || typeof value === 'string') return value; + if (value == null || typeof value === 'string') return value as string | null | undefined; if (typeof value.toString === 'function') return value.toString(); } /** * Validates a string. * - * @param {*} value + * @param {*} value_ * @param {Object} data * @return {String|Error} */ - validate(value_?, data?) { + validate(value_?: unknown, data?: unknown): string { const value = super.validate(value_, data); if (value !== undefined && typeof value !== 'string') { throw new ValidationError(`\`${value}\` is not a string!`); } - return value; + return value as string; } /** @@ -45,13 +47,13 @@ class SchemaTypeString extends SchemaType { * @param {Object} data * @return {Boolean} */ - match(value, query, data?) { + match(value: string | undefined, query: string | RegExp | undefined, data?: unknown): boolean { if (!value || !query) { return value === query; } - if (typeof query.test === 'function') { - return query.test(value); + if (typeof (query as any).test === 'function') { + return (query as RegExp).test(value); } return value === query; @@ -65,7 +67,7 @@ class SchemaTypeString extends SchemaType { * @param {Object} data * @return {Boolean} */ - q$in(value, query, data?) { + q$in(value: string | undefined, query: string[] | RegExp[], data?: unknown): boolean { for (let i = 0, len = query.length; i < len; i++) { if (this.match(value, query[i], data)) return true; } @@ -81,7 +83,7 @@ class SchemaTypeString extends SchemaType { * @param {Object} data * @return {Boolean} */ - q$nin(value, query, data?) { + q$nin(value: string | undefined, query: string[] | RegExp[], data?: unknown): boolean { return !this.q$in(value, query, data); } @@ -92,7 +94,7 @@ class SchemaTypeString extends SchemaType { * @param {Number} query * @return {Boolean} */ - q$length(value, query) { + q$length(value: string | undefined, query: number): boolean { return (value ? value.length : 0) === query; } } diff --git a/src/types/virtual.ts b/src/types/virtual.ts index aa333a5a..383907b3 100644 --- a/src/types/virtual.ts +++ b/src/types/virtual.ts @@ -14,7 +14,7 @@ class SchemaTypeVirtual extends SchemaType { * @param {Function} fn * @chainable */ - get(fn) { + get(fn: () => any): SchemaTypeVirtual { if (typeof fn !== 'function') { throw new TypeError('Getter must be a function!'); } @@ -30,7 +30,7 @@ class SchemaTypeVirtual extends SchemaType { * @param {Function} fn * @chainable */ - set(fn) { + set(fn: (value: any) => void): SchemaTypeVirtual { if (typeof fn !== 'function') { throw new TypeError('Setter must be a function!'); } @@ -47,7 +47,7 @@ class SchemaTypeVirtual extends SchemaType { * @param {Object} data * @return {*} */ - cast(value, data) { + cast(value: unknown, data: any): void { if (typeof this.getter !== 'function') return; const getter = this.getter; @@ -70,7 +70,7 @@ class SchemaTypeVirtual extends SchemaType { * @param {*} value * @param {Object} data */ - validate(value, data) { + validate(value: any, data: any): void { if (typeof this.setter === 'function') { this.setter.call(data, value); } diff --git a/src/util.ts b/src/util.ts index 62cef092..b7ab5d57 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,8 +1,8 @@ -function extractPropKey(key) { +function extractPropKey(key: string): string[] { return key.split('.'); } -function _parseArgs(args) { +function _parseArgs(args: string) { if (typeof args !== 'string') return args; const arr = args.split(' '); @@ -173,12 +173,12 @@ export function reverse(arr) { return arr; } -export function parseArgs(orderby, order?) { +export function parseArgs(orderby: string | object, order?: string | number | object) { let result; if (order) { result = {}; - result[orderby] = order; + result[orderby as string] = order; } else if (typeof orderby === 'string') { result = _parseArgs(orderby); } else { diff --git a/test/scripts/document.ts b/test/scripts/document.ts index abac13a4..3d92fd35 100644 --- a/test/scripts/document.ts +++ b/test/scripts/document.ts @@ -39,7 +39,7 @@ describe('Document', () => { const doc = User.new({}); return doc.save().then(item => { - User.findById(doc._id).should.exist; + User.findById(doc._id as string | number).should.exist; return User.removeById(item._id); }); }); @@ -115,5 +115,5 @@ describe('Document', () => { user.populate('comments').comments.toArray().should.eql(comments); return comments; - }).map(comment => Comment.removeById(comment._id))); + }).map(comment => Comment.removeById(comment._id))); }); diff --git a/test/scripts/model.ts b/test/scripts/model.ts index 88589338..f258031d 100644 --- a/test/scripts/model.ts +++ b/test/scripts/model.ts @@ -9,6 +9,8 @@ import Promise from 'bluebird'; import sinon from 'sinon'; import cuid from 'cuid'; import Database from '../../dist/database'; +import type Query from '../../dist/query'; +import type Document from '../../dist/document'; describe('Model', () => { @@ -48,7 +50,7 @@ describe('Model', () => { age: 20 }); - user._id.should.exist; + user._id!.should.exist; user.name.first.should.eql('John'); user.name.last.should.eql('Doe'); user.name.full.should.eql('John Doe'); @@ -98,16 +100,16 @@ describe('Model', () => { const doc = User.new(); delete doc._id; - return User.insert(doc).should.eventually.be.rejected; + return (User.insert(doc) as any).should.eventually.be.rejected; }); it('insert() - already existed', () => { let user; - return User.insert({}).then(data => { + return (User.insert({}).then(data => { user = data; return User.insert(data); - }).finally(() => User.removeById(user._id)).should.eventually.be.rejected; + }).finally(() => User.removeById(user._id)) as any).should.eventually.be.rejected; }); it('insert() - hook', () => { @@ -150,7 +152,7 @@ describe('Model', () => { ]).then(data => { data.length = 2; return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('insert() - sync problem', () => { const db = new Database(); @@ -301,7 +303,7 @@ describe('Model', () => { return data; }).then(data => User.removeById(data._id))); - it('updateById() - id not exist', () => User.updateById('foo', {}).should.eventually.be.rejected); + it('updateById() - id not exist', () => (User.updateById('foo', {}) as any).should.eventually.be.rejected); it('updateById() - hook', () => { const db = new Database(); @@ -341,7 +343,7 @@ describe('Model', () => { updated[0].email.should.eql('A'); updated[1].email.should.eql('A'); return data; - })).map(item => User.removeById(item._id))); + })).map(item => User.removeById(item._id))); it('replaceById()', () => { function validate(data) { @@ -371,7 +373,7 @@ describe('Model', () => { }).then(data => User.removeById(data._id)); }); - it('replaceById() - id not exist', () => User.replaceById('foo', {}).should.eventually.be.rejected); + it('replaceById() - id not exist', () => (User.replaceById('foo', {}) as any).should.eventually.be.rejected); it('replaceById() - pre-hook', () => { const db = new Database(); @@ -411,7 +413,7 @@ describe('Model', () => { updated[0].email.should.eql('A'); updated[1].email.should.eql('A'); return data; - })).map(item => User.removeById(item._id))); + })).map(item => User.removeById(item._id))); it('removeById()', () => { const listener = sinon.spy(data => { @@ -430,7 +432,7 @@ describe('Model', () => { }); }); - it('removeById() - id not exist', () => User.removeById('foo', {}).should.eventually.be.rejected); + it('removeById() - id not exist', () => (User.removeById('foo', {}) as any).should.eventually.be.rejected); it('removeById() - hook', () => { const db = new Database(); @@ -489,13 +491,13 @@ describe('Model', () => { count.should.eql(data.length); return data; - }).map(item => Post.removeById(item._id)); + }).map(item => Post.removeById(item._id)); }); it('toArray()', () => Post.insert(Array(10).fill({})).then(data => { Post.toArray().should.eql(data); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('find()', () => User.insert([ {age: 10}, @@ -504,10 +506,10 @@ describe('Model', () => { {age: 30}, {age: 40} ]).then(data => { - const query = User.find({age: 20}); + const query = User.find({age: 20}) as Query; query.data.should.eql(data.slice(1, 3)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - blank', () => User.insert([ {age: 10}, @@ -516,10 +518,10 @@ describe('Model', () => { {age: 30}, {age: 40} ]).then(data => { - const query = User.find({}); + const query = User.find({}) as Query; query.data.should.eql(data); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - operator', () => User.insert([ {age: 10}, @@ -527,10 +529,10 @@ describe('Model', () => { {age: 30}, {age: 40} ]).then(data => { - const query = User.find({age: {$gt: 20}}); + const query = User.find({age: {$gt: 20}}) as Query; query.data.should.eql(data.slice(2)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - limit', () => User.insert([ {age: 10}, @@ -538,10 +540,10 @@ describe('Model', () => { {age: 30}, {age: 40} ]).then(data => { - const query = User.find({age: {$gte: 20}}, {limit: 2}); + const query = User.find({age: {$gte: 20}}, {limit: 2}) as Query; query.data.should.eql(data.slice(1, 3)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - skip', () => User.insert([ {age: 10}, @@ -549,15 +551,15 @@ describe('Model', () => { {age: 30}, {age: 40} ]).then(data => { - let query = User.find({age: {$gte: 20}}, {skip: 1}); + let query = User.find({age: {$gte: 20}}, {skip: 1}) as Query; query.data.should.eql(data.slice(2)); // with limit - query = User.find({age: {$gte: 20}}, {limit: 1, skip: 1}); + query = User.find({age: {$gte: 20}}, {limit: 1, skip: 1}) as Query; query.data.should.eql(data.slice(2, 3)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - lean', () => User.insert([ {age: 10}, @@ -568,7 +570,7 @@ describe('Model', () => { const query = User.find({age: {$gt: 20}}, {lean: true}); query.should.be.a('array'); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - $and', () => User.insert([ {name: {first: 'John', last: 'Doe'}, age: 20}, @@ -582,10 +584,10 @@ describe('Model', () => { ] }); - query.toArray().should.eql([data[1]]); + (query as Query).toArray().should.eql([data[1]]); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - $or', () => User.insert([ {name: {first: 'John', last: 'Doe'}, age: 20}, @@ -599,10 +601,10 @@ describe('Model', () => { ] }); - query.toArray().should.eql(data.slice(1)); + (query as Query).toArray().should.eql(data.slice(1)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - $nor', () => User.insert([ {name: {first: 'John', last: 'Doe'}, age: 20}, @@ -616,10 +618,10 @@ describe('Model', () => { ] }); - query.toArray().should.eql([data[0]]); + (query as Query).toArray().should.eql([data[0]]); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - $not', () => User.insert([ {name: {first: 'John', last: 'Doe'}, age: 20}, @@ -630,10 +632,10 @@ describe('Model', () => { $not: {'name.last': 'Doe'} }); - query.toArray().should.eql(data.slice(2)); + (query as Query).toArray().should.eql(data.slice(2)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - $where', () => User.insert([ {name: {first: 'John', last: 'Doe'}, age: 20}, @@ -646,10 +648,10 @@ describe('Model', () => { } }); - query.toArray().should.eql(data.slice(0, 2)); + (query as Query).toArray().should.eql(data.slice(0, 2)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('findOne()', () => User.insert([ {age: 10}, @@ -659,7 +661,7 @@ describe('Model', () => { ]).then(data => { User.findOne({age: {$gt: 20}}).should.eql(data[2]); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('findOne() - lean', () => User.insert([ {age: 10}, @@ -667,9 +669,9 @@ describe('Model', () => { {age: 30}, {age: 40} ]).then(data => { - User.findOne({age: {$gt: 20}}, {lean: true})._id.should.eql(data[2]._id); + (User.findOne({age: {$gt: 20}}, {lean: true}) as Document)._id!.should.eql(data[2]._id); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('sort()', () => User.insert([ {age: 15}, @@ -681,7 +683,7 @@ describe('Model', () => { query.data[1].should.eql(data[0]); query.data[2].should.eql(data[1]); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('sort() - descending', () => User.insert([ {age: 15}, @@ -693,7 +695,7 @@ describe('Model', () => { query.data[1].should.eql(data[0]); query.data[2].should.eql(data[2]); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('sort() - multi', () => User.insert([ {age: 15, email: 'A'}, @@ -707,7 +709,7 @@ describe('Model', () => { query.data[2].should.eql(data[3]); query.data[3].should.eql(data[1]); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('eq()', () => Post.insert(Array(5).fill({})).then(data => { for (let i = 0, len = data.length; i < len; i++) { @@ -715,7 +717,7 @@ describe('Model', () => { } return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('eq() - negative index', () => Post.insert(Array(5).fill({})).then(data => { for (let i = 1, len = data.length; i <= len; i++) { @@ -723,7 +725,7 @@ describe('Model', () => { } return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('eq() - no data', () => { (typeof Post.eq(1)).should.eql('undefined'); @@ -733,68 +735,68 @@ describe('Model', () => { Post.first().should.eql(data[0]); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('last()', () => Post.insert(Array(5).fill({})).then(data => { Post.last().should.eql(data[data.length - 1]); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('slice() - no arguments', () => Post.insert(Array(5).fill({})).then(data => { Post.slice().data.should.eql(data); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('slice() - one argument', () => Post.insert(Array(5).fill({})).then(data => { Post.slice(2).data.should.eql(data.slice(2)); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('slice() - one negative argument', () => Post.insert(Array(5).fill({})).then(data => { Post.slice(-2).data.should.eql(data.slice(-2)); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('slice() - two arguments', () => Post.insert(Array(5).fill({})).then(data => { Post.slice(2, 4).data.should.eql(data.slice(2, 4)); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('slice() - start + negative end index', () => Post.insert(Array(5).fill({})).then(data => { Post.slice(1, -1).data.should.eql(data.slice(1, -1)); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('slice() - two negative arguments', () => Post.insert(Array(5).fill({})).then(data => { Post.slice(-3, -1).data.should.eql(data.slice(-3, -1)); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('slice() - start > end', () => Post.insert(Array(5).fill({})).then(data => { Post.slice(-1, -3).data.should.eql(data.slice(-1, -3)); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('slice() - index overflow', () => Post.insert(Array(5).fill({})).then(data => { Post.slice(1, 100).data.should.eql(data.slice(1, 100)); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('slice() - index overflow 2', () => Post.insert(Array(5).fill({})).then(data => { Post.slice(100, 200).data.should.eql(data.slice(100, 200)); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('limit()', () => Post.insert(Array(5).fill({})).then(data => { Post.limit(2).data.should.eql(data.slice(0, 2)); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('skip()', () => Post.insert(Array(5).fill({})).then(data => { Post.skip(2).data.should.eql(data.slice(2)); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('reverse()', () => Post.insert(Array(5).fill({})).then(data => { const query = Post.reverse(); @@ -804,13 +806,13 @@ describe('Model', () => { } return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('shuffle()', () => Post.insert(Array(5).fill({})).then(data => { const query = Post.shuffle(); sortBy(query.data, '_id').should.eql(sortBy(data, '_id')); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('map()', () => Post.insert(Array(5).fill({})).then(data => { let num = 0; @@ -825,7 +827,7 @@ describe('Model', () => { d1.should.eql(d2); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('reduce()', () => Post.insert([ {email: 'A'}, @@ -842,7 +844,7 @@ describe('Model', () => { sum.email.should.eql('ABC'); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('reduce() - with initial', () => Post.insert([ {email: 'A'}, @@ -859,7 +861,7 @@ describe('Model', () => { sum.should.eql('_ABC'); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('reduceRight()', () => Post.insert([ {email: 'A'}, @@ -876,7 +878,7 @@ describe('Model', () => { sum.email.should.eql('CBA'); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('reduceRight() - with initial', () => Post.insert([ {email: 'A'}, @@ -893,7 +895,7 @@ describe('Model', () => { sum.should.eql('_CBA'); return data; - }).map(item => Post.removeById(item._id))); + }).map(item => Post.removeById(item._id))); it('filter()', () => User.insert([ {age: 10}, @@ -911,7 +913,7 @@ describe('Model', () => { query.data.should.eql(data.slice(2)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('every()', () => User.insert([ {age: 10}, @@ -929,7 +931,7 @@ describe('Model', () => { User.every((data, i) => data.age > 10).should.be.false; return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('some()', () => User.insert([ {age: 10}, @@ -947,10 +949,11 @@ describe('Model', () => { }).should.be.false; return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('populate() - error', () => { try { + // @ts-ignore Post.populate(); } catch (err) { err.message.should.eql('path is required'); @@ -1230,7 +1233,7 @@ describe('Model', () => { const Test = db.model('Test', schema); - Test.add({name: 'foo'}).then(data => { + (Test as any).add({name: 'foo'}).then(data => { data.name.should.eql('foo'); }); diff --git a/test/scripts/query.ts b/test/scripts/query.ts index 81192205..eca942e7 100644 --- a/test/scripts/query.ts +++ b/test/scripts/query.ts @@ -5,6 +5,7 @@ const { sortBy } = lodash; import Promise from 'bluebird'; import Document from '../../dist/document'; import Database from '../../dist/database'; +import type Query from '../../dist/query'; describe('Query', () => { @@ -29,9 +30,9 @@ describe('Query', () => { }); it('count()', () => User.insert(Array(5).fill({})).then(data => { - User.find({}).count().should.eql(data.length); + (User.find({}) as Query).count().should.eql(data.length); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('forEach()', () => User.insert(Array(5).fill({})).then(data => { let count = 0; @@ -42,67 +43,67 @@ describe('Query', () => { }); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('toArray()', () => User.insert(Array(5).fill({})).then(data => { - User.find({}).toArray().should.eql(data); + (User.find({}) as Query).toArray().should.eql(data); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('eq()', () => User.insert(Array(5).fill({})).then(data => { const query = User.find({}); for (let i = 0, len = data.length; i < len; i++) { - query.eq(i).should.eql(data[i]); + (query as Query).eq(i).should.eql(data[i]); } return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('eq() - negative index', () => User.insert(Array(5).fill({})).then(data => { const query = User.find({}); for (let i = 1, len = data.length; i <= len; i++) { - query.eq(-i).should.eql(data[len - i]); + (query as Query).eq(-i).should.eql(data[len - i]); } return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('first()', () => User.insert(Array(5).fill({})).then(data => { - User.find({}).first().should.eql(data[0]); + (User.find({}) as Query).first().should.eql(data[0]); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('last()', () => User.insert(Array(5).fill({})).then(data => { - User.find({}).last().should.eql(data[data.length - 1]); + (User.find({}) as Query).last().should.eql(data[data.length - 1]); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('slice()', () => User.insert(Array(5).fill({})).then(data => { - User.find({}).slice(2, 4).data.should.eql(data.slice(2, 4)); + (User.find({}) as Query).slice(2, 4).data.should.eql(data.slice(2, 4)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('limit()', () => User.insert(Array(5).fill({})).then(data => { - User.find({}).limit(2).data.should.eql(data.slice(0, 2)); + (User.find({}) as Query).limit(2).data.should.eql(data.slice(0, 2)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('skip()', () => User.insert(Array(5).fill({})).then(data => { - User.find({}).skip(2).data.should.eql(data.slice(2)); + (User.find({}) as Query).skip(2).data.should.eql(data.slice(2)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('reverse()', () => User.insert(Array(5).fill({})).then(data => { - User.find({}).reverse().data.should.eql(data.reverse()); + (User.find({}) as Query).reverse().data.should.eql(data.reverse()); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('shuffle()', () => User.insert(Array(5).fill({})).then(data => { - sortBy(User.find({}).shuffle().data, '_id').should.eql(sortBy(data, '_id')); + sortBy((User.find({}) as Query).shuffle().data, '_id').should.eql(sortBy(data, '_id')); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find()', () => User.insert([ {age: 10}, @@ -111,7 +112,7 @@ describe('Query', () => { {age: 30}, {age: 40} ]).then(data => { - const query = User.find({}).find({age: 20}); + const query = (User.find({}) as Query).find({age: 20}) as Query; query.data.should.eql(data.slice(1, 3)); const { length } = query; @@ -120,7 +121,7 @@ describe('Query', () => { query.data[i].should.to.be.an.instanceof(Document); } return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - blank', () => User.insert([ {age: 10}, @@ -129,10 +130,10 @@ describe('Query', () => { {age: 30}, {age: 40} ]).then(data => { - const query = User.find({}).find({}); + const query = (User.find({}) as Query).find({}) as Query; query.data.should.eql(data); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - operator', () => User.insert([ {age: 10}, @@ -140,10 +141,10 @@ describe('Query', () => { {age: 30}, {age: 40} ]).then(data => { - const query = User.find({}).find({age: {$gt: 20}}); + const query = (User.find({}) as Query).find({age: {$gt: 20}}) as Query; query.data.should.eql(data.slice(2)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - limit', () => User.insert([ {age: 10}, @@ -151,10 +152,10 @@ describe('Query', () => { {age: 30}, {age: 40} ]).then(data => { - const query = User.find({}).find({age: {$gte: 20}}, {limit: 2}); + const query = (User.find({}) as Query).find({age: {$gte: 20}}, {limit: 2}) as Query; query.data.should.eql(data.slice(1, 3)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - skip', () => User.insert([ {age: 10}, @@ -162,15 +163,15 @@ describe('Query', () => { {age: 30}, {age: 40} ]).then(data => { - let query = User.find({}).find({age: {$gte: 20}}, {skip: 1}); + let query = (User.find({}) as Query).find({age: {$gte: 20}}, {skip: 1}) as Query; query.data.should.eql(data.slice(2)); // with limit - query = User.find({}).find({age: {$gte: 20}}, {limit: 1, skip: 1}); + query = (User.find({}) as Query).find({age: {$gte: 20}}, {limit: 1, skip: 1}) as Query; query.data.should.eql(data.slice(2, 3)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - lean', () => User.insert([ {age: 10}, @@ -178,127 +179,127 @@ describe('Query', () => { {age: 30}, {age: 40} ]).then(data => { - const query = User.find({}).find({age: {$gt: 20}}, {lean: true}); + const query = (User.find({}) as Query).find({age: {$gt: 20}}, {lean: true}) as Query; query.should.be.a('array'); const { length } = query; for (let i = 0; i < length; i++) { query[i].should.to.not.be.an.instanceof(Document); } return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - $and', () => User.insert([ {name: 'John', age: 20}, {name: 'John', age: 25}, {name: 'Jack', age: 30} ]).then(data => { - const query = User.find({}).find({ + const query = (User.find({}) as Query).find({ $and: [ {name: 'John'}, {age: {$gt: 20}} ] - }); + }) as Query; query.toArray().should.eql([data[1]]); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - $or', () => User.insert([ {name: 'John', age: 20}, {name: 'John', age: 25}, {name: 'Jack', age: 30} ]).then(data => { - const query = User.find({}).find({ + const query = (User.find({}) as Query).find({ $or: [ {name: 'Jack'}, {age: {$gt: 20}} ] - }); + }) as Query; query.toArray().should.eql(data.slice(1)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - $nor', () => User.insert([ {name: 'John', age: 20}, {name: 'John', age: 25}, {name: 'Jack', age: 30} ]).then(data => { - const query = User.find({}).find({ + const query = (User.find({}) as Query).find({ $nor: [ {name: 'Jack'}, {age: {$gt: 20}} ] - }); + }) as Query; query.toArray().should.eql([data[0]]); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - $not', () => User.insert([ {name: 'John', age: 20}, {name: 'John', age: 25}, {name: 'Jack', age: 30} ]).then(data => { - const query = User.find({}).find({ + const query = (User.find({}) as Query).find({ $not: {name: 'John'} - }); + }) as Query; query.toArray().should.eql([data[2]]); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - $where', () => User.insert([ {name: 'John', age: 20}, {name: 'John', age: 25}, {name: 'Jack', age: 30} ]).then(data => { - const query = User.find({}).find({ + const query = (User.find({}) as Query).find({ $where() { return this.name === 'John'; } - }); + }) as Query; query.toArray().should.eql(data.slice(0, 2)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - abnormal - 1', () => User.insert([ {name: 'John', age: 20}, {name: 'John', age: 25}, {name: 'Jack', age: 30} ]).then(data => { - const query = User.find({}).find({ + const query = (User.find({}) as Query).find({ $and: [ {name: 'Jack'}, {age: {gt: 20}} ] - }); + }) as Query; query.toArray().length.should.eql(0); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('find() - abnormal - 2', () => User.insert([ {name: 'John', age: 20}, {name: 'John', age: 25}, {name: 'Jack', age: 30} ]).then(data => { - const query = User.find({}).find({ + const query = (User.find({}) as Query).find({ $and: [ {name: 'Jack'}, {age: {gt: {}}} ] - }); + }) as Query; query.toArray().should.eql([data[2]]); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('findOne()', () => User.insert([ {age: 10}, @@ -306,11 +307,11 @@ describe('Query', () => { {age: 30}, {age: 40} ]).then(data => { - const result = User.find({}).findOne({age: {$gt: 20}}); + const result = (User.find({}) as Query).findOne({age: {$gt: 20}}); result.should.eql(data[2]); result.should.to.be.an.instanceof(Document); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('findOne() - lean', () => User.insert([ {age: 10}, @@ -318,47 +319,47 @@ describe('Query', () => { {age: 30}, {age: 40} ]).then(data => { - const result = User.find({}).findOne({age: {$gt: 20}}, {lean: true}); + const result = (User.find({}) as Query).findOne({age: {$gt: 20}}, {lean: true}); result._id.should.eql(data[2]._id); result.should.to.not.be.an.instanceof(Document); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('sort()', () => User.insert([ {age: 15}, {age: 35}, {age: 10} ]).then(data => { - const query = User.find({}).sort('age'); + const query = (User.find({}) as Query).sort('age'); query.data[0].should.eql(data[2]); query.data[1].should.eql(data[0]); query.data[2].should.eql(data[1]); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('sort() - object', () => Loop.insert([ {age: {age: 15}}, {age: {age: 35}}, {age: {age: 10}} ]).then(data => { - const query = Loop.find({}).sort('age', { age: 1 }); + const query = (Loop.find({}) as Query).sort('age', { age: 1 }); query.data[0].should.eql(data[2]); query.data[1].should.eql(data[0]); query.data[2].should.eql(data[1]); return data; - }).map(item => Loop.removeById(item._id))); + }).map(item => Loop.removeById(item._id))); it('sort() - descending', () => User.insert([ {age: 15}, {age: 35}, {age: 10} ]).then(data => { - const query = User.find({}).sort('age', -1); + const query = (User.find({}) as Query).sort('age', -1); query.data[0].should.eql(data[1]); query.data[1].should.eql(data[0]); query.data[2].should.eql(data[2]); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('sort() - multi', () => User.insert([ {age: 15, name: 'A'}, @@ -366,13 +367,13 @@ describe('Query', () => { {age: 20, name: 'C'}, {age: 20, name: 'D'} ]).then(data => { - const query = User.find({}).sort('age name'); + const query = (User.find({}) as Query).sort('age name'); query.data[0].should.eql(data[0]); query.data[1].should.eql(data[2]); query.data[2].should.eql(data[3]); query.data[3].should.eql(data[1]); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('map()', () => User.insert(Array(5).fill({})).then(data => { let num = 0; @@ -387,7 +388,7 @@ describe('Query', () => { d1.should.eql(d2); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('reduce()', () => User.insert([ {name: 'A'}, @@ -404,7 +405,7 @@ describe('Query', () => { sum.name.should.eql('ABC'); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('reduce() - initial', () => User.insert([ {name: 'A'}, @@ -421,7 +422,7 @@ describe('Query', () => { sum.should.eql('_ABC'); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('reduceRight()', () => User.insert([ {name: 'A'}, @@ -438,7 +439,7 @@ describe('Query', () => { sum.name.should.eql('CBA'); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('reduceRight() - initial', () => User.insert([ {name: 'A'}, @@ -455,7 +456,7 @@ describe('Query', () => { sum.should.eql('_CBA'); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('filter()', () => User.insert([ {age: 10}, @@ -468,12 +469,12 @@ describe('Query', () => { const query = User.find({}).filter((data, i) => { i.should.eql(num++); return data.age > 20; - }); + }) as Query; query.data.should.eql(data.slice(2)); return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('every()', () => User.insert([ {age: 10}, @@ -491,7 +492,7 @@ describe('Query', () => { User.find({}).every((data, i) => data.age > 10).should.be.false; return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('some()', () => User.insert([ {age: 10}, @@ -509,7 +510,7 @@ describe('Query', () => { }).should.be.false; return data; - }).map(item => User.removeById(item._id))); + }).map(item => User.removeById(item._id))); it('update()', () => User.insert([ {age: 10}, @@ -517,13 +518,13 @@ describe('Query', () => { {age: 30}, {age: 20}, {age: 40} - ]).then(data => User.find({age: 20}).update({name: 'A'}).then(updated => { + ]).then(data => (User.find({age: 20}) as Query).update({name: 'A'}).then(updated => { updated[0]._id.should.eql(data[1]._id); updated[1]._id.should.eql(data[3]._id); updated[0].name.should.eql('A'); updated[1].name.should.eql('A'); return data; - })).map(item => User.removeById(item._id))); + })).map(item => User.removeById(item._id))); it('replace()', () => User.insert([ {age: 10}, @@ -531,13 +532,13 @@ describe('Query', () => { {age: 30}, {age: 20}, {age: 40} - ]).then(data => User.find({age: 20}).replace({name: 'A'}).then(updated => { + ]).then(data => (User.find({age: 20}) as Query).replace({name: 'A'}).then(updated => { updated[0]._id.should.eql(data[1]._id); updated[1]._id.should.eql(data[3]._id); updated[0].name.should.eql('A'); updated[1].name.should.eql('A'); return data; - })).map(item => User.removeById(item._id))); + })).map(item => User.removeById(item._id))); it('remove()', () => User.insert([ {age: 10}, @@ -545,11 +546,11 @@ describe('Query', () => { {age: 30}, {age: 20}, {age: 40} - ]).then(data => User.find({age: 20}).remove().then(removed => { + ]).then(data => (User.find({age: 20}) as Query).remove().then(removed => { should.not.exist(User.findById(data[1]._id)); should.not.exist(User.findById(data[3]._id)); return [data[0], data[2], data[4]]; - })).map(item => User.removeById(item._id))); + })).map(item => User.removeById(item._id))); it('populate() - object', () => { let user, comment; @@ -562,7 +563,7 @@ describe('Query', () => { }); }).then(comment_ => { comment = comment_; - return Comment.find({}).populate('author'); + return (Comment.find({}) as Query).populate('author'); }).then(result => { result.first().author.should.eql(user); @@ -614,7 +615,7 @@ describe('Query', () => { }); }).then(comment_ => { comment = comment_; - return Comment.find({}).populate(['author']); + return (Comment.find({}) as Query).populate(['author']); }).then(result => { result.first().author.should.eql(user); @@ -636,7 +637,7 @@ describe('Query', () => { }); }).then(comment_ => { comment = comment_; - return Comment.find({}).populate([{ path: 'author' }]); + return (Comment.find({}) as Query).populate([{ path: 'author' }]); }).then(result => { result.first().author.should.eql(user); @@ -649,7 +650,7 @@ describe('Query', () => { it('populate() - path is required', () => { try { - Comment.find({}).populate({}); + (Comment.find({}) as Query).populate({}); } catch (err) { err.message.should.eql('path is required'); } diff --git a/test/scripts/schema.ts b/test/scripts/schema.ts index 2a4f9a70..7c8fd734 100644 --- a/test/scripts/schema.ts +++ b/test/scripts/schema.ts @@ -103,6 +103,7 @@ describe('Schema', () => { (() => schema.pre('wtf', () => {})).should.to.throw(TypeError, 'Hook type must be `save` or `remove`!'); // hook is not a function + //@ts-ignore (() => schema.pre('save', {})).should.to.throw(TypeError, 'Hook must be a function!'); }); @@ -123,6 +124,7 @@ describe('Schema', () => { (() => schema.post('wtf', () => {})).should.throw(TypeError, 'Hook type must be `save` or `remove`!'); // hook is not a function + //@ts-ignore (() => schema.post('save', {})).should.to.throw(TypeError, 'Hook must be a function!'); }); @@ -137,6 +139,7 @@ describe('Schema', () => { schema.method.should.to.throw(TypeError, 'Method name is required!'); // without function + //@ts-ignore (() => schema.method('wtf', {})).should.to.throw(TypeError, 'Instance method must be a function!'); }); @@ -151,6 +154,7 @@ describe('Schema', () => { schema.static.should.to.throw(TypeError, 'Method name is required!'); // without function + //@ts-ignore (() => schema.static('wtf', {})).should.to.throw(TypeError, 'Static method must be a function!'); }); }); diff --git a/test/scripts/schematype.ts b/test/scripts/schematype.ts index a49090e5..39abb55f 100644 --- a/test/scripts/schematype.ts +++ b/test/scripts/schematype.ts @@ -4,24 +4,24 @@ import ValidationError from '../../dist/error/validation'; import SchemaType from '../../dist/schematype'; describe('SchemaType', () => { - const type = new SchemaType('test'); + const type = new SchemaType('test'); it('cast()', () => { - type.cast(123).should.eql(123); + (type.cast(123) as number).should.eql(123); }); it('cast() - default', () => { const type = new SchemaType('test', {default: 'foo'}); - type.cast().should.eql('foo'); + (type.cast() as string).should.eql('foo'); }); it('cast() - default - function', () => { const type = new SchemaType('test', {default: () => 'foo'}); - type.cast().should.eql('foo'); + (type.cast() as string).should.eql('foo'); }); it('validate()', () => { - type.validate(123).should.eql(123); + (type.validate(123) as number).should.eql(123); }); it('validate() - required', () => { @@ -127,12 +127,12 @@ describe('SchemaType', () => { }); it('u$set', () => { - type.u$set(1, 1).should.eql(1); + type.u$set(1, 1).should.eql(1); }); it('u$unset', () => { should.not.exist(type.u$unset(1, true)); - type.u$unset(1, false).should.eql(1); + (type.u$unset(1, false) as number).should.eql(1); }); it('u$rename', () => { diff --git a/test/scripts/types/array.ts b/test/scripts/types/array.ts index 19ba5313..61cd52ba 100644 --- a/test/scripts/types/array.ts +++ b/test/scripts/types/array.ts @@ -13,12 +13,12 @@ describe('SchemaTypeArray', () => { type.cast('foo').should.eql(['foo']); type.cast([]).should.eql([]); type.cast([1, 2, 3]).should.eql([1, 2, 3]); - type.cast().should.eql([]); + (type.cast() as any[]).should.eql([]); }); it('cast() - default', () => { const type = new SchemaTypeArray('test', {default: [1, 2, 3]}); - type.cast().should.eql([1, 2, 3]); + (type.cast() as any[]).should.eql([1, 2, 3]); }); it('cast() - child', () => { diff --git a/test/scripts/types/buffer.ts b/test/scripts/types/buffer.ts index 9bae4b19..a9fa0d68 100644 --- a/test/scripts/types/buffer.ts +++ b/test/scripts/types/buffer.ts @@ -25,7 +25,7 @@ describe('SchemaTypeBuffer', () => { const buf = Buffer.from([97, 98, 99]); const type = new SchemaTypeBuffer('test', {default: buf}); - type.cast().should.eql(buf); + (type.cast() as Buffer).should.eql(buf); }); function shouldThrowError(value) { @@ -50,7 +50,9 @@ describe('SchemaTypeBuffer', () => { it('match()', () => { type.match(Buffer.from([97, 98, 99]), Buffer.from([97, 98, 99])).should.be.true; type.match(Buffer.from([97, 98, 99]), Buffer.from([97, 98, 100])).should.be.false; + //@ts-ignore type.match(undefined, Buffer.from([97, 98, 99])).should.be.false; + //@ts-ignore type.match(undefined, undefined).should.be.true; }); diff --git a/test/scripts/types/date.ts b/test/scripts/types/date.ts index da80826b..b0d73bf6 100644 --- a/test/scripts/types/date.ts +++ b/test/scripts/types/date.ts @@ -16,7 +16,7 @@ describe('SchemaTypeDate', () => { const date = new Date(); const type = new SchemaTypeDate('test', {default: date}); - type.cast().should.eql(date); + (type.cast() as Date).should.eql(date); }); function shouldThrowError(value) { @@ -42,7 +42,9 @@ describe('SchemaTypeDate', () => { it('match()', () => { type.match(new Date(2014, 1, 1), new Date(2014, 1, 1)).should.be.true; type.match(new Date(2014, 1, 1), new Date(2014, 1, 2)).should.be.false; + //@ts-ignore type.match(undefined, new Date()).should.be.false; + //@ts-ignore type.match(undefined, undefined).should.be.true; }); diff --git a/test/scripts/types/enum.ts b/test/scripts/types/enum.ts index ded35ace..7804322b 100644 --- a/test/scripts/types/enum.ts +++ b/test/scripts/types/enum.ts @@ -7,7 +7,7 @@ describe('SchemaTypeEnum', () => { it('validate()', () => { const type = new SchemaTypeEnum('test', {elements: ['foo', 'bar', 'baz']}); - type.validate('foo').should.eql('foo'); + (type.validate('foo') as string).should.eql('foo'); (() => type.validate('wat')).should.to.throw(ValidationError, 'The value must be one of foo, bar, baz'); }); diff --git a/test/scripts/types/number.ts b/test/scripts/types/number.ts index ae56afbf..3dd6003b 100644 --- a/test/scripts/types/number.ts +++ b/test/scripts/types/number.ts @@ -17,7 +17,7 @@ describe('SchemaTypeNumber', () => { it('cast() - default', () => { const type = new SchemaTypeNumber('type', {default: 42}); - type.cast().should.eql(42); + (type.cast() as number).should.eql(42); }); function shouldThrowError(value) { diff --git a/test/scripts/types/object.ts b/test/scripts/types/object.ts index e29b6473..960b651c 100644 --- a/test/scripts/types/object.ts +++ b/test/scripts/types/object.ts @@ -6,6 +6,6 @@ describe('SchemaTypeObject', () => { const type = new SchemaTypeObject('test'); it('cast() - default', () => { - type.cast().should.eql({}); + (type.cast() as object).should.eql({}); }); }); diff --git a/test/scripts/types/string.ts b/test/scripts/types/string.ts index b2572c8c..ebbda208 100644 --- a/test/scripts/types/string.ts +++ b/test/scripts/types/string.ts @@ -21,7 +21,7 @@ describe('SchemaTypeString', () => { it('cast() - default', () => { const type = new SchemaTypeString('test', {default: 'foo'}); - type.cast().should.eql('foo'); + (type.cast() as string).should.eql('foo'); }); function shouldThrowError(value) { diff --git a/test/scripts/types/virtual.ts b/test/scripts/types/virtual.ts index ddbc83c5..a7e25d47 100644 --- a/test/scripts/types/virtual.ts +++ b/test/scripts/types/virtual.ts @@ -9,10 +9,11 @@ describe('SchemaTypeVirtual', () => { const getter = () => 'foo'; type.get(getter); - type.getter.should.eql(getter); + (type.getter as () => any).should.eql(getter); }); it('get() - type check', () => { + //@ts-ignore (() => type.get(123)).should.to.throw(TypeError, 'Getter must be a function!'); }); @@ -22,10 +23,11 @@ describe('SchemaTypeVirtual', () => { }; type.set(setter); - type.setter.should.eql(setter); + (type.setter as () => any).should.eql(setter); }); it('set() - type check', () => { + //@ts-ignore (() => type.set(123)).should.to.throw(TypeError, 'Setter must be a function!'); });