-
-
Save brennanMKE/ee8ea002d305d4539ef6 to your computer and use it in GitHub Desktop.
import * as mongoose from 'mongoose'; | |
export let Schema = mongoose.Schema; | |
export let ObjectId = mongoose.Schema.Types.ObjectId; | |
export let Mixed = mongoose.Schema.Types.Mixed; | |
export interface IHeroModel extends mongoose.Document { | |
name: string; | |
power: string; | |
amountPeopleSaved: number; | |
createdAt: Date; | |
modifiedAt: Date; | |
} | |
let schema = new Schema({ | |
name: { | |
type: String, | |
required: true | |
}, | |
power: { | |
type: String, | |
required: true | |
}, | |
amountPeopleSaved: { | |
type: Number, | |
required: false | |
}, | |
createdAt: { | |
type: Date, | |
required: false | |
}, | |
modifiedAt: { | |
type: Date, | |
required: false | |
} | |
}).pre('save', function(next) { | |
if (this._doc) { | |
let doc = <IHeroModel>this._doc; | |
let now = new Date(); | |
if (!doc.createdAt) { | |
doc.createdAt = now; | |
} | |
doc.modifiedAt = now; | |
} | |
next(); | |
return this; | |
}); | |
export let HeroSchema = mongoose.model<IHeroModel>('hero', schema, 'heroes', true); | |
export class HeroModel { | |
private _heroModel: IHeroModel; | |
constructor(heroModel: IHeroModel) { | |
this._heroModel = heroModel; | |
} | |
get name(): string { | |
return this._heroModel.name; | |
} | |
get power(): string { | |
return this._heroModel.power; | |
} | |
get amountPeopleSaved(): number { | |
return this._heroModel.amountPeopleSaved; | |
} | |
static createHero(name: string, power: string) : Promise.IThenable<IHeroModel> { | |
let p = new Promise((resolve, reject) => { | |
let repo = new HeroRepository(); | |
let hero = <IHeroModel>{ | |
name: name, | |
power: power, | |
amountPeopleSaved: 0 | |
}; | |
repo.create(hero, (err, res) => { | |
if (err) { | |
reject(err); | |
} | |
else { | |
resolve(res); | |
} | |
}); | |
}); | |
return p; | |
} | |
static findHero(name: string) : Promise.IThenable<IHeroModel> { | |
let p = new Promise((resolve, reject) => { | |
let repo = new HeroRepository(); | |
repo.find({ name : name }).sort({ createdAt: -1 }).limit(1).exec((err, res) => { | |
if (err) { | |
reject(err); | |
} | |
else { | |
if (res.length) { | |
resolve(res[0]); | |
} | |
else { | |
resolve(null); | |
} | |
} | |
}); | |
}); | |
return p; | |
} | |
} | |
Object.seal(HeroModel); | |
export interface IRead<T> { | |
retrieve: (callback: (error: any, result: any) => void) => void; | |
findById: (id: string, callback: (error: any, result: T) => void) => void; | |
findOne(cond?: Object, callback?: (err: any, res: T) => void): mongoose.Query<T>; | |
find(cond: Object, fields: Object, options: Object, callback?: (err: any, res: T[]) => void): mongoose.Query<T[]>; | |
} | |
export interface IWrite<T> { | |
create: (item: T, callback: (error: any, result: any) => void) => void; | |
update: (_id: mongoose.Types.ObjectId, item: T, callback: (error: any, result: any) => void) => void; | |
delete: (_id: string, callback: (error: any, result: any) => void) => void; | |
} | |
export class RepositoryBase<T extends mongoose.Document> implements IRead<T>, IWrite<T> { | |
private _model: mongoose.Model<mongoose.Document>; | |
constructor(schemaModel: mongoose.Model<mongoose.Document>) { | |
this._model = schemaModel; | |
} | |
create(item: T, callback: (error: any, result: T) => void) { | |
this._model.create(item, callback); | |
} | |
retrieve(callback: (error: any, result: T) => void) { | |
this._model.find({}, callback); | |
} | |
update(_id: mongoose.Types.ObjectId, item: T, callback: (error: any, result: any) => void) { | |
this._model.update({ _id: _id }, item, callback); | |
} | |
delete(_id: string, callback: (error: any, result: any) => void) { | |
this._model.remove({ _id: this.toObjectId(_id) }, (err) => callback(err, null)); | |
} | |
findById(_id: string, callback: (error: any, result: T) => void) { | |
this._model.findById(_id, callback); | |
} | |
findOne(cond?: Object, callback?: (err: any, res: T) => void): mongoose.Query<T> { | |
return this._model.findOne(cond, callback); | |
} | |
find(cond?: Object, fields?: Object, options?: Object, callback?: (err: any, res: T[]) => void): mongoose.Query<T[]> { | |
return this._model.find(cond, options, callback); | |
} | |
private toObjectId(_id: string): mongoose.Types.ObjectId { | |
return mongoose.Types.ObjectId.createFromHexString(_id); | |
} | |
} | |
export class HeroRepository extends RepositoryBase<IHeroModel> { | |
constructor() { | |
super(HeroSchema); | |
} | |
} | |
Object.seal(HeroRepository); | |
let uri = 'mongodb://localhost/heroes'; | |
mongoose.connect(uri, (err) => { | |
if (err) { | |
console.log(err.message); | |
console.log(err); | |
} | |
else { | |
console.log('Connected to MongoDb'); | |
} | |
}); | |
HeroModel.createHero('Steve', 'Flying').then((res) => { | |
console.log('### Created Hero ###'); | |
console.log(res); | |
HeroModel.findHero('Steve').then((res) => { | |
console.log('### Found Hero ###'); | |
console.log(res); | |
// now update the Hero | |
let hero = <IHeroModel>res; | |
hero.power = 'Invisibility'; | |
hero.save((err, res) => { | |
if (err) { | |
console.log(err.message); | |
console.log(err); | |
} | |
else { | |
console.log(res); | |
} | |
}); | |
}, (err) => { | |
if (err) { | |
console.log(err.message); | |
} | |
}); | |
}, (err) => { | |
if (err) { | |
console.log(err.message); | |
console.log(err); | |
} | |
}); |
@stevethibault try to use Promise<T>, instead of IThenable<T>.
Also take a look at the typescript code guidelines -> https://github.com/Microsoft/TypeScript/wiki/Coding-guidelines
e.g. Names -> Do not use "I" as a prefix for interface names.
I can't see what's the intention of that code inside of pre('save', ...
- where is that _doc
used actually?
Updated working version for pre
:
}).pre< IHeroModel>('save', function (next) {
if (this.isNew) {
this.createdAt = new Date();
} else {
this.modifiedAt = new Date();
}
next();
});
I got error like this at 165, 169 :
Type 'DocumentQuery<Document, Document, {}>' is not assignable to type 'Query'.
Types of property 'exec' are incompatible.
Type '{ (callback?: (err: NativeError, res: Document) => void): Promise; (operation: string | Function, callback?: (err: any, res: Document) => void): Promise; }' is not assignable to type '{ (callback?: (err: NativeError, res: T) => void): Promise; (operation: string | Function, callback?: (err: any, res: T) => void): Promise; }'.
Types of parameters 'callback' and 'callback' are incompatible.
Types of parameters 'res' and 'res' are incompatible.
Type 'Document' is not assignable to type 'T'.
'Document' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Document'.ts(2322)
Is anyone have resolved it?
I have been constantly receiving the issue mentioned above, seems like a versioning problem
This is super useful thanks for sharing!
I got error like this at 165, 169 :
Type 'DocumentQuery<Document, Document, {}>' is not assignable to type 'Query'.
Types of property 'exec' are incompatible.
Type '{ (callback?: (err: NativeError, res: Document) => void): Promise; (operation: string | Function, callback?: (err: any, res: Document) => void): Promise; }' is not assignable to type '{ (callback?: (err: NativeError, res: T) => void): Promise; (operation: string | Function, callback?: (err: any, res: T) => void): Promise; }'.
Types of parameters 'callback' and 'callback' are incompatible.
Types of parameters 'res' and 'res' are incompatible.
Type 'Document' is not assignable to type 'T'.
'Document' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Document'.ts(2322)Is anyone have resolved it?
Hello. I fixed it by changing types using original *.ts file for mongoose. By opening the file node_modules/@types/mongoose/index.d.ts
you can see all the required types, in the future this will help you find a solution when changing mongoose versions.
findOne(cond?: Object, callback?: (err: any, res: T) => void): mongoose.Query<T> { return this._model.findOne(cond, callback); }
To
findOne(conditions?: any, callback?: (err: any, res: mongoose.Model<T> | null) => void): mongoose.DocumentQuery<T | null, T>;
You can find more examples here: https://github.com/Britskiy/BasicAppArchitecture
I've updated the dependencies and added some functionality.
For anyone stumbling on this gist, be aware that Mongoose team discourages to extend your interfaces from Mongoose.Document :
https://mongoosejs.com/docs/typescript.html#using-extends-document
Can't find IThenable Where does this type come from?