Creating custom attributes in Sailsjs - sails.js

I am trying to create a custom attribute in my sails app and I am not getting any result back in my get call.
My code looks something like this:
module.exports = {
attributes: {
id: {
type: 'string',
primaryKey: true,
defaultsTo: function () {
return uuid.v4();
},
unique: true,
index: true,
uuidv4: true
},
name: {
type: 'string',
required: true
}
fullName: function(){
return this.name ;
}
};
I get back all the fields expect full Name

In my opinion the sailsjs model attributes only create corresponding column and get the column in database based on the type. In your case, the fullName has no type. so it does not know what to get from database.
However, if what you want is the returned json object has some extra fields, you can overwrite the toJSON function to add it.
module.exports={
attributes:
id: {
type: 'string',
primaryKey: true,
defaultsTo: function () {
return uuid.v4();
},
unique: true,
index: true,
uuidv4: true
},
name: {
type: 'string',
required: true
},
toJSON:function(){
var obj=this.toObject();
obj.fullName=obj.name;
return obj;
}
}
}

This issue is a little old, but I've a better answer:
module.exports = {
attributes: {
firstname : 'string',
lastname : 'string,
fullName: function () {
return this.firstname + ' ' + this.lastname
}
toJSON:function(){
var obj = this.toObject();
obj.fullName = this.fullName()
return obj;
}
}
}

Related

SequelizeDatabaseError: the operator does not exist : integer = boolean when using special methods on model instance

I have two models in Many-to-Many association : Agency and Customer.
UPDATE : (here are the models and association definition)
Agency :
const agency = (sequelize, DataTypes) => {
const Agency = sequelize.define('agency', {
name: {
type: DataTypes.STRING,
allowNull: false,
validate: {
notEmpty: true,
}
},
});
Agency.associate = models => {
Agency.hasMany(models.User, { onDelete: 'CASCADE' });
Agency.belongsToMany(models.Customer, { onDelete: 'SET NULL', through: 'CustomerAgencies'});
};
return Agency;
};
export default agency;
Customer :
const customer = (sequelize, DataTypes) => {
const Customer = sequelize.define('customer', {
email: {
type: DataTypes.STRING,
unique: true,
allowNull: false,
validate: {
notEmpty: true,
isEmail: true,
},
},
firstname: {
type: DataTypes.STRING,
allowNull: true,
validate: {
notEmpty: true,
}
},
lastname: {
type: DataTypes.STRING,
allowNull: true,
validate: {
notEmpty: true,
}
},
phone: {
type: DataTypes.INTEGER,
},
language: {
type: DataTypes.STRING,
},
});
Customer.associate = models => {
Customer.belongsToMany(models.Agency, { onDelete: 'SET NULL', through: 'CustomerAgencies'});
};
return Customer;
};
export default customer;
When i create some entries, there is no problem :
const agency = await models.Agency.findOrCreate({
where: { name: 'SunTour'},
defaults: {
name: 'SunTour'
}
});
const customer = await models.Customer.findOrCreate({
where: { email: 'paulo#example.com' },
defaults: {
email: 'paulo#example.com',
firstname: 'Paulo',
lastname: 'Dena',
phone: '0202020202',
},
});
But i'm trying to use the special methods of Sequelize that are available when two models are in relation.
Juste under the previous code example i wrote this to check is there is already an assocation between the two instances :
debug(await customer[0].hasAgency(agency));
The node server return me the error below for this line :
UnhandledPromiseRejectionWarning: SequelizeDatabaseError: the operator does not exist : integer = boolean
In the console the query executed is this one :
SELECT "agency"."id" FROM "agencies" AS "agency" INNER JOIN "CustomerAgencies" AS "CustomerAgencies" ON "agency"."id" = "CustomerAgencies"."agencyId" AND "CustomerAgencies"."customerId" = 1 WHERE ((("agency"."id" = 1 OR "agency"."id" = false)));
You can see that Sequelize query is using "agency.id = false" in his condition, i guess that's the problem.
Note : i'm using a PostGreSQL Database.
I guess the problem come from the PostGreSQL Database, but what can i do ?
Thanks in advance.

Why isn't my Getter function working with Mongoose?

I have a getter on the price property of my schema.
For some reason, my getter function is not working when I try to query a document from my MongoDB database. The price value comes back exactly as I have it saved in my database, as opposed to a rounded number via Math.floor(v). Fyi, my setter works fine in the same scenario. Any help would be much appreciated!
const schema = mongoose.Schema({
name: { type: String, required: true, lowercase: true },
isPublished: Boolean,
author: {
type: String,
required: function (v) {
return this.isPublished;
},
uppercase:true,
},
price: {
type: Number,
required: true,
get: function (v) {
return Math.floor(v);
},
},
});
const Documents = mongoose.model("Documents", schema);
async function myQuery(id) {
const result = await Documents.findById(id);
if (!result) return debug("Not found...");
debug(result);
}
myQuery("60348d30e7b9bf3878170955");
const schema = mongoose.Schema({
name: { type: String, required: true, lowercase: true },
isPublished: Boolean,
author: {
type: String,
required: function (v) {
return this.isPublished;
},
uppercase: true,
},
price: {
type: Number,
required: true,
get: function (v) {
return Math.floor(v);
},
},
} {
toObject: { getters: true, setters: true },
toJSON: { getters: true, setters: true },
runSettersOnQuery: true
});
Add the following configuration to your schema and give it a try.

UUID as primary key in sailsjs domain

I am using Sails.js version 1.0.2. I am trying to assign uuid as primary key throughout the application. I tried putting
id: { type: 'string', defaultsTo:uuid.v4() } in model.js but it's saying Primary keys must be unique therefore can't contain a default value.
_________________EDIT_______________
I tried this code in my domain
beforeCreate: function (modelObj, next) {
modelObj.id = uuidv4.v4();
next();
}
And edit my Model.js configuration is like :
attributes: {
createdAt: { type: 'number', autoCreatedAt: true, },
updatedAt: { type: 'number', autoUpdatedAt: true, },
id: { type: 'string',required:true},
}
beforeCreate method never executes and throw the error while creating the record like:
error: Sending 500 ("Server Error") response:
{ UsageError: Invalid new record.
Details:
Missing value for required attribute `id`. Expected a string, but
instead, got: undefined
Please let me know if I am doing anything wrong.
Thanks
You can do something like this instead of giving default value
beforeCreate: function (modelObj, next) {
modelObj.id = uuid.v4();
next();
}
You can add this piece of function in your model. This gets invoked whenever there is a create operation on model.
Your Model.js should looks something like this
attributes: {
createdAt: { type: 'number', autoCreatedAt: true, },
updatedAt: { type: 'number', autoUpdatedAt: true, },
id: { type: 'string',required:true},
},
beforeCreate: function (modelObj, next) {
modelObj.id = uuid.v4();
next();
}
Sample code of my Controller and Model,
TestController.js
module.exports = {
create: function(req, res) {
Test.create({"name": "arshad"})
.then(function(result){
res.send("done");
})
}
};
Test.js Model
module.exports = {
attributes: {
id: { type: 'string', required: true },
name: { type: 'string' }
},
beforeCreate: function(obj, next) {
obj.id = 'someId';
next();
}
};
This is how your model and controller will look like. This will add someId as defined in beforeCreate function to the object
In your case you are using uuid package. Check in debugging mode whether uuid reference is available in beforeCreate or not

Get single attribute in model using Mongoose

I have 2 Schemas : StepSchema, StepRelationshipSchema
var StepSchema = new Schema(
{
name: { type: String, required: true },
description: { type: String, default: '' },
isVisible: { type: Boolean, default: true }
}, options
);
var StepRelationshipSchema = new Schema(
{
workflowId: { type: String, required: true },
stepId: { type: String, required: true },
prevSteps: [ Schema.Types.Mixed ] ,
nextSteps: [ Schema.Types.Mixed ] ,
gotoStep: { type: String, default: '' }
}, options
);
In StepSchema, I want to create a static method to get nextSteps in StepRelationshipSchema.
Can I use this, thank you so much.
StepSchema.statics.getNextSteps = function(workflowId, currStepId) {
return StepRelationship.findOne({
workflowId: workflowId,
stepId: currStepId
}).nextSteps
};
As #JohnnyHK suggested in his comments, findOne() is async thus you need to use a callback function as follows:
// create a query for next stepswith a blogpost _id matching workflowId and currStepId
schema.statics.getNextSteps = function (workflowId, currStepId, callback) {
return this.model('StepRelationship').findOne({
workflowId: workflowId,
stepId: currStepId
}, callback);
}

Sails.js composite unique field

This model gives me the effect I want at the expense of duplicated data and general uglyness:
//Example
var Example = {
attributes: {
foo: {
type: 'string',
required: true
},
bar: {
type: 'string',
required: true,
},
baz: {
type: 'integer',
required: true,
min: 1
},
foobar: {
type: 'string',
unique: true
}
},
beforeValidation : function(values,cb) {
values.foobar = values.foo+values.bar;
cb();
}
};
module.exports = Example;
Is there a better strategy for creating a composite unique key?
There's no way to do this directly in sails see https://github.com/balderdashy/waterline/issues/221. The best solution is to do this directly in the db you plan to use.