Skip to content

Instantly share code, notes, and snippets.

@masahirompp
Last active May 5, 2021 20:04
Show Gist options
  • Star 31 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save masahirompp/3c012c8721b70821fa45 to your computer and use it in GitHub Desktop.
Save masahirompp/3c012c8721b70821fa45 to your computer and use it in GitHub Desktop.
mongoose + typescript
/// <reference path="../tsd/tsd.d.ts" />
import mongoose = require('mongoose');
import passport = require('passport');
interface IUser extends mongoose.Document {
provider: string;
id: string;
authorId: string;
displayName: string;
emails: any;
photos: any;
show: boolean;
created: Date;
updated: Date;
}
/**
* MongooseSchema
* @type {"mongoose".Schema}
* @private
*/
var _schema: mongoose.Schema = new mongoose.Schema({
provider: {
type: String,
require: true
},
id: {
type: String,
require: true
},
authorId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Author'
},
displayName: {
type: String
},
emails: {
type: mongoose.Schema.Types.Mixed
},
photos: {
type: mongoose.Schema.Types.Mixed
},
show: Boolean,
created: {
type: Date,
default: Date.now
},
updated: {
type: Date,
default: Date.now
}
})
.pre('save', function(next) {
this.updated = new Date();
next();
});
/**
* Mongoose.Model
* @type {Model<IUser>}
* @private
*/
var _model = mongoose.model < IUser > ('User', _schema);
class User {
/**
* static ユーザが存在しなければ作成して返す。
* @param passport.Profile
* @returns {Promise<User>}
*/
static findOrCreate(profile: passport.Profile): Promise < User > {
return new Promise < IUser > ((resolve, reject) => {
_model.findOne({
provider: profile.provider,
id: profile.id
})
.exec()
.then(user => {
if (user) {
return resolve(new User(user));
}
_model.create({
provider: profile.provider,
id: profile.id,
displayName: profile.displayName,
emails: profile.emails,
photos: profile.photos
})
.onResolve((err, user) => {
err ? reject(err) : resolve(new User(user));
});
});
});
}
/**
* static idからUserオブジェクトを取得
* @param id
* @returns {Promise<User>}
*/
static findById(id: string): Promise < User > {
return new Promise < IUser > ((resolve, reject) => {
_model.findById(id)
.exec()
.onResolve((err, user) => {
err ? reject(err) : resolve(new User(user));
});
})
}
/**
* インスタンス変数
*/
private _document: IUser;
/**
* コンストラクタ
* @param mongoose.Document<IUser>
*/
constructor(document: IUser) {
this._document = document;
}
get provider(): string {
return this._document.provider;
}
get image(): string {
if (Array.isArray(this._document.photos)) {
return this._document.photos.length > 0 ? this._document.photos[0] : null;
}
return this._document.photos;
}
get show(): boolean {
return this._document.show;
}
get authorId(): string {
return this._document.authorId;
}
}
export = User;
@DNRN
Copy link

DNRN commented Mar 25, 2016

First I like your model, but I have a question. How would you implement methods on the schema?
I have have a validate password method:

.method("validPassword", (password) => {
  var member = this;
  return bcrypt.compareSync(password, member.password);
});

Do you know how I could call this from a static validatePassword(password: string) on the class object? The problem is TypeScript is not aware of this "validatePassword" method?
Or is the easiest way to collect it all in one function:

static validPassword(email: string, password: string): Promise<IMember> {
    return new Promise<IMember> ((resolve, reject) => {
      _model.findOne({email: email}, (err, member) => {
        if (err) reject (err);
        if (!member) resolve(null);
        bcrypt.compareSync(password, member.password) ? resolve(member) : resolve(null);
      });
    });
  }

@chrismatix
Copy link

@DNRN Yeah, I have been thinking the same thing, because this snippet sort of makes the mongoose methods and statics obsolete, right?

@vanor89
Copy link

vanor89 commented Jun 12, 2016

_schema.methods.methodName = function (*) {
your code
}

Would not work?

@ollyde
Copy link

ollyde commented Jul 23, 2016

Compiling gives me this

src/models/UserModel.ts(4,41): error TS2339: Property 'Document' does not exist on type 'typeof 'mongoose''.
src/models/UserModel.ts(65,37): error TS2344: Type 'UserModel' does not satisfy the constraint 'Document'.

@manuelxaguilar
Copy link

@DNRN & @xChrisPx, did you guys make this work? I'm having the exact same problem with a password comparisson method. "Property 'compare' does not exist on type 'IUser[]'."

@Eronmmer
Copy link

Hi, has anybody found a solution to this password comparison method? I'm stuck with the same problem.

@fcastrocs
Copy link

fcastrocs commented Feb 24, 2021

Thank you for the sample code. I would like to extend on your solution.

If you extend your User class to _model, it would give you access to all default model functions such as findById, findOne, etc.

Lines 65 and 67
var _model = mongoose.model < IUser > ('User', _schema);
class User <-------------- change this to class User extends _model

and now you can reference 'this' instead of using _model, and you would have all the features in model in your User class.

Thank you, this code helped me a lot.

Edit: just make sure all your static methods names don't try to override the default model methods or you will get a weird large error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment