Add methods to execute before "save", "delete", "findOne" or your customMethod. The middleware that you declare receives the original argument(s) passed to the method. You can modify them in your resolve passing an object with an __override property containing the new parameter(s) for the target method (be careful though... with great power comes great responsibility!). See example below.
If you reject the Promise in a "pre" middleware, the target function is not executed.
Example
Hook to hash a user's password before saving it into the Datastore.
constgstore=require('gstore-node')();constbscrypt=require('bcrypt-nodejs');constuserSchema=newgstore.Schema({ user: { type: String }, email: { type: String, validate:'isEmail' }, password: { type: String, excludeFromIndexes:true }});// Hash password middlewarefunctionhashPassword() {// scope *this* is the entity instanceconst_this=this;constpassword=this.password;if (!password) {// nothing to hash... exitreturnPromise.resolve(); }returnnewPromise((resolve, reject) => {bcrypt.genSalt(5,functiononSalt(err, salt) {if (err) {returnreject(err); };bcrypt.hash(password, salt,null,functiononHash(err, hash) {if (err) {// reject will *not* save the entityreturnreject(err); };_this.password = hash;// resolve to go to next middleware or target methodreturnresolve(); }); }); });}// add the "pre" middleware to the save methoduserSchema.pre('save', hashPassword);...// Then when you create a new user and save it (or when updating it)// the password will automatically be hashedconstUser=require('./user.model');constuser=newUser({ username:'john', password:'mypassword' });user.save().then((response) => {constentity= response[0];console.log(entity.password);// $7b$01$GE/7OqVnMyThnaGC3QfEwuQ1imjifli3MvjcP7UGFHAe2AuGzne5.});
Note
The pre('delete') hook has its scope set on the entity to be deleted. Except when an Array of ids to delete is passed.
blogSchema.pre('delete',function() {console.log(this.entityKey); // the datastore entity key to be deleted// Access arguments passedconstargs=Array.prototype.slice(arguments);console.log(args[0]); // 1234 (from call below)// By default the entity data is not present because// the entity is *not* fetched from the Datastore.// Though you can call "this.datastoreEntity()" here (see the "Entity" section)// to fetch the data from the Datastore and process any other logic// before resolving the middleware// example 1:returnthis.datastoreEntity() // fetch the entity data from the Datastore.then((entity) => {// entity is a gstore entity instance// You could delete an associated uploaded image for ex.returnmyImageHelper.deleteImage(entity.imageIdx).then(() =>Promise.resolve()); // always resolve empty unless... });// example 2:// ... if you want to override the original argument passed resolve passing a value.// Here you would override the id to delete! At your own risk...returnPromise.resolve({ __override:1235 });});BlogPost.delete(1234).then(() => {...});
You can also pass an Array of middlewares to execute
functionmiddleware1() {// Return a PromisereturnPromise.resolve();}functionmiddleware2() {returnPromise.resolve();}userSchema.pre('save', [middleware1, middleware2]);
Dataloader instance
In case you provided a Dataloader instance to a Model.update() call, it will be added to the entity being saved. This means that it is accessible from inside your "pre" save hooks.
functionmyPreSaveMiddleware() {// fetch the BlogPost author detail with the "entity.model()" methodreturnthis.model('User').get(this.author,null,null,null, { dataloader:this.dataloader }).then((user) => {this.authorDetails = user; });}
Override parameters
In the rare cases (maybe during a migration of data) where you'd need to override the parameters in a "pre" hook, you can resolve your middleware with an object containing an __overrideproperty.
constuserSchema=newgstore.Schema({ user: { type:'string' }, email: { type:'string', validate:'isEmail' }, password: { type:'string', excludeFromIndexes:true }});userSchema.pre('findOne', (...args) => {if (args[0].email ==='john@snow.com') {returnPromise.resolve({ __override: [ args[0],// we keep the original props|values passed ['Dad','Targaryen'] // we add an Ancestor to the Query for this user ]}); }returnPromise.resolve();});// ...// Whenever you will search for this user,// the Query will occur on the Ancestor ['Dad', 'Targaryen'];User.findOne({ email:'john@snow.com' }).then((user) => { ... })