Mongoose validation error when using custom validator - node.js

Following is the Schema which is not working correctly with custom validator-
var mongoose = require('mongoose');
var userSchema = new mongoose.Schema({
email : { type: String, validate: lengthValidator },
});
// Length validator for email
var lengthValidator = function(val){
if(val && val.length >= 6 )
return true;
return false;
};
var User = mongoose.model('User',userSchema);
module.exports = User;
Error -
Error: Invalid validator. Received (undefined) undefined. See http://mongoosejs.com/docs/api.html#schematype_SchemaType-validate
at SchemaString.SchemaType.validate (/MY_PROJECT_PATH/node_modules/mongoose/lib/schematype.js:416:13)
at SchemaString.SchemaType (/MY_PROJECT_PATH/node_modules/mongoose/lib/schematype.js:38:13)
at new SchemaString (/MY_PROJECT_PATH/node_modules/mongoose/lib/schema/string.js:24:14)
at Function.Schema.interpretAsType (/MY_PROJECT_PATH/node_modules/mongoose/lib/schema.js:367:10)
at Schema.path (/MY_PROJECT_PATH/node_modules/mongoose/lib/schema.js:305:29)
at Schema.add (/MY_PROJECT_PATH/node_modules/mongoose/lib/schema.js:217:12)
at new Schema (/MY_PROJECT_PATH/node_modules/mongoose/lib/schema.js:73:10)
at Object.<anonymous> (/MY_PROJECT_PATH/models/users.js:2:18)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
However if I remove validate then it is working correctly as I checked by changing the type from String to Number.
Let me know what i am doing wrong?

The issue you're experiencing is related to hoisting. The way that you've written your validation function means that at the time you're passing it into the schema it's an undefined value; it's not until afterwards that the variable gets set.
Here's a really basic example of the problem.
var thing = {
foo: bar
}
var bar = function () {
alert('hello!');
}
thing.foo();
When thing.foo() is called, it will throw an error. Why? Because this is how JavaScript interprets what I wrote:
var bar;
var thing = {
foo: bar // At this point, bar is undefined
}
bar = function () {
alert('hello!');
}
thing.foo();
The same thing is happening to your code. When you set the validate property in the schema to lengthValidate, it hasn't been defined yet.
There's two ways to fix it.
Move the validation function definition above the schema definition in the code.
Use function lengthValidator(val) instead of var lengthValidator = function(val)

Related

Node require - i don't understand this code

I'm starting to learn node.js and mongoose and I do not understand the following code.
I have 2 files: app.js and idea.js
app.js
const mongoose = require('mongoose')
require('./models/Idea')
const Idea = mongoose.model('ideas')
idea.js
const mongoose1 = require('mongoose')
const Schema = mongoose1.Schema
const IdeaSchema = new Schema(
{
title: { type:String, required:true},
details: {type:String, required:true},
date: {type:Date, default:Date.now()}
}
)
mongoose1.model('ideas', IdeaSchema)
When I run app.js, no error occurs. How is it possible? I did not export anything from the idea.js file!
How did the app.js file get access to the ideas model?
require is cached. So, this:
let obj1 = require('an_object');
let obj2 = require('an_object');
will load the object in the first line, and return that same object from cache in the second line. This holds even if the two requires are in different files. Since obj1 and obj2 are references to the same object, if obj1 gets modified, obj2 also gets modified (because they're one and the same).
You did not export anything from Idea, but it doesn't matter; the purpose of Idea was to modify the mongoose object, not to return anything.
Simplified:
// storage.js
exports.hello = 'Mumble mumble';
// mod_storage.js
let modding_storage = require('./storage');
modding_storage.hello = "Hello, world!";
// main.js
let main_storage = require('./storage');
require('./mod_storage');
console.log(main_storage.hello);
// => Hello, world!
mod_storage changed modding_storage, but modding_storage is the same object as main_storage; change one, both change.

SINON unittesting stub constructor

I'm trying to stub a constructor in node but I really can't.
I found this , that is quite similiar to what I need to do but I have an error that I could not solve.
//file.js
var foo = require('foo-client')
function toTest () {
var bar = foo()
returns config = bar.foo2(a,b) // returns a Promise
}
what I am trying to do in the test file is
//file-sepc.js
var stub = sinon.stub()
stub.returns(Promise.resolve('config'))// config it's just an example
var file = proxyquire('./file.js', {
'foo-client':{foo2: stub}
})
file.toTest()
.then((result) => {
console.log(result)
done()
})
supposing the node syntax is correct, I am getting this output:
TypeError: foo is not a function
Can anyone help me telling me where is my error or another way to mock/stub this things?
Thanks a lot!
Haven't tried running your code but it looks like foo-client should be a function rather than an object in order for the var bar = foo() not to throw an error you are seeing. Try the following:
var file = proxyquire('./file.js', {'foo-client': sinon.stub.returns({ foo2: stub }) })

Getting instance of node module while test driving codeal

I am creating a factory method where i am returning an instance of a node module
var dal1 = require('../dal/dal1');
var dal2 = require('../dal/dal2');
exports.createDAL(role){
switch(role){
case "XYZ": return dal1;
case "ABC": return dal2
}
};
Using Mocha as the TDD frame work, When I get the object returned,I get the value of returnObject.constructor.name as object instead of dal1 or dal2. Any pointers?
So I went ahead with using the node-module 'util'. I was able to get the expected value instead of just 'Object'
I created a DAL object
//dal.js
function dal(){
}
dal.prototype.BLAH = function(){
//logic here
}
module.exports = dal
//dal1.js
var inherits = require('util').inherits;
function dal1(){
dal1.call(this);
}
inherits(dal1,dal);
module.exports = dal1;
//similarly dal2.js
//finally in factory
var dal1 = require('./dal1');
var dal2 = require('./dal2');
switch(role){
case 'XYZ': return new dal1();
case 'ABC' : return new dal2();
}

require module does not respond object as singleton pattern in some cases

file_a.js is dependency of file_b.js and file_c.js. Please take a look in file_c.js, there is weird thing there.
file_a.js
module.exports = {
test: null,
setTest: function(a){
this.test = a;
},
getTest: function(){
return this.test
},
}
file_b.js
var a = require('./file_a')
var b = {
print: function(someVar){
console.log(someVar);
}
}
a.setTest(b)
file_c.js
this way will work
var a = require('./file_a')
console.log(typeof a.getTest().print) //function
this way will NOT work
var a = require('./file_a').getTest()
console.log(typeof a.print) //Cannot read property 'print' of null
Both of your examples for file_c.js throw TypeError: Cannot read property 'print' of null.
Module from file_b.js sets test property from module file_a.js on its initialization, and in your snippets it never gets initialized. To fix this, you need:
var a = require('./file_a');
require('./file_b'); // now `test` is set
console.log(typeof a.getTest().print); // function
or
require('./file_b'); // module from `file_a` loaded to cache and `test` is set
var a = require('./file_a').getTest();
console.log(typeof a.print); // function

Unexpected value for 'this' in express.js instantiated controllers

'this' does not appear to refer to the instantiated budget controller object. Instead it seems to refer to the global object. Does anyone know why this is?
I've defined a budget model. Injected into the controller and I'm attempting to simply generate a random 6 char string when I hit /budgets in my app. Instead this.DEFAULT_SLUG_LENGTH is undefined and I can't figure out why.
This is a dumbed down test case illustrating the issue with 'this'. I have a similar problem when referencing the injected this.budget within another function to query the db based on the slug value.
//models/budget.js
var Schema = require('jugglingdb').Schema;
var schema = new Schema('postgres',{url:process.env.DATABASE_URL});
var Budget = schema.define('budgets',{
total: Number,
slug: String
});
module.exports = Budget;
====================
//controllers/budget.js
function BudgetController (budget) {
this.budget = budget;
};
BudgetController.prototype.DEFAULT_SLUG_LENGTH = 6;
BudgetController.prototype.generateSlug = function (req,res) {
var slug = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (var i = 0; i < this.DEFAULT_SLUG_LENGTH; i++) {
slug += possible.charAt(Math.floor(Math.random() * possible.length));
}
res.send(slug);
};
module.exports = BudgetController;
===================
//app.js
var express = require('express');
var app = express();
app.use(express.bodyParser());
// models
var Budget = require('./models/budget');
// controllers
var BudgetController = require('./controllers/budget');
var budgetCtrl = new BudgetController(Budget);
// routes
app.get('/budgets',budgetCtrl.generateSlug);
app.listen(process.env.PORT || 4730);
If I manually instantiate the model/controller in the node repl, the generateSlug method works fine. If I restructure my code so that the BudgetController is a function that returns an object {} with methods, that seems to work fine. Is there some issue with my use of prototype/new ?
express takes functions and invokes them without a preceding object, so if you want to use an object method bound to a specific this as an express route handler function, you need to bind it:
app.get('/budgets', budgetCtrl.generateSlug.bind(budgetCtrl));

Resources