import { EventEmitter } from 'events';
import BluebirdPromise from 'bluebird';
import Document from './document';
import Query from './query';
import Schema from './schema';
import Mutex from './mutex';
import type Database from './database';
import type { AddSchemaTypeOptions, NodeJSLikeCallback, Options, queryCallback } from './types';
declare class Model<T> extends EventEmitter {
    name: string;
    _mutex: Mutex;
    data: Record<PropertyKey, T>;
    schema: Schema<T>;
    length: number;
    Document: {
        new <T>(data: T): Document<T>;
    };
    Query: {
        new <T>(data: Document<T>[]): Query<T>;
    };
    _database: Database;
    [key: string]: any;
    _dataKeys: string[];
    dirty: boolean;
    /**
     * Model constructor.
     *
     * @param {string} name Model name
     * @param {Schema|object} [schema_] Schema
     */
    constructor(name: string, schema_: Schema<T> | Record<string, AddSchemaTypeOptions>);
    /**
     * Returns the cached data keys.
     */
    get dataKeys(): string[];
    /**
     * Creates a new document.
     *
     * @param {object} data
     * @return {Document}
     */
    new(data?: T): Document<T>;
    /**
     * Finds a document by its identifier.
     *
     * @param {*} id
     * @param {object} options
     *   @param {boolean} [options.lean=false] Returns a plain JavaScript object
     * @return {Document|object}
     */
    findById(id: PropertyKey): Document<T>;
    findById(id: PropertyKey, options_: Partial<Omit<Options, 'lean'>> & {
        lean: true;
    }): T;
    findById(id: PropertyKey, options_: Partial<Omit<Options, 'lean'>> & {
        lean: false;
    }): Document<T>;
    findById(id: PropertyKey, options_: Partial<Omit<Options, 'lean'>> & {
        lean?: undefined;
    }): Document<T>;
    findById(id: PropertyKey, options_: Partial<Options>): Document<T> | T;
    /**
     * Checks if the model contains a document with the specified id.
     *
     * @param {*} id
     * @return {boolean}
     */
    has(id: PropertyKey): boolean;
    /**
     * Acquires write lock.
     *
     * @return {BluebirdPromise}
     * @private
     */
    _acquireWriteLock(): BluebirdPromise.Disposer<void>;
    /**
     * Inserts a document.
     *
     * @param {Document|object} data
     * @return {BluebirdPromise}
     * @private
     */
    _insertOne(data_: Document<T> | T): BluebirdPromise<any>;
    /**
     * Inserts a document.
     *
     * @param {object} data
     * @param {function} [callback]
     * @return {BluebirdPromise}
     */
    insertOne(data: Document<T> | T, callback?: NodeJSLikeCallback<any>): BluebirdPromise<any>;
    /**
     * Inserts documents.
     *
     * @param {object|array} data
     * @param {function} [callback]
     * @return {BluebirdPromise}
     */
    insert(data: Document<T> | T | Document<T>[] | T[], callback?: NodeJSLikeCallback<any>): BluebirdPromise<any>;
    /**
     * Inserts the document if it does not exist; otherwise updates it.
     *
     * @param {object} data
     * @param {function} [callback]
     * @return {BluebirdPromise}
     */
    save(data: Document<T> | T, callback?: NodeJSLikeCallback<any>): BluebirdPromise<any>;
    /**
     * Updates a document with a compiled stack.
     *
     * @param {*} id
     * @param {array} stack
     * @return {BluebirdPromise}
     * @private
     */
    _updateWithStack(id: string, stack: queryCallback<T>[]): BluebirdPromise<any>;
    /**
     * Finds a document by its identifier and update it.
     *
     * @param {*} id
     * @param {object} update
     * @param {function} [callback]
     * @return {BluebirdPromise}
     */
    updateById(id: string, update: object, callback?: NodeJSLikeCallback<any>): BluebirdPromise<any>;
    /**
     * Updates matching documents.
     *
     * @param {object} query
     * @param {object} data
     * @param {function} [callback]
     * @return {BluebirdPromise}
     */
    update(query: object, data: object, callback?: NodeJSLikeCallback<any>): BluebirdPromise<any>;
    /**
     * Finds a document by its identifier and replace it.
     *
     * @param {*} id
     * @param  {object} data
     * @return {BluebirdPromise}
     * @private
     */
    _replaceById(id: string, data_: Document<T> | T): BluebirdPromise<any>;
    /**
     * Finds a document by its identifier and replace it.
     *
     * @param {*} id
     * @param {object} data
     * @param {function} [callback]
     * @return {BluebirdPromise}
     */
    replaceById(id: string, data: Document<T> | T, callback?: NodeJSLikeCallback<any>): BluebirdPromise<any>;
    /**
     * Replaces matching documents.
     *
     * @param {object} query
     * @param {object} data
     * @param {function} [callback]
     * @return {BluebirdPromise}
     */
    replace(query: object, data: T | Document<T>, callback?: NodeJSLikeCallback<any>): BluebirdPromise<any>;
    /**
     * Finds a document by its identifier and remove it.
     *
     * @param {*} id
     * @return {BluebirdPromise}
     * @private
     */
    _removeById(id: string): BluebirdPromise<any>;
    /**
     * Finds a document by its identifier and remove it.
     *
     * @param {*} id
     * @param {function} [callback]
     * @return {BluebirdPromise}
     */
    removeById(id: string, callback?: NodeJSLikeCallback<any>): BluebirdPromise<any>;
    /**
     * Removes matching documents.
     *
     * @param {object} query
     * @param {function} [callback]
     * @return {BluebirdPromise}
     */
    remove(query: object, callback?: NodeJSLikeCallback<any>): BluebirdPromise<any>;
    /**
     * Deletes a model.
     */
    destroy(): void;
    /**
     * Returns the number of elements.
     *
     * @return {number}
     */
    count(): number;
    /**
     * Iterates over all documents.
     *
     * @param {function} iterator
     * @param {object} [options] See {@link Model#findById}.
     */
    forEach(iterator: (value: Document<T>, index: number) => void): void;
    forEach(iterator: (value: T, index: number) => void, options: Partial<Omit<Options, 'lean'>> & {
        lean: true;
    }): void;
    forEach(iterator: (value: Document<T>, index: number) => void, options: Partial<Omit<Options, 'lean'>> & {
        lean: false;
    }): void;
    forEach(iterator: (value: Document<T>, index: number) => void, options: Partial<Omit<Options, 'lean'>> & {
        lean?: undefined;
    }): void;
    forEach(iterator: ((value: T, index: number) => void) | ((value: Document<T>, index: number) => void), options: Partial<Options>): void;
    /**
     * Returns an array containing all documents.
     *
     * @param {Object} [options] See {@link Model#findById}.
     * @return {Array}
     */
    toArray(): Document<T>[];
    toArray(options: Partial<Omit<Options, 'lean'>> & {
        lean: true;
    }): T[];
    toArray(options: Partial<Omit<Options, 'lean'>> & {
        lean: false;
    }): Document<T>[];
    toArray(options: Partial<Omit<Options, 'lean'>> & {
        lean?: undefined;
    }): Document<T>[];
    toArray(options: Partial<Options>): Document<T>[] | T[];
    /**
     * Finds matching documents.
     *
     * @param {Object} query
     * @param {Object} [options]
     *   @param {Number} [options.limit=0] Limits the number of documents returned.
     *   @param {Number} [options.skip=0] Skips the first elements.
     *   @param {Boolean} [options.lean=false] Returns a plain JavaScript object.
     * @return {Query|Array}
     */
    find(query: object): Query<T>;
    find(query: object, options: Partial<Omit<Options, 'lean'>> & {
        lean: true;
    }): T[];
    find(query: object, options: Partial<Omit<Options, 'lean'>> & {
        lean: false;
    }): Query<T>;
    find(query: object, options: Partial<Omit<Options, 'lean'>> & {
        lean?: undefined;
    }): Query<T>;
    find(query: object, options: Partial<Options>): Query<T> | T[];
    /**
     * Finds the first matching documents.
     *
     * @param {Object} query
     * @param {Object} [options]
     *   @param {Number} [options.skip=0] Skips the first elements.
     *   @param {Boolean} [options.lean=false] Returns a plain JavaScript object.
     * @return {Document|Object}
     */
    findOne(query: object): Document<T>;
    findOne(query: object, options_: Partial<Omit<Options, 'lean'>> & {
        lean: true;
    }): T;
    findOne(query: object, options_: Partial<Omit<Options, 'lean'>> & {
        lean: false;
    }): Document<T>;
    findOne(query: object, options_: Partial<Omit<Options, 'lean'>> & {
        lean?: undefined;
    }): Document<T>;
    findOne(query: object, options_: Partial<Options>): Document<T> | T;
    /**
     * Sorts documents. See {@link Query#sort}.
     *
     * @param {String|Object} orderby
     * @param {String|Number} [order]
     * @return {Query}
     */
    sort(orderby: string, order: 'desc' | number | Record<string, any>): Query<T>;
    sort(orderby: string): Query<T>;
    sort(orderby: Record<string, number | Record<string, any>>): Query<T>;
    /**
     * Returns the document at the specified index. `num` can be a positive or
     * negative number.
     *
     * @param {Number} i
     * @param {Object} [options] See {@link Model#findById}.
     * @return {Document|Object}
     */
    eq(i_: number): Document<T>;
    eq(i_: number, options: Partial<Omit<Options, 'lean'>> & {
        lean: true;
    }): T;
    eq(i_: number, options: Partial<Omit<Options, 'lean'>> & {
        lean: false;
    }): Document<T>;
    eq(i_: number, options: Partial<Omit<Options, 'lean'>> & {
        lean?: undefined;
    }): Document<T>;
    eq(i_: number, options: Partial<Options>): Document<T> | T;
    /**
     * Returns the first document.
     *
     * @param {Object} [options] See {@link Model#findById}.
     * @return {Document|Object}
     */
    first(): Document<T>;
    first(options: Partial<Omit<Options, 'lean'>> & {
        lean: true;
    }): T;
    first(options: Partial<Omit<Options, 'lean'>> & {
        lean: false;
    }): Document<T>;
    first(options: Partial<Omit<Options, 'lean'>> & {
        lean?: undefined;
    }): Document<T>;
    first(options: Partial<Options>): Document<T> | T;
    /**
     * Returns the last document.
     *
     * @param {Object} [options] See {@link Model#findById}.
     * @return {Document|Object}
     */
    last(): Document<T>;
    last(options: Partial<Omit<Options, 'lean'>> & {
        lean: true;
    }): T;
    last(options: Partial<Omit<Options, 'lean'>> & {
        lean: false;
    }): Document<T>;
    last(options: Partial<Omit<Options, 'lean'>> & {
        lean?: undefined;
    }): Document<T>;
    last(options: Partial<Options>): Document<T> | T;
    /**
     * Returns the specified range of documents.
     *
     * @param {Number} start
     * @param {Number} [end]
     * @return {Query}
     */
    slice(start_?: number, end_?: number): Query<T>;
    /**
     * Limits the number of documents returned.
     *
     * @param {Number} i
     * @return {Query}
     */
    limit(i: number): Query<T>;
    /**
     * Specifies the number of items to skip.
     *
     * @param {Number} i
     * @return {Query}
     */
    skip(i: number): Query<T>;
    /**
     * Returns documents in a reversed order.
     *
     * @return {Query}
     */
    reverse(): Query<T>;
    /**
     * Returns documents in random order.
     *
     * @return {Query}
     */
    shuffle(): Query<T>;
    /**
     * Creates an array of values by iterating each element in the collection.
     *
     * @param {Function} iterator
     * @param {Object} [options]
     * @return {Array}
     */
    map<R>(iterator: (value: Document<T>, index: number) => R): R[];
    map<R>(iterator: (value: T, index: number) => R, options: Partial<Omit<Options, 'lean'>> & {
        lean: true;
    }): R[];
    map<R>(iterator: (value: Document<T>, index: number) => R, options: Partial<Omit<Options, 'lean'>> & {
        lean: false;
    }): R[];
    map<R>(iterator: (value: Document<T>, index: number) => R, options: Partial<Omit<Options, 'lean'>> & {
        lean?: undefined;
    }): R[];
    map<R>(iterator: ((value: T, index: number) => R) | ((value: Document<T>, index: number) => R), options: Partial<Options>): R[];
    /**
     * Reduces a collection to a value which is the accumulated result of iterating
     * each element in the collection.
     *
     * @param {Function} iterator
     * @param {*} [initial] By default, the initial value is the first document.
     * @return {*}
     */
    reduce<R>(iterator: (pre: any, cur: Document<T>, index: number) => R, initial?: R): R;
    /**
     * Reduces a collection to a value which is the accumulated result of iterating
     * each element in the collection from right to left.
     *
     * @param {Function} iterator
     * @param {*} [initial] By default, the initial value is the last document.
     * @return {*}
     */
    reduceRight<R>(iterator: (pre: any, cur: Document<T>, index: number) => R, initial?: R): R;
    /**
     * Creates a new array with all documents that pass the test implemented by the
     * provided function.
     *
     * @param {Function} iterator
     * @param {Object} [options]
     * @return {Query}
     */
    filter(iterator: (value: Document<T>, index: number) => boolean): Query<T>;
    filter(iterator: (value: T, index: number) => boolean, options: Partial<Omit<Options, 'lean'>> & {
        lean: true;
    }): Query<T>;
    filter(iterator: (value: Document<T>, index: number) => boolean, options: Partial<Omit<Options, 'lean'>> & {
        lean: false;
    }): Query<T>;
    filter(iterator: (value: Document<T>, index: number) => boolean, options: Partial<Omit<Options, 'lean'>> & {
        lean?: undefined;
    }): Query<T>;
    filter(iterator: ((value: T, index: number) => boolean) | ((value: Document<T>, index: number) => boolean), options: Partial<Options>): Query<T>;
    /**
     * Tests whether all documents pass the test implemented by the provided
     * function.
     *
     * @param {Function} iterator
     * @return {Boolean}
     */
    every(iterator: (value: Document<T>, index: number) => boolean): boolean;
    /**
     * Tests whether some documents pass the test implemented by the provided
     * function.
     *
     * @param {Function} iterator
     * @return {Boolean}
     */
    some(iterator: (value: Document<T>, index: number) => boolean): boolean;
    /**
     * Returns a getter function for normal population.
     *
     * @param {Object} data
     * @param {Model} model
     * @param {Object} options
     * @return {Function}
     * @private
     */
    _populateGetter(data: PropertyKey, model: Model<T>, options: unknown): () => Document<T>;
    /**
     * Returns a getter function for array population.
     *
     * @param {Object} data
     * @param {Model} model
     * @param {Object} options
     * @return {Function}
     * @private
     */
    _populateGetterArray(data: PropertyKey[], model: Model<T>, options: Partial<Options>): () => T[] | Query<T>;
    /**
     * Populates document references with a compiled stack.
     *
     * @param {Object} data
     * @param {Array} stack
     * @return {Object}
     * @private
     */
    _populate(data: Document<T>, stack: Partial<Options>[]): Document<T>;
    /**
     * Populates document references.
     *
     * @param {String|Object} path
     * @return {Query}
     */
    populate(path: string | string[] | Partial<Options>[] | Partial<Options>): Query<T>;
    /**
     * Imports data.
     *
     * @param {Array} arr
     * @private
     */
    _import(arr: any[]): void;
    /**
     * Exports data.
     *
     * @return {String}
     * @private
     */
    _export(): string;
    toJSON(): any[];
    get: Model<T>['findById'];
    size: Model<T>['count'];
    each: Model<T>['forEach'];
    random: Model<T>['shuffle'];
}
export default Model;
