Skip to content

Instantly share code, notes, and snippets.

@taxilian
Last active June 19, 2019 11:19
Show Gist options
  • Save taxilian/a05a5246b1d6a4c0bd2b26dfe5443d24 to your computer and use it in GitHub Desktop.
Save taxilian/a05a5246b1d6a4c0bd2b26dfe5443d24 to your computer and use it in GitHub Desktop.
Mongoose.js helper library using typescript decorators to define models

Purpose

This is a library of sorts for using mongoose in Typescript. It lets you define models in a class so that you get type information. There are some limitations, but it works pretty well.

Requirements

You'll probably need to use the custom mongoose.d.ts and mongodb.d.ts files included in this gist. I have them there simply because I've been too lazy so far to figure out where to submit them -- I modified the ones from definitely typed because those frankly were out of date and/or otherwise woefully incomplete.

You also need the 'reflect-metadata' npm package and you need to have "experimentalDecorators": true and "emitDecoratorMetadata": true in your tsconfig.json file for your project.

We use bluebird for our Promise library, and assumptions to that end currently exist in the .d.ts files. That should be easy to fix, but it's one of the reasons this is in a gist and not a npm library so far.

Defining a Schema

There are a number of decorators that you can use in this, but there are two critical ones to understand:

  • schemaDef - this needs to decorate a class which defines a mongoose schema. You can provide options if desired. (see examples below)
  • field - this is the most basic type to decorate a field definition. It accepts an object with the same options you'd pass to define a type in a normal mongosoe schema, but if possible the type will be auto detected using decorator metadata from typescript.
  • Note that array types cannot be correctly detected, so you should either use the arrayField decorator or specify the type in the @field options

Example Schema

This is an example user schema which uses this library. Things to note:

  • Field decorators can be stacked if you want

  • All field decorators are specializations of @field:

  • @required is equivalent to @field({required: true})

  • @arrayField(foo) is equivalent to @field({type: [foo]})

  • @defaultVal(val) is equvalent to @field({default: val})

  • @ref('User', {required: true}) is equavalent to @required({ref: 'User'}), @required @ref('User'), and also @field({ref: 'User', required: true})

  • The model name will come from the class name; that regex may only work correctly when targeting es6, so this should be checked and fixed to work with older targets if needed. We use node 4 and later, so es6 is a reasonable target for us.

  • Methods inside the class don't know about the members added from mongoose's Document and Model classes, so if you need those you'll have to typecast this. e.g. let self: IUserDocument = <any>this, UserModel: IUserModel = <any>this.constructor on a normal method or let self: IUserModel = <any>this; on a static method.

  • getter / setter properties will be automatically made into virtuals

    import * from mongoose as 'mongoose'; import {schemaDef, field, defaultVal, lower, upper, arrayField, required, regex, pre, IMongooseDocument, ModelFromSchemaDef} from './MongooseDecorators';

    export function hashPassword(password:string) { return crypto.createHash("md5").update(password).digest("hex"); }

    @schemaDef({ indexes: [ [{type: 1, identifier: 1}] ] }) class UserAuthProvider { @required type: string; @required identifier: string; @field({match: emailValidate}) email: string; }

    @schemaDef({ indexes: [ [{username: 1}, {unique: true}], [{email: 1}] ] }) export class User { _id: mongoose.Types.ObjectId;

      // Define schema fields
      @required({lowercase: true})  username: string;
      @required({lowercase: true})  email: string;
    
      @defaultVal(Date.now)         created: Date;
      @defaultVal(Date.now)         modified: Date;
    
      @required                     first: string;
      @required                     last: string;
    
      @field                        password: string;
      @arrayField(String)           permissions: string[];
    
      @defaultVal(false)            validated: boolean;
      @defaultVal(false)            passInvalid: boolean;
    
      @arrayField(UserAuthProvider) providers: mongoose.DocumentArray<UserAuthProvider>;
      
      get fullname() { return this.getFullName(); }
    
      getFullName() { return this.first + ' ' + this.last; }
      setPassword(newPass:string) {
          this.password = hashPassword(newPass);
      }
      // Allow login by username or password
      static authenticate(username:string, password:string, done:Function) {
          let User:IUserModel = <any>this;
          User.find({$or: [{username: username}, {email: username}], password: hashPassword(password)}).findOne((err, user) => {
              if (err) {
                  return done(err);
              } else if (!user) {
                  return done(null, false, {message:'Invalid username or password'});
              } else {
                  return done(null, user);
              }
          });
      }
    
      @pre("save")
      onPreSave(next:Function) {
          console.log("Presave");
          this.modified = new Date();
          next();
      }
    

    }

    export const UserModel = ModelFromSchemaDef<typeof User, User>(User, mongoose.connection); export type IUserDocument = IMongooseDocument; export type IUserModel = typeof UserModel;

import 'reflect-metadata';
import {Schema} from 'mongoose';
let excludeStatics = ['length', 'name', 'prototype'];
let excludeMethods = ['constructor'];
function shouldIgnore(obj: any, propertyKey: string) {
return propertyKey.substr(0, 3) == '_$_' || !!Reflect.getMetadata('schema:ignore', obj, propertyKey) as boolean;
}
interface PropertyInfo {
name: string;
getter?: Function;
setter?: Function;
}
function log(msg: string, debug: boolean) {
if (debug) { console.log(msg); }
}
export default function MixinPlugin(schema:Schema, options:any, debug: boolean = false) {
let statics = Object.getOwnPropertyNames(options);
let methods = Object.getOwnPropertyNames(options.prototype);
let properties: PropertyInfo[] = methods.map<PropertyInfo>((prop) => {
let info = {
name: prop,
getter: options.prototype.__lookupGetter__(prop),
setter: options.prototype.__lookupSetter__(prop),
};
return info;
}).filter((info) => !!(info.getter || info.setter));
let propertyNames = properties.map((info) => info.name);
statics = statics.filter(n => !shouldIgnore(options, n) && excludeStatics.indexOf(n) == -1 && typeof options[n] == 'function');
methods = methods.filter(n => !shouldIgnore(options.prototype, n) && excludeMethods.indexOf(n) == -1 && propertyNames.indexOf(n) == -1 && typeof options.prototype[n] == 'function');
statics.forEach(n => { log(`Found static ${n}`, debug); schema.static(n, options[n]); });
methods.forEach(n => { log(`Found method ${n}`, debug); schema.method(n, options.prototype[n]); });
properties.forEach((prop) => {
let virtual = schema.virtual(prop.name);
if (prop.getter) { virtual.get(prop.getter); }
if (prop.setter) { virtual.set(prop.setter); }
});
if (debug) {
console.log("After applying mixin plugin we have the following:", schema.statics, schema.methods);
}
};
// Type definitions for MongoDB
// Project: https://github.com/mongodb/node-mongodb-native
// Definitions by: Boris Yankov <https://github.com/borisyankov/>
// Heavily modified by: Richard Bateman <rbateman@gradecam.com>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
// Documentation : http://mongodb.github.io/node-mongodb-native/
// /// <reference path='../node/node.d.ts' />
declare module "mongodb" {
interface PromiseConstructor {
(resolve:Function, reject: Function): void;
}
interface PromiseLike<T> {
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult>(onfulfilled?: (value: T) => TResult | PromiseLike<TResult>, onrejected?: (reason: any) => TResult | PromiseLike<TResult>): PromiseLike<TResult>;
then<TResult>(onfulfilled?: (value: T) => TResult | PromiseLike<TResult>, onrejected?: (reason: any) => void): PromiseLike<TResult>;
}
interface MongoClientOptions {
// default: false. Uri decode the user name and password for authentication
uri_decode_auth?:boolean;
// default: null. A hash of options to set on the db object, see Db constructor
db?:DbCreateOptions;
// default: null. A hash of options to set on the server objects, see Server constructor**
server?:ServerOptions;
// default: null. A hash of options to set on the replSet object, see ReplSet constructor**
replSet?:ReplicaSetOptions;
// default: null. A hash of options to set on the mongos object, see Mongos constructor**
mongos?:MongosOptions;
// default: (ES6 Promise or polyfill). A Promise library class the application wishes to use
// such as Bluebird, must be ES6 compatible
promiseLibrary?:PromiseConstructor;
}
interface ChildDbOptions {
noListener?: boolean;
returnNonCachedInstance?: boolean;
}
interface EvalOptions {
// Tell MongoDB not to block on the evaluation of the javascript
nolock?: boolean;
}
interface CommandOptions {
readPreference?: ReadPreference|string;
maxTimeMS?: number;
}
interface IndexInformationOptions {
readPreference?: ReadPreference|string;
// If true, returns the full raw index information
full?: boolean;
}
interface RemoveUserOptions {
w: number|string;
wtimeout: number;
j: boolean;
}
interface connectCallback {
(err: Error, db: Db) : void;
}
// http://mongodb.github.io/node-mongodb-native/2.0/api/MongoClient.html
export class MongoClient{
constructor();
static connect(url:string, options:MongoClientOptions, callback:connectCallback) : PromiseLike<Db>;
static connect(uri: string, callback:connectCallback): PromiseLike<Db>;
connect(url:string, options:MongoClientOptions, callback:connectCallback) : PromiseLike<Db>;
connect(uri: string, callback:connectCallback): PromiseLike<Db>;
}
// Class documentation : http://mongodb.github.io/node-mongodb-native/api-generated/server.html
export class Server {
constructor (host: string, port: number, opts?: ServerOptions);
public connect(): any;
}
interface DbResultCallback {
(err:Error, result:any) : void;
}
// Class documentation : http://mongodb.github.io/node-mongodb-native/api-generated/db.html
export class Db {
constructor (databaseName: string, serverConfig: Server, dbOptions?: DbCreateOptions);
public addUser(username: string, password: string, callback: DbResultCallback ): void;
public addUser(username: string, password: string, options: any, callback: DbResultCallback ): void;
public addUser<T>(username: string, password: string): PromiseLike<T>;
public addUser<T>(username: string, password: string, options: any): PromiseLike<T>;
public admin(callback: DbResultCallback ): any;
public authenticate(userName: string, password: string, callback: DbResultCallback ): void;
public authenticate(userName: string, password: string, options: any, callback: DbResultCallback ): void;
public authenticate<T>(userName: string, password: string): PromiseLike<T>;
public authenticate<T>(userName: string, password: string, options: any): PromiseLike<T>;
public close(forceClose: boolean, callback: DbResultCallback ): void;
public close(callback: DbResultCallback ): void;
public close<T>(forceClose?: boolean ): PromiseLike<T>;
public collection(collectionName: string, callback?: CollectionResultCallback ): Collection;
public collection(collectionName: string, options?: MongoCollectionOptions, callback?: CollectionResultCallback ): Collection;
public collections(callback: CollectionsResultCallback ): void;
public collections(): PromiseLike<Collection[]>;
public command(selector: Object, callback: DbResultCallback ): void;
public command(selector: Object, options: any, callback: DbResultCallback ): void;
public command<T>(selector: Object): PromiseLike<T>;
public command<T>(selector: Object, options: any ): PromiseLike<T>;
public createCollection(collectionName: string, callback: CollectionResultCallback ): void;
public createCollection(collectionName: string, options: CollectionCreateOptions, callback: CollectionResultCallback ): void;
public createCollection(collectionName: string ): void;
public createCollection(collectionName: string, options?: CollectionCreateOptions ): PromiseLike<Collection>;
public createIndex(collectionName: string, fieldOrSpec: any, options: IndexOptions, callback: DbResultCallback): void;
public createIndex(collectionName: string, fieldOrSpec: any, options?: IndexOptions): PromiseLike<string>;
public db(dbName: string, dbOpts?:ChildDbOptions): Db;
public dropCollection(collectionName: string, callback: Function ): void;
public dropCollection(collectionName: string ): PromiseLike<any>;
public dropDatabase(callback: DbResultCallback ): void;
public dropDatabase(): PromiseLike<any>;
public ensureIndex(collectionName: any, fieldOrSpec: any, options: IndexOptions, callback: Function): void;
public ensureIndex(collectionName: any, fieldOrSpec: any, options: IndexOptions): PromiseLike<any>;
public eval(code: any, parameters: any, options: EvalOptions, callback: DbResultCallback ): void;
public eval(code: any, parameters: any, callback: DbResultCallback ): void;
public eval<T>(code: any, parameters: any, options?: EvalOptions ): PromiseLike<T>;
public executeDbAdminCommand(command_hash: any, callback: DbResultCallback ): void;
public executeDbAdminCommand(command_hash: any, options: CommandOptions, callback: DbResultCallback ): void;
public executeDbAdminCommand<T>(command_hash: any, options?: CommandOptions ): PromiseLike<T>;
public indexInformation(collectionName: string, options: any, callback: DbResultCallback): void;
public indexInformation(collectionName: string, options: any): PromiseLike<any>;
// TODO: This should return a CommandCursor
public listCollections(filter:any, options:{batchSize?:number}) : any;
public logout(callback: DbResultCallback ): void;
public logout(options: {dbName?:string}, callback: DbResultCallback ): void;
public logout(options: {dbName?:string}): PromiseLike<boolean>;
public open(callback: (err : Error, db : Db) => void ): void;
public open(): PromiseLike<Db>;
public removeUser(username: string, callback: DbResultCallback ): void;
public removeUser(username: string, options: RemoveUserOptions, callback: DbResultCallback ): void;
public removeUser(username: string, options?: RemoveUserOptions): PromiseLike<boolean>;
public renameCollection(fromCollection: string, toCollection: string, options:{dropTarget?:boolean}, callback: DbResultCallback ): void;
public renameCollection(fromCollection: string, toCollection: string, callback: DbResultCallback ): void;
public renameCollection(fromCollection: string, toCollection: string): PromiseLike<any>;
public stats(options: {scale?:number}, callback: DbResultCallback): void;
public stats(callback: DbResultCallback): void;
public stats(options?: {scale?:number}): PromiseLike<any>;
}
// Class documentation : http://mongodb.github.io/node-mongodb-native/api-bson-generated/objectid.html
// Last update: doc. version 1.3.13 (28.08.2013)
export class ObjectID {
constructor (s?: string);
// Creates an ObjectID from a hex string representation of an ObjectID.
// hexString – create a ObjectID from a passed in 24 byte hexstring.
public static createFromHexString(hexString: string): ObjectID;
// Creates an ObjectID from a second based number, with the rest of the ObjectID zeroed out. Used for comparisons or sorting the ObjectID.
// time – an integer number representing a number of seconds.
public static createFromTime(time: number): ObjectID;
// Checks if a value is a valid bson ObjectId
// id - Value to be checked
public static isValid(id: string): Boolean;
// Compares the equality of this ObjectID with otherID.
public equals(otherID: ObjectID) : boolean;
// Generate a 12 byte id string used in ObjectID's
// time - optional parameter allowing to pass in a second based timestamp
public generate(time?: number): string;
// Returns the generation date (accurate up to the second) that this ID was generated.
public getTimestamp(): Date;
// Returns the ObjectID id as a 24 byte hex string representation
public toHexString() : string;
}
// Class documentation : http://mongodb.github.io/node-mongodb-native/api-bson-generated/binary.html
export class Binary {
constructor (buffer: Buffer, subType?: number);
// The length of the binary.
length(): number;
// Updates this binary with byte_value
put(byte_value: any): void;
// Reads length bytes starting at position.
read(position: number, length: number): Buffer;
// Returns the value of this binary as a string.
value(): string;
// Writes a buffer or string to the binary
write(buffer: any, offset: number): void;
}
export interface SocketOptions {
//= set seconds before connection times out default:0
connectTimeoutMS?: number;
//= TCP Socket timeout setting
socketTimeoutMS?: number;
//= Disables the Nagle algorithm default:true
noDelay?: boolean;
//= Set if keepAlive is used default:0 , which means no keepAlive, set higher than 0 for keepAlive
keepAlive?: number;
}
export interface BasicServerOptions {
// - specify the number of connections in the pool default:5
poolSize?: number;
// - Use ssl connection (needs to have a mongod server with ssl support)
ssl?: boolean;
// - Validate mongod server certificate against ca (needs to have a mongod server with ssl support, 2.4 or higher)
sslValidate?: boolean;
// - Array of valid certificates either as Buffers or Strings (needs to have a mongod server with ssl support, 2.4 or higher)
sslCA?: Array<Buffer|string>;
// - String or buffer containing the certificate we wish to present (needs to have a mongod server with ssl support, 2.4 or higher)
sslCert?: Buffer|string;
// - String or buffer containing the certificate private key we wish to present (needs to have a mongod server with ssl support, 2.4 or higher)
sslKey?: Buffer|string;
// - String or buffer containing the certificate password (needs to have a mongod server with ssl support, 2.4 or higher)
sslPass?: Buffer|string;
// - a collection of pr socket settings
socketOptions?: SocketOptions;
}
// from http://mongodb.github.io/node-mongodb-native/2.0/api/Server.html
interface ServerOptions extends BasicServerOptions {
// - Server attempt to reconnect #times (default 30)
reconnectTries?:number;
// - Server will wait # milliseconds between retries (default 1000)
reconnectInterval?:number;
}
// from http://mongodb.github.io/node-mongodb-native/2.0/api/ReplSet.html
interface ReplicaSetOptions extends BasicServerOptions {
// - Turn on high availability monitoring.
ha?: boolean;
// - Time between each replicaset status check.
haInterval?: number;
// - (no default) The name of the replicaset to connect to.
replicaSet?: string;
// - (15) Sets the range of servers to pick when using NEAREST (lowest ping ms + the latency fence, ex: range of 1 to (1 + 15) ms)
secondaryAcceptableLatencyMS?: number;
// - (false) Sets if the driver should connect even if no primary is available
connectWithNoPrimary?: boolean;
}
// from http://mongodb.github.io/node-mongodb-native/2.0/api/Mongos.html
interface MongosOptions extends BasicServerOptions {
// - Turn on high availability monitoring.
ha?: boolean;
// - Time between each replicaset status check.
haInterval?: number;
}
export interface PKFactory {
counter: number;
createPk: () => number;
}
// See : http://mongodb.github.io/node-mongodb-native/api-generated/db.html
// Current definition by documentation version 1.3.13 (28.08.2013)
export interface DbCreateOptions {
// If the database authentication is dependent on another databaseName.
authSource?: string;
// the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = ‘majority’ or tag acknowledges the write.
w?: number|string;
// set the timeout for waiting for write concern to finish (combines with w option).
wtimeout?: number;
// Specify a journal write concern.
j?: boolean;
// use c++ bson parser. default:false.
native_parser?: boolean;
// force server to create _id fields instead of client. default:false.
forceServerObjectId?: boolean;
// serialize functions. default:false.
serializeFunctions?: boolean;
ignoreUndefined?: boolean;
// peform operations using raw bson buffers. default:false.
raw?: boolean;
// when deserializing a Long will fit it into a Number if it’s smaller than 53 bits. default:true.
promoteLongs?: boolean;
bufferMaxEntries?: number;
// the prefered read preference. use 'ReadPreference' class.
readPreference?: ReadPreference|string;
// custom primary key factory to generate _id values (see Custom primary keys).
pkFactory?: PKFactory;
// default: (ES6 Promise or polyfill). A Promise library class the application wishes to use
// such as Bluebird, must be ES6 compatible
promiseLibrary?:PromiseConstructor;
// Specify a read concern for the collection. (only MongoDB 3.2 or higher supported)
readConcern?: {
// Specify a read concern level for the collection operations, one of [local|majority]. (only MongoDB 3.2 or higher supported)
level: string;
};
}
export class ReadPreference {
public static PRIMARY: string;
public static PRIMARY_PREFERRED: string;
public static SECONDARY: string;
public static SECONDARY_PREFERRED: string;
public static NEAREST: string;
}
// See : http://mongodb.github.io/node-mongodb-native/api-generated/collection.html
// Current definition by documentation version 1.3.13 (28.08.2013)
export interface CollectionCreateOptions {
// the prefered read preference. use 'ReadPreference' class.
readPreference?: ReadPreference|string;
// Allow reads from secondaries. default:false.
slaveOk?: boolean;
// serialize functions on the document. default:false.
serializeFunctions?: boolean;
// perform all operations using raw bson objects. default:false.
raw?: boolean;
// object overriding the basic ObjectID primary key generation.
pkFactory?: PKFactory;
}
// Documentation: http://docs.mongodb.org/manual/reference/command/collStats/
export interface CollStats {
// Namespace.
ns: string;
// Number of documents.
count: number;
// Collection size in bytes.
size: number;
// Average object size in bytes.
avgObjSize: number;
// (Pre)allocated space for the collection in bytes.
storageSize: number;
// Number of extents (contiguously allocated chunks of datafile space).
numExtents: number;
// Number of indexes.
nindexes: number;
// Size of the most recently created extent in bytes.
lastExtentSize: number;
// Padding can speed up updates if documents grow.
paddingFactor: number;
flags: number;
// Total index size in bytes.
totalIndexSize: number;
// Size of specific indexes in bytes.
indexSizes: {
_id_: number;
username: number;
};
}
interface CollectionResultCallback {
(err:Error, collection:Collection) : void;
}
interface CollectionsResultCallback {
(err:Error, collections:Collection[]) : void;
}
interface OpenDbCallback {
(err:Error, db:Db) : void;
}
// TODO: Update this for node-mongodb-native 2.0
// Documentation : http://mongodb.github.io/node-mongodb-native/api-generated/collection.html
export interface Collection {
new (db: Db, collectionName: string, pkFactory?: Object, options?: CollectionCreateOptions): Collection; // is this right?
/**
* @deprecated use insertOne or insertMany
* Documentation : http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#insert
*/
insert(query: any, callback: DbResultCallback): void;
insert(query: any, options: { safe?: any; continueOnError?: boolean; keepGoing?: boolean; serializeFunctions?: boolean; }, callback: DbResultCallback): void;
// Documentation : http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#insertOne
insertOne(doc:any, callback: DbResultCallback) :void;
insertOne(doc: any, options: { w?: any; wtimeout?: number; j?: boolean; serializeFunctions?: boolean; forceServerObjectId?: boolean }, callback: DbResultCallback): void;
// Documentation : http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#insertMany
insertMany(docs: any, callback: DbResultCallback): void;
insertMany(docs: any, options: { w?: any; wtimeout?: number; j?: boolean; serializeFunctions?: boolean; forceServerObjectId?: boolean }, callback: DbResultCallback): void;
/**
* @deprecated use deleteOne or deleteMany
* Documentation : http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#remove
*/
remove(selector: Object, callback?: DbResultCallback): void;
remove(selector: Object, options: { safe?: any; single?: boolean; }, callback?: DbResultCallback): void;
// Documentation : http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#deleteOne
deleteOne(filter: any, callback: DbResultCallback): void;
deleteOne(filter: any, options: { w?: any; wtimeout?: number; j?: boolean;}, callback: DbResultCallback): void;
// Documentation : http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#deleteMany
deleteMany(filter: any, callback: DbResultCallback): void;
deleteMany(filter: any, options: { w?: any; wtimeout?: number; j?: boolean;}, callback: DbResultCallback): void;
rename(newName: String, callback?: DbResultCallback): void;
save(doc: any, callback : DbResultCallback): void;
save(doc: any, options: { w?: any; wtimeout?: number; j?: boolean;}, callback : DbResultCallback): void;
/**
* @deprecated use updateOne or updateMany
* Documentation : http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#update
*/
update(selector: Object, document: any, callback?: DbResultCallback): void;
update(selector: Object, document: any, options: { safe?: boolean; upsert?: any; multi?: boolean; serializeFunctions?: boolean; }, callback: DbResultCallback): void;
// Documentation : http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#updateOne
updateOne(filter: Object, update: any, callback: DbResultCallback): void;
updateOne(filter: Object, update: any, options: { upsert?: boolean; w?: any; wtimeout?: number; j?: boolean;}, callback: DbResultCallback): void;
// Documentation : http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#updateMany
updateMany(filter: Object, update: any, callback: DbResultCallback): void;
updateMany(filter: Object, update: any, options: { upsert?: boolean; w?: any; wtimeout?: number; j?: boolean;}, callback: DbResultCallback): void;
distinct(key: string, query: Object, callback: DbResultCallback): void;
distinct(key: string, query: Object, options: { readPreference: ReadPreference|string; }, callback: DbResultCallback): void;
count(callback: DbResultCallback): void;
count(query: Object, callback: DbResultCallback): void;
count(query: Object, options: { readPreference: ReadPreference|string; }, callback: DbResultCallback): void;
drop(callback?: DbResultCallback): void;
/**
* @deprecated use findOneAndUpdate, findOneAndReplace or findOneAndDelete
* Documentation : http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndModify
*/
findAndModify(query: Object, sort: any[], doc: Object, callback: DbResultCallback): void;
findAndModify(query: Object, sort: any[], doc: Object, options: { safe?: any; remove?: boolean; upsert?: boolean; new?: boolean; }, callback: DbResultCallback): void;
/**
* @deprecated use findOneAndDelete
* Documentation : http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findAndRemove
*/
findAndRemove(query : Object, sort? : any[], callback?: DbResultCallback): void;
findAndRemove(query : Object, sort? : any[], options?: { safe: any; }, callback?: DbResultCallback): void;
// Documentation : http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findOneAndDelete
findOneAndDelete(filter: any, callback: DbResultCallback): void;
findOneAndDelete(filter: any, options: { projection?: any; sort?: any; maxTimeMS?: number; }, callback: DbResultCallback): void;
// Documentation : http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findOneAndReplace
findOneAndReplace(filter: any, replacement: any, callback: DbResultCallback): void;
findOneAndReplace(filter: any, replacement: any, options: { projection?: any; sort?: any; maxTimeMS?: number; upsert?: boolean; returnOriginal?: boolean }, callback: DbResultCallback): void;
// Documentation : http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#findOneAndUpdate
findOneAndUpdate(filter: any, update: any, callback: DbResultCallback): void;
findOneAndUpdate(filter: any, update: any, options: { projection?: any; sort?: any; maxTimeMS?: number; upsert?: boolean; returnOriginal?: boolean }, callback: DbResultCallback): void;
find(callback?: (err: Error, result: Cursor) => void): Cursor;
find(selector: Object, callback?: (err: Error, result: Cursor) => void): Cursor;
find(selector: Object, fields: any, callback?: (err: Error, result: Cursor) => void): Cursor;
find(selector: Object, options: CollectionFindOptions, callback?: (err: Error, result: Cursor) => void): Cursor;
find(selector: Object, fields: any, options: CollectionFindOptions, callback?: (err: Error, result: Cursor) => void): Cursor;
find(selector: Object, fields: any, skip: number, limit: number, callback?: (err: Error, result: Cursor) => void): Cursor;
find(selector: Object, fields: any, skip: number, limit: number, timeout: number, callback?: (err: Error, result: Cursor) => void): Cursor;
findOne(callback?: DbResultCallback): Cursor;
findOne(selector: Object, callback?: DbResultCallback): Cursor;
findOne(selector: Object, fields: any, callback?: DbResultCallback): Cursor;
findOne(selector: Object, options: CollectionFindOptions, callback?: DbResultCallback): Cursor;
findOne(selector: Object, fields: any, options: CollectionFindOptions, callback?: DbResultCallback): Cursor;
findOne(selector: Object, fields: any, skip: number, limit: number, callback?: DbResultCallback): Cursor;
findOne(selector: Object, fields: any, skip: number, limit: number, timeout: number, callback?: DbResultCallback): Cursor;
createIndex(fieldOrSpec: any, callback: (err: Error, indexName: string) => void): void;
createIndex(fieldOrSpec: any, options: IndexOptions, callback: (err: Error, indexName: string) => void): void;
ensureIndex(fieldOrSpec: any, callback: (err: Error, indexName: string) => void): void;
ensureIndex(fieldOrSpec: any, options: IndexOptions, callback: (err: Error, indexName: string) => void): void;
indexInformation(options: any, callback: Function): void;
dropIndex(name: string, callback: Function): void;
dropAllIndexes(callback: Function): void;
// dropIndexes = dropAllIndexes
reIndex(callback: Function): void;
mapReduce(map: Function, reduce: Function, options: MapReduceOptions, callback: Function): void;
group(keys: Object, condition: Object, initial: Object, reduce: Function, finalize: Function, command: boolean, options: {readPreference: ReadPreference|string}, callback: Function): void;
options(callback: Function): void;
isCapped(callback: Function): void;
indexExists(indexes: string, callback: Function): void;
geoNear(x: number, y: number, callback: Function): void;
geoNear(x: number, y: number, options: Object, callback: Function): void;
geoHaystackSearch(x: number, y: number, callback: Function): void;
geoHaystackSearch(x: number, y: number, options: Object, callback: Function): void;
indexes(callback: Function): void;
aggregate(pipeline: any[], callback: (err: Error, results: any) => void): void;
aggregate(pipeline: any[], options: {readPreference: ReadPreference|string}, callback: (err: Error, results: any) => void): void;
stats(options: {readPreference: ReadPreference|string; scale: number}, callback: (err: Error, results: CollStats) => void): void;
stats(callback: (err: Error, results: CollStats) => void): void;
hint: any;
}
export interface MapReduceOptions {
out?: Object;
query?: Object;
sort?: Object;
limit?: number;
keeptemp?: boolean;
finalize?: any;
scope?: Object;
jsMode?: boolean;
verbose?: boolean;
readPreference?: ReadPreference|string;
}
export interface IndexOptions {
w?: number|string;
wtimeout?: number;
j?: boolean;
unique?: boolean;
sparse?: boolean;
background?: boolean;
dropDups?: boolean;
min?: number;
max?: number;
v?: number;
expireAfterSeconds?: number;
name?: string;
}
// Class documentation : http://mongodb.github.io/node-mongodb-native/api-generated/cursor.html
// Last update: doc. version 1.3.13 (29.08.2013)
export class Cursor {
// INTERNAL TYPE
// constructor (db: Db, collection: Collection, selector, fields, skip, limit, sort, hint, explain, snapshot, timeout, tailable, batchSize, slaveOk, raw, read, returnKey, maxScan, min, max, showDiskLoc, comment, awaitdata, numberOfRetries, dbName, tailableRetryInterval, exhaust, partial);
// constructor(db: Db, collection: Collection, selector, fields, options);
rewind() : Cursor;
toArray(callback: (err: Error, results: any[]) => any) : void;
each(callback: (err: Error, item: any) => void) : void;
count(applySkipLimit: boolean, callback: (err: Error, count: number) => void) : void;
sort(keyOrList: any, callback? : DbResultCallback): Cursor;
// this determines how the results are sorted. "asc", "ascending" or 1 for asceding order while "desc", "desceding or -1 for descending order. Note that the strings are case insensitive.
sort(keyOrList: String, direction : string, callback : DbResultCallback): Cursor;
limit(limit: number, callback?: DbResultCallback): Cursor;
setReadPreference(preference: string, callback?: Function): Cursor;
skip(skip: number, callback?: DbResultCallback): Cursor;
batchSize(batchSize: number, callback?: DbResultCallback): Cursor;
nextObject(callback: (err: Error, doc: any) => void) : void;
explain(callback: DbResultCallback) : void;
stream(): CursorStream;
close(callback: DbResultCallback) : void;
isClosed(): boolean;
public static INIT: number;
public static OPEN: number;
public static CLOSED: number;
public static GET_MORE: number;
}
// Class documentation : http://mongodb.github.io/node-mongodb-native/api-generated/cursorstream.html
// Last update: doc. version 1.3.13 (29.08.2013)
export class CursorStream {
constructor(cursor: Cursor);
public pause(): any;
public resume(): any;
public destroy(): any;
}
export interface CollectionFindOptions {
limit?: number;
sort?: any;
fields?: Object;
skip?: number;
hint?: Object;
explain?: boolean;
snapshot?: boolean;
timeout?: boolean;
tailtable?: boolean;
tailableRetryInterval?: number;
numberOfRetries?: number;
awaitdata?: boolean;
oplogReplay?: boolean;
exhaust?: boolean;
batchSize?: number;
returnKey?: boolean;
maxScan?: number;
min?: number;
max?: number;
showDiskLoc?: boolean;
comment?: String;
raw?: boolean;
readPreference?: ReadPreference|string;
partial?: boolean;
}
export interface MongoCollectionOptions {
safe?: any;
serializeFunctions?: any;
strict?: boolean;
raw?: boolean;
pkFactory?: any;
readPreference?: ReadPreference|string;
}
}
// Type definitions for Mongoose 3.8.5
// Project: http://mongoosejs.com/
// Definitions by: horiuchi <https://github.com/horiuchi/>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
// tslint:disable
///<reference path="../mongodb/mongodb.d.ts" />
declare module "mongoose" {
// interface Promise {
// then<U>(onFulfill: (value: R) => U | Promise<U>, onReject?: (error: any) => U | Promise<U>): Promise<U>;
// then<U>(onFulfill: (value: R) => U | Promise<U>, onReject?: (error: any) => void | Promise<void>): Promise<U>;
// }
import * as Promise from 'bluebird';
import * as mongodb from 'mongodb';
import * as stream from 'stream';
function connect(uri: string, options?: ConnectionOptions , callback?: (err: any) => void): Mongoose;
function createConnection(): Connection;
function createConnection(uri: string, options?: ConnectionOptions): Connection;
function createConnection(host: string, database_name: string, port?: number, options?: ConnectionOptions): Connection;
function disconnect(callback?: (err?: any) => void): Mongoose;
function model<T extends Document>(name: string, schema?: Schema, collection?: string, skipInit?: boolean): Model<T>;
function modelNames(): string[];
function plugin(plugin: (schema: Schema, options?: any) => void, options?: any): Mongoose;
function get(key: string): any;
function set(key: string, value: any): void;
var mongo: any;
var mquery: any;
var version: string;
var connection: Connection;
var models: any;
export class Mongoose {
connect(uri: string, options?: ConnectOpenOptionsBase, callback?: (err: any) => void): Mongoose;
createConnection(): Connection;
createConnection(uri: string, options?: any): Connection;
createConnection(host: string, database_name: string, port?: number, options?: ConnectOpenOptionsBase): Connection;
disconnect(callback?: (err?: any) => void): Mongoose;
get(key: string): any;
model<T extends Document>(name: string, schema?: Schema, collection?: string, skipInit?: boolean): Model<T>;
modelNames(): string[];
plugin(plugin: (schema: Schema, options?: any) => void, options?: any): Mongoose;
set(key: string, value: any): void;
mongo: any;
mquery: any;
version: string;
connection: Connection;
}
export interface Connection extends NodeJS.EventEmitter {
constructor(base: Mongoose): Connection;
close(callback?: (err: any) => void): Connection;
collection(name: string, options?: any): Collection;
model<T extends Document>(name: string, schema?: Schema, collection?: string): Model<T>;
modelNames(): string[];
models: {[name:string]:Model<any>};
open(host: string, database?: string, port?: number, options?: OpenSetConnectionOptions, callback?: (err: any) => void): Connection;
openSet(uris: string, database?: string, options?: OpenSetConnectionOptions, callback?: (err: any) => void): Connection;
db: any;
collections: {[index: string]: Collection};
readyState: number;
}
export interface ConnectOpenOptionsBase {
db?: DbCreateOptions;
server?: ServerOptions;
replset?: ReplicaSetOptions;
mongos?: MongosOptions;
/** Username for authentication if not supplied in the URI. */
user?: string;
/** Password for authentication if not supplied in the URI. */
pass?: string;
/** Options for authentication */
auth?: any;
}
export interface ConnectionOptions extends ConnectOpenOptionsBase {
/** Passed to the underlying driver's Mongos instance. */
mongos?: MongosOptions;
promiseLibrary?: any;
}
interface OpenSetConnectionOptions extends ConnectOpenOptionsBase {
/** If true, enables High Availability support for mongos */
mongos?: boolean;
}
export interface DbCreateOptions {
// If the database authentication is dependent on another databaseName.
authSource?: string;
// the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = ‘majority’ or tag acknowledges the write.
w?: number|string;
// set the timeout for waiting for write concern to finish (combines with w option).
wtimeout?: number;
// Specify a journal write concern.
j?: boolean;
// use c++ bson parser. default:false.
native_parser?: boolean;
// force server to create _id fields instead of client. default:false.
forceServerObjectId?: boolean;
// serialize functions. default:false.
serializeFunctions?: boolean;
ignoreUndefined?: boolean;
// peform operations using raw bson buffers. default:false.
raw?: boolean;
// when deserializing a Long will fit it into a Number if it’s smaller than 53 bits. default:true.
promoteLongs?: boolean;
bufferMaxEntries?: number;
// the prefered read preference. use 'ReadPreference' class.
readPreference?: ReadPreference|string;
// custom primary key factory to generate _id values (see Custom primary keys).
pkFactory?: any;
// default: (ES6 Promise or polyfill). A Promise library class the application wishes to use
// such as Bluebird, must be ES6 compatible
promiseLibrary?:PromiseConstructor;
// Specify a read concern for the collection. (only MongoDB 3.2 or higher supported)
readConcern?: {
// Specify a read concern level for the collection operations, one of [local|majority]. (only MongoDB 3.2 or higher supported)
level: string;
};
}
export interface SocketOptions {
//= set seconds before connection times out default:0
connectTimeoutMS?: number;
//= TCP Socket timeout setting
socketTimeoutMS?: number;
//= Disables the Nagle algorithm default:true
noDelay?: boolean;
//= Set if keepAlive is used default:0 , which means no keepAlive, set higher than 0 for keepAlive
keepAlive?: number;
}
export class ReadPreference {
public static PRIMARY: string;
public static PRIMARY_PREFERRED: string;
public static SECONDARY: string;
public static SECONDARY_PREFERRED: string;
public static NEAREST: string;
}
export interface BasicServerOptions {
// - specify the number of connections in the pool default:5
poolSize?: number;
// - Use ssl connection (needs to have a mongod server with ssl support)
ssl?: boolean;
// - Validate mongod server certificate against ca (needs to have a mongod server with ssl support, 2.4 or higher)
sslValidate?: boolean;
// - Array of valid certificates either as Buffers or Strings (needs to have a mongod server with ssl support, 2.4 or higher)
sslCA?: string|Buffer|string[]|Buffer[];
// - String or buffer containing the certificate we wish to present (needs to have a mongod server with ssl support, 2.4 or higher)
sslCert?: string|Buffer;
// - String or buffer containing the certificate private key we wish to present (needs to have a mongod server with ssl support, 2.4 or higher)
sslKey?: string|Buffer;
// - String or buffer containing the certificate password (needs to have a mongod server with ssl support, 2.4 or higher)
sslPass?: string|Buffer;
// - a collection of pr socket settings
socketOptions?: SocketOptions;
}
// from http://mongodb.github.io/node-mongodb-native/2.0/api/Server.html
interface ServerOptions extends BasicServerOptions {
// - Server attempt to reconnect #times (default 30)
reconnectTries?:number;
// - Server will wait # milliseconds between retries (default 1000)
reconnectInterval?:number;
}
// from http://mongodb.github.io/node-mongodb-native/2.0/api/ReplSet.html
interface ReplicaSetOptions extends BasicServerOptions {
// - Turn on high availability monitoring.
ha?: boolean;
// - Time between each replicaset status check.
haInterval?: number;
// - (no default) The name of the replicaset to connect to.
replicaSet?: string;
// - (15) Sets the range of servers to pick when using NEAREST (lowest ping ms + the latency fence, ex: range of 1 to (1 + 15) ms)
secondaryAcceptableLatencyMS?: number;
// - (false) Sets if the driver should connect even if no primary is available
connectWithNoPrimary?: boolean;
}
// from http://mongodb.github.io/node-mongodb-native/2.0/api/Mongos.html
interface MongosOptions extends BasicServerOptions {
// - Turn on high availability monitoring.
ha?: boolean;
// - Time between each replicaset status check.
haInterval?: number;
}
export type Collection = mongodb.Collection;
export class SchemaType { }
export class VirtualType {
get(fn: Function): VirtualType;
set(fn: Function): VirtualType;
}
namespace internal {
export class ObjectId {
constructor(id?: string|number|ObjectId);
toHexString(): string;
equals(other: ObjectId|string): boolean;
getTimestamp(): Date;
isValid(): boolean;
static isValid(val: string|number|ObjectId): boolean;
static createFromTime(time: number): ObjectId;
static createFromHexString(hexString: string): ObjectId;
}
}
export class Types { }
export namespace Types {
let ObjectId: typeof internal.ObjectId;
type ObjectId = internal.ObjectId;
}
type HookCallback = (next:Function, obj?:any) => void;
export class Schema {
constructor(schema?: any, options?: any);
tree: any;
add(obj: any, prefix?: string): void;
eachPath(fn: (path: string, type: any) => void): Schema;
get(key: string): any;
index(fields: any, options?: any): Schema;
indexes(): any[][];
method(name: string, fn: Function): Schema;
method(method: any): Schema;
path(path: string): any;
path(path: string, constructor: any): Schema;
pathType(path: string): string;
plugin(plugin: (schema: Schema, options?: any) => void, options?: any): Schema;
post(method: string, fn: HookCallback): Schema;
pre(method: string, callback: HookCallback): Schema;
requiredPaths(): string[];
set(key: string, value: any): void;
static(name: string, fn: Function): Schema;
statics: any;
methods: any;
paths: any;
virtual(name: string, options?: any): VirtualType;
virtualpath(name: string): VirtualType;
}
export namespace Schema {
let stringTyped: String;
interface ObjectIdConstructor {
new(id?: string|number|ObjectId) : internal.ObjectId;
schemaName: string;
}
export class Types { }
export namespace Types {
let String: String;
type String = typeof stringTyped;
let ObjectId: ObjectIdConstructor;
type ObjectId = internal.ObjectId;
let OId: ObjectIdConstructor;
type OId = internal.ObjectId;
let Mixed: any;
type Mixed = any;
}
export let ObjectId: ObjectIdConstructor;
export type ObjectId = internal.ObjectId;
}
export interface SchemaOption {
autoIndex?: boolean;
bufferCommands?: boolean;
capped?: boolean;
collection?: string;
id?: boolean;
_id?: boolean;
minimize?: boolean;
read?: string;
safe?: boolean;
shardKey?: boolean;
strict?: boolean;
toJSON?: any;
toObject?: any;
versionKey?: boolean;
}
export interface Model<T extends Document> extends NodeJS.EventEmitter {
new(doc?: any): T;
aggregate(...aggregations: any[]): Aggregate<T[]>;
aggregate(aggregation: any, callback: (err: any, res: T[]) => void): Promise<T[]>;
aggregate(aggregation1: any, aggregation2: any, callback: (err: any, res: T[]) => void): Promise<T[]>;
aggregate(aggregation1: any, aggregation2: any, aggregation3: any, callback: (err: any, res: T[]) => void): Promise<T[]>;
count(conditions: any, callback?: (err: any, count: number) => void): Query<number, number>;
create(doc: any, fn?: (err: any, res: T) => void): Promise<T>;
create(doc1: any, doc2: any, fn?: (err: any, res1: T, res2: T) => void): Promise<T[]>;
create(doc1: any, doc2: any, doc3: any, fn?: (err: any, res1: T, res2: T, res3: T) => void): Promise<T[]>;
discriminator<U extends Document>(name: string, schema: Schema): Model<U>;
distinct(field: string, callback?: (err: any, res: T[]) => void): Query<T[], T>;
distinct(field: string, conditions: any, callback?: (err: any, res: T[]) => void): Query<T[], T>;
ensureIndexes(options: any): Promise<T>;
ensureIndexes(options: any, callback: (err: any) => void): void;
ensureIndexes(): Promise<T>;
ensureIndexes(callback: (err: any) => void): void;
find(cond?: any, callback?: (err: any, res: T[]) => void): Query<T[], T>;
find(cond: any, fields: any, callback?: (err: any, res: T[]) => void): Query<T[], T>;
find(cond: any, fields: any, options: any, callback?: (err: any, res: T[]) => void): Query<T[], T>;
findById(id: string | internal.ObjectId, callback?: (err: any, res: T) => void): Query<T, T>;
findById(id: string | internal.ObjectId, fields: any, callback?: (err: any, res: T) => void): Query<T, T>;
findById(id: string | internal.ObjectId, fields: any, options: any, callback?: (err: any, res: T) => void): Query<T, T>;
findByIdAndRemove(id: string, callback?: (err: any, res: T) => void): Query<T, T>;
findByIdAndRemove(id: string, options: any, callback?: (err: any, res: T) => void): Query<T, T>;
findByIdAndUpdate(id: string, update: any, callback?: (err: any, res: T) => void): Query<T, T>;
findByIdAndUpdate(id: string, update: any, options: FindAndUpdateOption, callback?: (err: any, res: T) => void): Query<T, T>;
findOne(cond?: any, callback?: (err: any, res: T) => void): Query<T, T>;
findOne(cond: any, fields: any, callback?: (err: any, res: T) => void): Query<T, T>;
findOne(cond: any, fields: any, options: any, callback?: (err: any, res: T) => void): Query<T, T>;
findOneAndRemove(cond: any, callback?: (err: any, res: T) => void): Query<T, T>;
findOneAndRemove(cond: any, options: any, callback?: (err: any, res: T) => void): Query<T, T>;
findOneAndUpdate(cond: any, update: any, callback?: (err: any, res: T) => void): Query<T, T>;
findOneAndUpdate(cond: any, update: any, options: FindAndUpdateOption, callback?: (err: any, res: T) => void): Query<T, T>;
geoNear(point: { type: string; coordinates: number[] }, options: any, callback?: (err: any, res: T[]) => void): Query<T[], T>;
geoNear(point: number[], options: any, callback?: (err: any, res: T[]) => void): Query<T[], T>;
geoSearch(cond: any, options: GeoSearchOption, callback?: (err: any, res: T[]) => void): Query<T[], T>;
increment(): T;
mapReduce<K, V>(options: MapReduceOption<T, K, V>, callback?: (err: any, res: MapReduceResult<K, V>[]) => void): Promise<MapReduceResult<K, V>[]>;
mapReduce<K, V>(options: MapReduceOption2<T, K, V>, callback?: (err: any, res: MapReduceResult<K, V>[]) => void): Promise<MapReduceResult<K, V>[]>;
model<U extends Document>(name: string): Model<U>;
populate<U>(doc: U, options: any, callback?: (err: any, res: U) => void): Promise<U>;
populate<U>(doc: U[], options: any, callback?: (err: any, res: U[]) => void): Promise<U[]>;
update(cond: any, update: any, callback?: (err: any, affectedRows: number, raw: any) => void): Query<T, T>;
update(cond: any, update: any, options: any, callback?: (err: any, affectedRows: number, raw: any) => void): Query<T, T>;
remove(cond: any, callback?: (err: any) => void): Query<{}, {}>;
save(callback?: (err: any, result: T, numberAffected: number) => void): Query<T, T>;
where(path: string, val?: any): Query<T[], T>;
$where(argument: string): Query<T[], T>;
$where(argument: Function): Query<T[], T>;
base: Mongoose;
collection: Collection;
db: any;
discriminators: any;
modelName: string;
schema: Schema;
}
export interface DocumentArray<T> extends Array<T> {
addToSet?(...members: T[]) : T[];
create?(obj?:T) : T;
isMongooseDocumentArray?: boolean;
isMongooseArray?: boolean;
pull?(val:any) : DocumentArray<T>;
remove?(val:any) : DocumentArray<T>;
set?(index:number, val:T) : DocumentArray<T>;
toObject?(options?:{depopulate?:boolean}) : T[];
inspect?(): string;
indexOf(obj:T) : number;
nonAtomicPush?(...objects: T[]) : T[];
hasAtomics?:number;
id?: internal.ObjectId;
}
export interface FindAndUpdateOption {
new?: boolean;
upsert?: boolean;
sort?: any;
select?: any;
}
export interface GeoSearchOption {
near: number[];
maxDistance: number;
limit?: number;
lean?: boolean;
}
export interface MapReduceOption<T extends Document, Key, Val> {
map: () => void;
reduce: (key: Key, vals: T[]) => Val;
query?: any;
limit?: number;
keeptemp?: boolean;
finalize?: (key: Key, val: Val) => Val;
scope?: any;
jsMode?: boolean;
verbose?: boolean;
out?: {
inline?: number;
replace?: string;
reduce?: string;
merge?: string;
};
}
export interface MapReduceOption2<T extends Document, Key, Val> {
map: string;
reduce: (key: Key, vals: T[]) => Val;
query?: any;
limit?: number;
keeptemp?: boolean;
finalize?: (key: Key, val: Val) => Val;
scope?: any;
jsMode?: boolean;
verbose?: boolean;
out?: {
inline?: number;
replace?: string;
reduce?: string;
merge?: string;
};
}
export interface MapReduceResult<Key, Val> {
_id: Key;
value: Val;
}
export class Query<T, O> {
exec(callback?: (err: any, res: T) => void): Promise<T>;
exec(operation: string, callback?: (err: any, res: T) => void): Promise<T>;
exec(operation: Function, callback?: (err: any, res: T) => void): Promise<T>;
all(val: number): Query<T, O>;
all(path: string, val: number): Query<T, O>;
and(array: any[]): Query<T, O>;
box(val: any): Query<T, O>;
box(a: number[], b: number[]): Query<T, O>;
batchSize(val: number): Query<T, O>;
cast<U extends Document>(model: Model<U>, obj: any): U;
//center(): Query<T>;
//centerSphere(path: string, val: any): Query<T>;
circle(area: any): Query<T, O>;
circle(path: string, area: any): Query<T, O>;
comment(val: any): Query<T, O>;
count(callback?: (err: any, count: number) => void): Query<number, number>;
count(criteria: any, callback?: (err: any, count: number) => void): Query<number, number>;
cursor(options?: Object): QueryCursor<T, O>;
distinct(callback?: (err: any, res: T) => void): Query<T, O>;
distinct(field: string, callback?: (err: any, res: T) => void): Query<T, O>;
distinct(criteria: any, field: string, callback?: (err: any, res: T) => void): Query<T, O>;
distinct(criteria: Query<T, O>, field: string, callback?: (err: any, res: T) => void): Query<T, O>;
elemMatch(criteria: any): Query<T, O>;
elemMatch(criteria: (elem: Query<T, O>) => void): Query<T, O>;
elemMatch(path: string, criteria: any): Query<T, O>;
elemMatch(path: string, criteria: (elem: Query<T, O>) => void): Query<T, O>;
equals(val: any): Query<T, O>;
exists(val?: boolean): Query<T, O>;
exists(path: string, val?: boolean): Query<T, O>;
find(callback?: (err: any, res: T) => void): Query<T, O>;
find(criteria: any, callback?: (err: any, res: T) => void): Query<T, O>;
findOne(callback?: (err: any, res: T) => void): Query<O, O>;
findOne(criteria: any, callback?: (err: any, res: T) => void): Query<O, O>;
findOneAndRemove(callback?: (err: any, res: T) => void): Query<O, O>;
findOneAndRemove(cond: any, callback?: (err: any, res: T) => void): Query<O, O>;
findOneAndRemove(cond: any, options: any, callback?: (err: any, res: T) => void): Query<O, O>;
findOneAndUpdate(callback?: (err: any, res: T) => void): Query<O, O>;
findOneAndUpdate(update: any, callback?: (err: any, res: T) => void): Query<O, O>;
findOneAndUpdate(cond: any, update: any, callback?: (err: any, res: T) => void): Query<O, O>;
findOneAndUpdate(cond: any, update: any, options: FindAndUpdateOption, callback?: (err: any, res: T) => void): Query<O, O>;
geometry(object: any): Query<T, O>;
getUpdate(): any;
gt(val: number | Date): Query<T, O>;
gt(path: string, val: number | Date): Query<T, O>;
gte(val: number | Date): Query<T, O>;
gte(path: string, val: number | Date): Query<T, O>;
hint(val: any): Query<T, O>;
in(val: any[]): Query<T, O>;
in(path: string, val: any[]): Query<T, O>;
intersects(arg?: any): Query<T, O>;
lean(bool?: boolean): Query<T, O>;
limit(val: number): Query<T, O>;
lt(val: number | Date): Query<T, O>;
lt(path: string, val: number | Date): Query<T, O>;
lte(val: number | Date): Query<T, O>;
lte(path: string, val: number | Date): Query<T, O>;
maxDistance(val: number): Query<T, O>;
maxDistance(path: string, val: number): Query<T, O>;
maxScan(val: number): Query<T, O>;
merge(source: Query<T, O>): Query<T, O>;
merge(source: any): Query<T, O>;
mod(val: number[]): Query<T, O>;
mod(path: string, val: number[]): Query<T, O>;
ne(val: any): Query<T, O>;
ne(path: string, val: any): Query<T, O>;
near(val: any): Query<T, O>;
near(path: string, val: any): Query<T, O>;
nearSphere(val: any): Query<T, O>;
nearSphere(path: string, val: any): Query<T, O>;
nin(val: any[]): Query<T, O>;
nin(path: string, val: any[]): Query<T, O>;
nor(array: any[]): Query<T, O>;
or(array: any[]): Query<T, O>;
polygon(...coordinatePairs: number[][]): Query<T, O>;
polygon(path: string, ...coordinatePairs: number[][]): Query<T, O>;
populate(path: string, select?: string, match?: any, options?: any): Query<T, O>;
populate(path: string, select: string, model: string, match?: any, options?: any): Query<T, O>;
populate(opt: PopulateOption): Query<T, O>;
read(pref: string, tags?: any[]): Query<T, O>;
regex(val: RegExp): Query<T, O>;
regex(path: string, val: RegExp): Query<T, O>;
remove(callback?: (err: any, res: T) => void): Query<T, O>;
remove(criteria: any, callback?: (err: any, res: T) => void): Query<T, O>;
select(arg: string): Query<T, O>;
select(arg: any): Query<T, O>;
setOptions(options: any): Query<T, O>;
size(val: number): Query<T, O>;
size(path: string, val: number): Query<T, O>;
skip(val: number): Query<T, O>;
slaveOk(v?: boolean): Query<T, O>;
slice(val: number): Query<T, O>;
slice(val: number[]): Query<T, O>;
slice(path: string, val: number): Query<T, O>;
slice(path: string, val: number[]): Query<T, O>;
snapshot(v?: boolean): Query<T, O>;
sort(arg: any): Query<T, O>;
sort(arg: string): Query<T, O>;
stream(options?: { transform?: Function; }): QueryStream;
tailable(v?: boolean): Query<T, O>;
toConstructor(): Query<T, O>;
update(callback?: (err: any, affectedRows: number, doc: T) => void): Query<T, O>;
update(doc: any, callback?: (err: any, affectedRows: number, doc: T) => void): Query<T, O>;
update(criteria: any, doc: any, callback?: (err: any, affectedRows: number, doc: T) => void): Query<T, O>;
update(criteria: any, doc: any, options: any, callback?: (err: any, affectedRows: number, doc: T) => void): Query<T, O>;
where(path?: string, val?: any): Query<T, O>;
where(path?: any, val?: any): Query<T, O>;
within(val?: any): Query<T, O>;
within(coordinate: number[], ...coordinatePairs: number[][]): Query<T, O>;
$where(argument: string): Query<T, O>;
$where(argument: Function): Query<T, O>;
static use$geoWithin: boolean;
}
export interface QueryCursor<T, O> extends stream.Readable {
/**
* A QueryCursor is a concurrency primitive for processing query results
* one document at a time. A QueryCursor fulfills the Node.js streams3 API,
* in addition to several other mechanisms for loading documents from MongoDB
* one at a time.
* Unless you're an advanced user, do not instantiate this class directly.
* Use Query#cursor() instead.
* @param options query options passed to .find()
* @event cursor Emitted when the cursor is created
* @event error Emitted when an error occurred
* @event data Emitted when the stream is flowing and the next doc is ready
* @event end Emitted when the stream is exhausted
*/
constructor(query: Query<T, O>, options: Object): QueryCursor<T, O>;
/** Marks this cursor as closed. Will stop streaming and subsequent calls to next() will error. */
close(callback?: (error: any, result: any) => void): Promise<any>;
/**
* Execute fn for every document in the cursor. If fn returns a promise,
* will wait for the promise to resolve before iterating on to the next one.
* Returns a promise that resolves when done.
* @param callback executed when all docs have been processed
*/
eachAsync(fn: (doc: T) => any, callback?: (err: any) => void): Promise<T>;
/**
* Get the next document from this cursor. Will return null when there are
* no documents left.
*/
next(callback?: (err: any) => void): Promise<any>;
}
export interface PopulateOption {
path: string;
select?: string;
model?: string;
match?: any;
options?: any;
}
export interface QueryStream extends NodeJS.EventEmitter {
destroy(err?: any): void;
pause(): void;
resume(): void;
pipe<T extends NodeJS.WritableStream>(destination: T, options?: { end?: boolean; }): T;
paused: number;
readable: boolean;
}
export interface Document {
id?: any;
_id?: any;
__v?: number;
equals?(doc: Document): boolean;
get?(path: string, type?: new(...args: any[]) => any): any;
inspect?(options?: any): string;
invalidate?(path: string, errorMsg: string, value: any): void;
invalidate?(path: string, error: Error, value: any): void;
isDirectModified?(path: string): boolean;
isInit?(path: string): boolean;
isModified?(path?: string): boolean;
isSelected?(path: string): boolean;
markModified?(path: string): void;
modifiedPaths?(): string[];
execPopulate?(): Promise<Document>;
populate?<T>(callback?: (err: any, res: T) => void): Document;
populate?<T>(path?: string, callback?: (err: any, res: T) => void): Document;
populate?<T>(opt: PopulateOption, callback?: (err: any, res: T) => void): Document;
populated?(path: string): any;
remove?<T>(callback?: (err: any) => void): Query<T, T>;
save?<T>(callback?: (err: any, res: T) => void): Promise<T>;
set?(path: string, val: any, type?: new(...args: any[]) => any, options?: any): void;
set?(path: string, val: any, options?: any): void;
set?(value: any): void;
toJSON?(options?: any): any;
toObject?(options?: any): any;
toany?(options?: any): any;
toString?(): string;
update?<T>(doc: any, options: any, callback: (err: any, affectedRows: number, raw: any) => void): Query<T, T>;
validate?(cb?: (err: any) => void): Promise<void>;
isNew?: boolean;
errors?: any;
schema?: any;
}
export class Aggregate<T> {
constructor(...options: any[]);
append(...options: any[]): Aggregate<T>;
group(arg: any): Aggregate<T>;
limit(num: number): Aggregate<T>;
match(arg: any): Aggregate<T>;
near(parameters: any): Aggregate<T>;
project(arg: string): Aggregate<T>;
project(arg: any): Aggregate<T>;
select(filter: string): Aggregate<T>;
skip(num: number): Aggregate<T>;
sort(arg: string): Aggregate<T>;
sort(arg: any): Aggregate<T>;
unwind(fiels: string, ...rest: string[]): Aggregate<T>;
exec(callback?: (err: any, result: T) => void): Promise<T>;
read(pref: string, ...tags: any[]): Aggregate<T>;
}
}
// tslint:disable:variable-name
import 'reflect-metadata';
import * as mongoose from 'mongoose';
import MixinPlugin from './MixinPlugin';
import * as _ from 'lodash';
export type IMongooseDocument<T> = T & mongoose.Document;
export type IMongooseModel<TModel, TDoc> = TModel & mongoose.Model<IMongooseDocument<TDoc>>;
/**
* Contains information needed to create a model from a decorated class
*/
export interface IModelInfo {
modelName: string;
debug: boolean;
schemaObj: any;
schema: mongoose.Schema;
children: IMongooseClassMetadataHolder[];
preHooks: { name: string, fn: mongoose.HookCallback }[];
postHooks: { name: string, fn: mongoose.HookCallback }[];
}
interface IMongooseClassMetadataHolder {
_$_mongooseMeta: IModelInfo;
}
// interface IMongooseFields {
// [name: string]: any;
// }
export function ModelFromSchemaDef<TModel, TDocument>(cls:TModel, conn?:mongoose.Connection ) {
conn = conn || mongoose.connection;
let data = getMetadata(cls, true);
if (conn.models[data.modelName]) {
return <IMongooseModel<TModel, TDocument>>conn.model(data.modelName);
}
if (!data || !data.modelName) {
throw new Error("Provided object has not been decorated with @Schema!");
}
// console.log("Creating model:", data.schemaName);
let Model: IMongooseModel<TModel, TDocument> = <any>conn.model(data.modelName, data.schema);
return Model;
}
/**
* Get the schema for a class which has been decorated with @Schema;
* use this if you need functionality not otherwise available to
* your class
*
* @param {@Schema class} obj A class which has been
* @return {mongoose.Schema} The schema which was generated for the class
* using the decorated properties
*/
export function getSchema(obj:any) : mongoose.Schema {
let data = getMetadata(obj, true);
return data && data.schema;
}
/**
* Returns the metadata object with the Schema information
* @param {any} cls The object to get metadata for
* @param {boolean} safe Unless true the metadata and schema will be created for the class if it doesn't exist
* @return {object} The metadata object
*/
function getMetadata(cls:any, safe?: boolean) {
if (!cls) { throw new Error("Cannot getMetadata of null"); }
let obj: IMongooseClassMetadataHolder = cls;
if (!obj._$_mongooseMeta && !safe) {
// console.log("Defining the property");
Object.defineProperty(obj, '_$_mongooseMeta', {
value: <IModelInfo>{
modelName: null,
schema: null,
children: [],
schemaObj: {},
preHooks: [],
postHooks: [],
debug: false
},
writable: false,
enumerable: false,
configurable: false
});
// obj._$_mongooseMeta = {
// schemaName: null,
// schema: new mongoose.Schema(),
// children: []
// };
}
return obj._$_mongooseMeta;
}
/**
* This function will check to see if the provided type is a class which
* has been decorated with @Schema and if so it will return the mongoose
* Schema so that the type works correctly
*
* @param {any} type A type which may or may not be a @Schema-decorated class
*/
function normalizeType(type:any) : any {
if (type instanceof Array) {
// console.log("Array!");
if (type.length != 1) { throw new Error("Invalid type! " + type); }
return [normalizeType(type[0])];
}
if (type == Object) {
// This is what comes from an any type; it maps to mixed
return mongoose.Schema.Types.Mixed;
} else if (type == mongoose.Types.ObjectId) {
// Turns out the actual ObjectID type doesn't work, so we need to map
// to the schematype ObjectId
return mongoose.Schema.ObjectId;
}
let schema = getSchema(type);
return schema || type;
}
/**
* Figures out the name of a class by looking at the .toString()
* @param {any} cls The class to get the name for
* @return {string} The name of the class
*/
function getClassName(cls:any) : string {
let funcNameRegex = /class ([^ {]{1,})/;
let results = (funcNameRegex).exec(cls.toString());
return (results && results.length > 1) ? results[1] : "";
}
/**
* Returns the name of the model from a decorated class. If class name ends
* in 'Schema' the resultant modelName will strip 'Schema' from the derivied
* name, otherwise the class name will be returned.
* @param {any} cls The class to get the name for
* @return {string} The derived modelName
*/
function getModelName(cls: any): string {
let modelName = getClassName(cls);
const suffix = 'Schema';
return modelName.endsWith(suffix) ?
modelName.substr(0, modelName.length - suffix.length) :
modelName;
}
type PluginFunction = (schema: mongoose.Schema, options?: any) => void;
export interface ISchemaPlugin {
plugin: PluginFunction;
options?: any;
}
/**
* The options which can be passed into the @Schema class decorator
*/
export interface ISchemaOptions {
/**
* If provided, this is the name that will be used for the model (if you
* use the createModel method of this library). If not provided, the name
* of the class will be used. Auto-detecting the name may not work well
* in conjunction with other decorators and/or unusually built classes.
*
* @type {string}
*/
name?: string;
/**
* This should be an array of arrays where each array defines an index. The
* format is the same as the format returned by getIndexes on a mongodb model.
* Each entry in the indexes array should be an array with one or two objects;
* the first is the object indicating which fields are in the index, the second
* are the options for the index
* [
* [{field1: 1, field2: 1}, {unique: true}],
* [{field: 1}],
* [{field: 1, field: 2, field: 3}]
* ]
*/
indexes?: any[][];
/**
* Any plugins which you want to run on the model should be added in this
* array.
*
* [
* {plugin: LastModifiedPlugin},
* {plugin: NextModifiedPlugin, options: {index: true}}
* ]
*/
plugins?: ISchemaPlugin[];
/**
* Any options that you want to be passed into the new Schema(name, opts: Options) call
* @type {Schema Options}
*/
schema_options?: any;
debug?: boolean;
}
/**
* Decorates a class to be a Mongoose model/document. When used in conjunction
* with the @Field and @ArrayField decorators this collects the information
* needed to generate a mongoose Schema
*
* @param {ISchemaOptions} opts Options for the schema, including indexes
* @return {ClassDecorator} Returns the decorator which does the work
*/
export function schemaDef<TF extends Function>(target: TF): TF | void;
export function schemaDef(opts?: ISchemaOptions): ClassDecorator;
export function schemaDef(v?: any) : any {
let opts:ISchemaOptions = {};
if (typeof v == 'function') {
return ModelClassDecorator(v);
}
opts = v as ISchemaOptions || {};
function ModelClassDecorator<TF extends Function>(target: TF): TF | void {
// It turns out that this decorator runs only after the entire class has been defined --
// and thus after all the other decorators have run. This makes it easy to convert
// the object we've been building into a schema
let data = getMetadata(target);
data.modelName = opts.name || getModelName(target);
data.debug = !!opts.debug;
if (data.debug) {
console.log("Creating schema: ", data.modelName);
}
data.schema = new mongoose.Schema(data.schemaObj, opts.schema_options);
if (opts.indexes) {
opts.indexes.forEach(i => data.schema.index.apply(data.schema, i));
}
if (opts.plugins) {
opts.plugins.forEach(p => data.schema.plugin(p.plugin, p.options));
}
data.preHooks.forEach (hook => data.schema.pre (hook.name, hook.fn));
data.postHooks.forEach(hook => data.schema.post(hook.name, hook.fn));
MixinPlugin(data.schema, target, data.debug);
return target;
}
return ModelClassDecorator;
}
function getFieldByName(target: any, propertyKey: string, opts: any) {
let data = getMetadata(target.constructor);
let field = data.schemaObj[propertyKey];
if (!field) {
let type = opts.type || Reflect.getMetadata("design:type", target, propertyKey);
type = normalizeType(type);
if (opts.debug) {
console.log(`Trying to link ${propertyKey} type [${type}]`);
}
field = data.schemaObj[propertyKey] = {
type: type
};
}
return field;
}
function getArrayByName(target: any, propertyKey: string, opts: any) {
let data = getMetadata(target.constructor);
let field: any[] = data.schemaObj[propertyKey];
if (!field) {
let type = opts.type || Reflect.getMetadata("design:type", target, propertyKey);
type = normalizeType(type);
if (opts.debug) {
console.log(`Trying to link ${propertyKey} type`);
}
field = data.schemaObj[propertyKey] = [{
type: type
}];
}
return field[0];
}
function setFieldOpts(target: any, propertyKey: string, opts: any) {
let field = getFieldByName(target, propertyKey, opts);
if (opts.type) {
opts.type = normalizeType(opts.type);
}
_.extend(field, opts);
}
function setArrayOpts(target: any, propertyKey: string, opts: any) {
let field = getArrayByName(target, propertyKey, opts);
if (opts.type) {
opts.type = normalizeType(opts.type);
}
_.extend(field, opts);
}
/**
* Use this as a helper to make new field decorators
* @param {any} default_opts [description]
*/
function makeFieldDecorator(default_opts: any) {
function FieldDecorator(opts?: any): PropertyDecorator;
function FieldDecorator(t: any, pKey: string): void;
function FieldDecorator(opts?:any, pKey?: string) : PropertyDecorator | void {
if (pKey) {
let t = opts;
opts = default_opts;
return SchemaFieldDecorator(t, pKey);
} else if (!opts) {
opts = default_opts || {};
}
_.defaults(opts, default_opts);
function SchemaFieldDecorator(target: any, propertyKey: string) : void {
setFieldOpts(target, propertyKey, opts);
}
return SchemaFieldDecorator;
}
return FieldDecorator;
}
/**
* Decorator for class properties which should be mapped to a field on the
* document in the database. Any options provided will be passed in the same
* as options defined on a mongoose schema would be. The name will be the same
* as the name of the property; if type is not specified it will be auto-detected.
* Note that array types cannot be auto-detected, so if you need an array type use
* @ArrayField instead.
*
* @param {any} opts Field options as defined by mongoose
*/
export const field = makeFieldDecorator({});
/**
* Specialization of @Field which marks a field required
*/
export const required = makeFieldDecorator({ required: true });
/**
* Specialization of @Field which marks a field to be an index
*/
export const indexed = makeFieldDecorator({ index: true });
/**
* Specialization of @Field which marks a field to be unique
*/
export const unique = makeFieldDecorator({ unique: true });
/**
* Specialization of @Field which marks a field to be lowercase
*/
export const lower = makeFieldDecorator({ lowercase: true });
/**
* Specialization of @Field which marks a field to be lowercase
*/
export const upper = makeFieldDecorator({ uppercase: true });
/**
* Specialization of @Field for setting a default
*/
export function defaultVal(defaultValue: any, opts?: any) {
opts = opts || {};
_.extend(opts, { default: defaultValue });
return makeFieldDecorator(opts);
}
/**
* Specialization of @Field for specifying a ref (should be used only with ObjectId)
*/
export function ref(ref: string, opts?: any) {
opts = opts || {};
_.extend(opts, { type: mongoose.Schema.ObjectId, ref: ref });
return makeFieldDecorator(opts);
}
/**
* Specialization of @Field for specifying an enum (string fields only)
*/
export function enumVal(enumVal: string[], opts?: any) {
opts = opts || {};
_.extend(opts, { type: String, enum: enumVal });
return makeFieldDecorator(opts);
}
/**
* Specialization of @Field for specifying a maximum length (string fields only)
*/
export function maxLen(len: number, opts?: any) {
opts = opts || {};
_.extend(opts, { type: String, maxlength: len });
return makeFieldDecorator(opts);
}
/**
* Specialization of @Field for specifying a minimum length (string fields only)
*/
export function minLen(len: number, opts?: any) {
opts = opts || {};
_.extend(opts, { type: String, minlength: len });
return makeFieldDecorator(opts);
}
/**
* Specialization of @Field for specifying a field setter
*/
export function setter(fn: (val: any, schema?: mongoose.Schema) => any) {
return makeFieldDecorator({ set: fn });
}
/**
* Specialization of @Field for specifying a field getter
*/
export function getter(fn: () => any) {
return makeFieldDecorator({ set: fn });
}
/**
* Specialization of @Field for specifying a regex match (string fields only)
*/
export function regex(regex: RegExp, opts?: any) {
opts = opts || {};
_.extend(opts, { type: String, match: regex });
return makeFieldDecorator(opts);
}
/**
* Specialization of @Field which marks a field as type: Date (since reflection doesn't work correctly on class properties of type Date)
*/
export const dateField = makeFieldDecorator({ type: Date });
/**
* Use this if you have a field which is a typed array; we can't use reflection
* to detect the array type, so this is needed.
* @param {type} inType The type of the array
* @param {options} opts an object with the Schema Type options for this field, if any
* @return {PropertyDecorator} A decorator which will apply the desired attributes
*/
export function arrayField(inType: any, opts?:any) {
opts = opts || {};
_.extend(opts, { type: [inType] });
return makeFieldDecorator(opts);
}
/**
* Use this if you have a field which is a typed array; we can't use reflection
* to detect the array type, so this is needed.
* @param {type} inType The type of the array
* @param {options} opts an object with the Schema Type options for this field, if any
* @return {PropertyDecorator} A decorator which will apply the desired attributes
*/
export function refArray(ref: string, inType?: any, opts?:any) {
opts = opts || {};
_.extend(opts, { type: inType, ref: ref });
return makeArrayDecorator(opts);
}
/**
* Use this as a helper to make new decorators for array fields with special needs
* currently used just for refArray
* @param {any} default_opts [description]
*/
function makeArrayDecorator(default_opts: any) {
function ArrayFieldDecorator(opts?: any): PropertyDecorator;
function ArrayFieldDecorator(t: any, pKey: string): void;
function ArrayFieldDecorator(opts?:any, pKey?: string) : PropertyDecorator | void {
if (pKey) {
let t = opts;
opts = default_opts;
return SchemaArrayFieldDecorator(t, pKey);
} else if (!opts) {
opts = default_opts || {};
}
_.defaults(opts, default_opts);
function SchemaArrayFieldDecorator(target: any, propertyKey: string) : void {
setArrayOpts(target, propertyKey, opts);
}
return SchemaArrayFieldDecorator;
}
return ArrayFieldDecorator;
}
/**
* Apply to a method with the event string to configure a pre-hook for the desired event
* @param {string} event the name of the event, e.g. 'save'
* @return {MethodDecorator} A decorator which will set up the hook
*/
export function pre(event: string) : MethodDecorator {
function PreDecorator(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<Function>) : TypedPropertyDescriptor<Function> | void {
let data = getMetadata(target.constructor);
data.preHooks.push({ name: event, fn: <any>descriptor.value });
}
return PreDecorator;
}
/**
* Apply to a method with the event string to configure a pre-hook for the desired event
* @param {string} event the name of the event, e.g. 'save'
* @return {MethodDecorator} A decorator which will set up the hook
*/
export function post(event: string) : MethodDecorator {
function PostDecorator(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<Function>) : TypedPropertyDescriptor<Function> | void {
let data = getMetadata(target.constructor);
data.postHooks.push({ name: event, fn: <any>descriptor.value });
}
return PostDecorator;
}
/**
* Apply to a static or method if you don't want it to end up on the runtime object
* (I don't really know why you'd want this, but in case you do...)
*/
export function ignore(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<Function>) : TypedPropertyDescriptor<Function> | void {
Reflect.defineMetadata('schema:ignore', true, target, propertyKey);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment