Customizing sequelize validation errors - javascript

I've been using sequelize#3.4.1 for a while and now I need to update sequelize to the latest stable version (3.28.0)
TL;DR: How can I change validation error's structure other than manipulating the 'msg' attribute in the model definition?
The thing is, I use custom validation messages in all of my models, for example:
var Entity = sequelize.define("Entity", {
id: {
type: DataTypes.INTEGER.UNSIGNED,
allowNull: false,
primaryKey: true,
autoIncrement: true,
validate: {
isInt: {
msg: errorMessages.isInt()
}
}
},
name: {
type: DataTypes.STRING(128),
allowNull: false,
unique: {
name: "uniqueNamePerAccount",
args: [["Name", "Account ID"]],
msg: errorMessages.unique()
},
validate: {
notEmpty: {
msg: errorMessages.notEmpty()
}
}
},
accountId: {
type: DataTypes.INTEGER.UNSIGNED,
allowNull: false,
unique: {
name: "uniqueNamePerAccount",
args: [["Name", "Account ID"]],
msg: errorMessages.unique()
},
validate: {
isInt: {
msg: errorMessages.isInt()
}
}
}
}
Until sequelize#3.4.1 I used to add my own attributes to the validation error, so in fact the messages were objects that contains the message and other attributes like inner error code.
Here's an example of the messages:
function notEmpty() {
return {
innercode: innerErrorCodes.notEmpty,
data: {},
message: "cannot be empty"
};
}
function unique() {
return {
innercode: innerErrorCodes.unique,
data: {},
message: util.format("There is already an item that contains the exact same values of the following keys")
};
}
In fact, This how the Entity used to look like:
{"name":"SequelizeValidationError",
"message":"Validation error: cannot be empty",
"errors":[{"message":"cannot be empty",
"type":"Validation error",
"path":"name",
"value":{"innercode":704,
"data":{},
"message":"cannot be empty"},
"__raw":{"innercode":704,
"data":{},
"message":"cannot be empty"}}]}
So basically sequelize found my 'msg' attribute and appended it into the value of the error.
But now, in the latest version, It looks like sequelize throwing new Error(): (instance-validator.js line:268)
throw new Error(test.msg || 'Validation ' + validatorType + ' failed');
Instead of the error that was thrown in 3.4.1 version:
throw test.msg || 'Validation ' + validatorType + ' failed';
Because of that, the error object I set as a custom message is shown as 'Object object' (most probably after toString())
My question is: How can I influence the error's structure and add more attributes other than message?
P.s:
I have problems with the unique constraint custom message too, It's different because it's not considered as a validator.
How can I influence the unique constraint error structure?
Thank you very much!

Related

Can't update(nor save) existing row using Sequelize

When trying to .update() or .save() a row I'm getting this error:
Unhandled rejection Error: You attempted to save an instance with no primary key,
this is not allowed since it would result in a global update
I tried all 4 ways the docs uses as examples(with and without defining the attributes I wanna save), nothing worked.
This is my actual code for updating:
Sydney.databases.guilds.findOrCreate({
attributes: ['guildLocale'],
where: {
guildID: _guild.id,
},
defaults: {
guildID: _guild.id,
guildLocale: 'en_US',
guildPrefix: '?',
},
}).spread((guild, created) => {
guild.update({guildLocale: args[1]})
.then(() => console.log(7))
.catch((e) => throw e);
});
And this is the guild model:
let model = sequelize.define('guild', {
guildID: {
field: 'guild_id',
type: DataTypes.STRING,
primaryKey: true,
},
guildLocale: {
field: 'guild_locale',
type: DataTypes.STRING,
},
guildPrefix: {
field: 'guild_prefix',
type: DataTypes.STRING,
},
}, {tableName: 'guilds'});
What am I missing here?
I had the same problem. It occurs when you specify the attributes you want to fetch from the database without including the primary key in the attributes. And when you attempt to save, it will throw the following error:
Unhandled rejection Error: You attempted to save an instance with no primary key, this is not allowed since it would result in a global update
So the simple solution is to include the primary key in the attributes like this:
Sydney.databases.guilds.findOrCreate({
attributes: ['guildLocale', 'guildID'], // include guideID here!!
where: {
guildID: _guild.id,
},
defaults: {
guildID: _guild.id,
guildLocale: 'en_US',
guildPrefix: '?',
},
}).spread((guild, created) => {
guild.update({guildLocale: args[1]})
.then(() => console.log(7))
.catch((e) => throw e);
});
Ok, so the problem seems that was the attributes: ['guildLocale'] in the .findOrCreate() method. I can't tell why, to be honest, gonna read that doc again to be sure, but I'll leave this answer if another newbie is getting trouble with this, ;P...

insert failed: Error: Title is required

I'm trying to add an object to an object array that is a key in a collection entry with the following code, but I'm getting a weird response "insert failed: Error: Title is required". I'm using simple schema/autoform on meteor.
Has anyone encountered this before (and have a solution)?
Template.dashboard.events({
'click .requestinvite'(e,t) {
Posts.insert({ _id : $(e.currentTarget).attr('_id')},
{$push: { invitesRequested : {username : Meteor.userId()} }}
);
}
});
Here is the relevant Simple Schema in coffeescript
Schemas.Posts = new SimpleSchema
title:
type:String
max: 60
optional: true
content:
type: String
optional: false
autoform:
rows: 5
createdAt:
type: Date
autoValue: ->
if this.isInsert
new Date()
updatedAt:
type:Date
optional:true
autoValue: ->
if this.isUpdate
new Date()
invitesRequested:
type: [Object]
optional: true
defaultValue: []
owner:
type: String
regEx: SimpleSchema.RegEx.Id
autoValue: ->
if this.isInsert
Meteor.userId()
autoform:
options: ->
_.map Meteor.users.find().fetch(), (user)->
label: user.emails[0].address
value: user._id
First of all as per proper javascript assignment standards, you are doing blunder in your code.
What if your code is hacked and the click event is called without any id assigned?
Your code must be as follows.
Template.dashboard.events({
'click .requestinvite'(e,t) {
var id = $(e.currentTarget).attr('_id');
if(id){
Posts.insert(
{
_id : id
},
{
$push: {
invitesRequested : {username : Meteor.userId()}
}
}
);
} else {
//do something here when you don't have id here, or the `click` event is hacked on UI to work without id'
}
}
});
Since your SimpleSchema is giving error regarding title field, if it is not mandatory, then kindly use optional : true at the point of defining title field.
e.g.
title: {
type: String,
label: "Title",
optional: true //<---- do this
}
NOTE: By default, all keys are required. Set optional: true to change that.
The answer was using Posts.update instead. But Ankur Soni's post lead me in the right direction to troubleshoot this down.

How to print data, retrieved from mongoDB database in Node.js?

I'm working on a online shop project. I'm using Node.js, express.js and MongoDB with mongoose. I got the product information from the MongoDB database and sending them to the client side. In my case, I can get all these data in my client side but before sending, when I print them to the console in server side, it says undefined.
This is the products schema:
var schema = new Schema({
imagePath: {
type: String,
required: true
},
productName: {
type: String,
required: true
},
productPrice: {
type: Number,
required: true
},
productCategory: {
type: String,
required: true
},
productShortInformation: {
type: String,
required: true
},
productFullInformation: {
type: String,
required: true
},
productViews: {
type: Number,
required: false
},
productStock: {
type: Number,
required: true
}
});
and here is my Node.js code
router.get('/category/summary', function(req, res, next) {
//getting my all products information
var products = Product.find(function (err, docs) {
if(err) {
console.log('Error Happened' + err);
return res.redirect('/');
} else {
//HERE IS THE PROBLEM
//ALL PRODUCT NAME IS SHOWN UNDEFINED
//BUT WHEN I SEND THEM TO THE CLIENT, I GET PRODUCT NAME
for(var product in docs) {
console.log('Name: ' + product.productName);
}
res.render('shop/categorySummary', {
products: docs //sending these information to the client side
});
}
});
});
When I try to print these product name, I get undefined. But in the client side I can print the product information.
I need to manipulate these data before sending them to the client side. So how can I print these product information to the server side(in console) before sending?
for(var product in docs) {
console.log('Name: ' + docs[product].productName);
}
That should work

meteor autoform custom validation not reactive

I'm trying to use a custom validation function for a field defined in a simpleSchema, however the error message does not render on the field.
num: {
type: Number,
label: "Number",
min: 1,
decimal: false, // unnecessary as this is default for Number, but for future reference
autoform: {
group: "Info",
defaultValue: function() {
//#TODO - default to next number for logged in user
return 5;
}
},
custom: function () {
Collection.simpleSchema().namedContext("addNumberForm").addInvalidKeys([{name: "num", type: "numNotUnique"}]);
}
},
I've defined a custom error message for it
SimpleSchema.messages({numNotUnique: "This number has already been entered"});
When I submit the form I can confirm that the custom function executes, but nothing changes in the UI for that field indicating the error. The context name "addNumberForm" I got from the SimpleSchema.debug = true; setting and seeing what was thrown for other fields with default validation.
What am I missing here?
After much trial and error I've figured it out.
The simpleSchema named context is only necessary if manually validating using simpleSchema by itself. Autoform takes care of this, and the custom function can return a simple string that defines the error.
num: {
type: Number,
label: "Number",
min: 1,
decimal: false, // unnecessary as this is default for Number, but for future reference
autoform: {
group: "Info",
defaultValue: function() {
//#TODO - default to next number for logged in user
return 5;
}
},
custom: function () {
// some check
return 'numNotUnique'; // return our error
}
},

Waterline queries similar to HQL

I have models in Sails as follows:
User Model
attributes: {
firstName: {
type: 'string',
required: true
},
lastName: {
type: 'string',
required: true
},
company: {
model: 'Company'
}
}
Company
name: {
type: 'string',
required: true,
unique: true
},
description: {
type: 'string',
required: true
}
In HQL queries, for getting a user working in a specific company, we use something like this:
Select * from User where company.name=?
How can I achieve same in Sails, Right now there are two queries which I am running, one to get User and then another to get company for that user. Is there any way both can be combined in one?
and one more thing, how does waterline deal with scenarios where in we need to get something out of a foreign key directly i.e. If I get user data, then can I get company details by just calling:
User.findOne({id:1}, function(err, res){
//Res contains user data with just companyId now,
//how can i get whole company object here
var companyName = res.company.name; //This is not working currently
})
Try something like this:
User.findOne({id: 1})
.populate('company')
.exec(function(err, user) {
if(err){
//handle errors
}else{
//do stuff
}
});
This should get the values from the association (foreign key).

Categories

Resources