SailsJS update and mySQL custom ID column not working - mysql

In SailsJS, I created a model Profiles including a custom primary key as follows:
module.exports = {
tableName: 'tbl_profiles',
autoPK: false,
autoCreatedAt: false,
autoUpdatedAt: false,
attributes: {
user_id: {
type: 'integer',
size: 11,
columnName: 'user_id',
unique: true,
primaryKey: true,
},
...
Now, when calling the blueprint route to update a user profile, I get the following error:
ER_BAD_FIELD_ERROR: Unknown column 'tbl_profiles.id' in 'where clause'
Debugging this down (and seeing question SailsJS and mySQL custom ID name not working with blue prints not helping) I found out that the update is carried through all right in the db and that the record is changed but in the controller callback function an error and status 400 is raised nevertheless:
Profiles.update({user_id: req.param('id')}, req.body).exec(function(err, profile) {
if (err) {
return res.status(400).json(err);
} else {
return res.status(200).json(profile);
}
});
Tracing down the SQL involved in /node_modules/sails-mysql/node_modules/mysql/lib/protocol/sequences/Sequence.js:48:14, it seems the following statement is executed just after the update is finished (note the final WHERE clause):
SELECT `tbl_profiles`.`user_id`,
`tbl_profiles`.`lastName`,
`tbl_profiles`.`firstName`,
`tbl_profiles`.`date_of_birth`,
`tbl_profiles`.`address_line1`,
`tbl_profiles`.`address_line2`,
`tbl_profiles`.`zip_code`,
`tbl_profiles`.`city`,
`tbl_profiles`.`gender`,
`tbl_profiles`.`country_id`,
`tbl_profiles`.`phone`,
`tbl_profiles`.`user_id`
FROM `tbl_profiles` AS `tbl_profiles`
WHERE `tbl_profiles`.`id` = undefined
Where could I set SailsJS/Waterline to use the custom column ID? Setting autoPK true either in the beginning or the end of the model wouldn't do the trick..

Related

Unable to create BLOB/Binary types with LoopBack 4

I'm trying to use Loopback for my new projects, but I've been facing some problems...
I have the habit of storing my UUIDs ID in a binary format at my databases, here's an example:
#model({
settings: { mysql: { table: 'application' } },
})
export class Application extends Entity {
#property({
type: 'buffer',
required: true,
generated: false,
id: true,
dataLength: 16,
})
id: BinaryType;
[...]
}
But when I try to do the migration, I've been receiving that error from mysql:
"BLOB/TEXT column 'id' used in key specification without a key length"
I really tried everything and nothing works. Hope that you'll be able to help me!
Thanks a lot!
I'll show the answer for this question that I made.
Just define your model with the following info:
#property({
required: true,
mysql: {
columnName: 'application_id',
dataType: 'VARBINARY',
dataLength: 16,
nullable: 'NO'
}
})
application_id: string;
It worked like a charm for me :)
Thank you all!

NodeJS sequelize timestamps disabled but still getting Unknown column 'createdAt' error

I am building a new NodeJS application with MySQL. I need to use the existing database from the original version of the application. I am using a mysql dump file from the old database to create the new database.
I generated the models automatically based on the existing database using sequelize-auto module.
The createdAt field does not exist in the database and timestamps are specifically disabled in all of the models. However, I am still seeing this error when running a query such as models.people.findAll() or models.people.findOne():
"SequelizeDatabaseError: Unknown column 'createdAt' in 'field list'"
I followed the instructions in this other post to disable timestamps globally, however it does not work to solve the issue.
Sequelize Unknown column '*.createdAt' in 'field list'
Here are the relevant versions:
"mysql": "^2.17.1",
"mysql2": "^1.6.5",
"sequelize": "^5.8.5",
"sequelize-auto": "^0.4.29",
"sequelize-auto-migrations": "^1.0.3"
Here is the people model. Timestamps have been disabled explicitly in this and all other models globally. Also, I have read that timestamps : false is the default in the latest version of sequelize, so I am confused as to how this is an issue at all.
module.exports = function(sequelize, DataTypes) {
return sequelize.define('people', {
PersonID: {
type: DataTypes.INTEGER(10).UNSIGNED,
allowNull: false,
primaryKey: true
},
FirstName: {
type: DataTypes.STRING(50),
allowNull: false
},
LastName: {
type: DataTypes.STRING(50),
allowNull: false
},
Username: {
type: DataTypes.STRING(50),
allowNull: true
},
EmailAddress: {
type: DataTypes.STRING(255),
allowNull: true
}
}, {
tableName: 'people',
timestamps: 'false'
});
};
I see that you use sequelize-auto-migrations in your dependencies and I found an opened issue in their repo linked to your problem.
You maybe made a mistake setting the timestamps or the migrations are executed in the server after the disabling of the timestamps so the created_at columns are being added again to your tables.
I hope this helps you.

sequelize returns null for column 'id' in the dataValues of a query result.

I am using the sequelize in combination with my nodejs typescript application and am facing the following issue. I created a class called OrmMapper which is responsible for creating my tables. I created a table called "PCS" and initialized it with the following code:
PCS.init({
id: {
primaryKey : true,
autoIncrement: true,
type: DataTypes.INTEGER
},
owner : DataTypes.INTEGER,
created: DataTypes.DATE,
year : DataTypes.STRING
}, {sequelize});
The generated DDL is fine and the problem occurs whenever I run this piece of code:
handleGetByOwner(request: TrackerRequest, res:Response):void{
this.pcsModel.findAll({where:{owner: request.queryParams.ownerId}}).then((dataPackage:any)=>{
let PCSS = [];
console.log(dataPackage);
for(let pcs of dataPackage){
PCSS.push(pcs.dataValues);
}
res.status(200).send(new TrackerResponse({success: true, payload: PCSS, timeStamp: new Date()}));
});
}
which generates the following SQL:
SELECT `id`, `owner`, `created`, `year`, `createdAt`, `updatedAt` FROM `PCs` AS `PCS` WHERE `PCS`.`owner` = '1';
When I look in my database, all the data inserted is correct, when i execute the above SQL statement everything works. However when I run the server code above the result of my query is:
All of the datavalues are correct, expect for id which is null.

How to get create() return auto-increment primary key after creation in sails.js?

I have a model, Case.js:
...
attributes: {
id: {
type: 'integer',
unique: true,
primaryKey: true,
columnName: 'pid' //an auto-increment primary key, generated by MySQL
},
...
}
And I want to get this id after creation:
Case.create({...}).then(function(aCase){
console.log(aCase.id);
})
The creation succeeded, but the output I got is undefined.
I tried setting autoPK to false, and deleting "unique" and "primaryKey" entry, but the result didn't change.
Please tell me how to make create() return this id.
I've worked it out myself. The problem lies in my model Case.js.
In sails.js, if you want a primary key (usually id) created by MySQL with auto-increment to be returned after create(), your model should look like this:
module.exports = {
...
autoPK: false,
attributes: {
id: {
type: 'integer',
unique: true,
primaryKey: true,
autoIncrement: true,
},
...
}
}
Pay attention to "autoIncrement" attribute, it is necessary in my case, and probably in every auto-increment primary key.
I'm looking at the Sails.js documentation for creating a new entry in a database. The method is indicated as
Something.create(values).exec(function (err, records) {
});
In your case, you should have
Case.create({...}).exec(function(err, aCase){
console.log(aCase.id);
})

A Sequelize column that cannot be updated

Is it possible to create a column on a MySQL table using Sequelize that can be initialized when creating a new row, but never updated?
For example, a REST service allows a user to update his profile. He can change any field except his id. I can strip the id from the request on the API route, but that's a little redundant because there are a number of different models that behave similarly. Ideally, I'd like to be able to define a constraint in Sequelize that prevents the id column from being set to anything other than DEFAULT.
Currently, I'm using a setterMethod for the id to manually throw a ValidationError, but this seems hackish, so I was wondering if there's a cleaner way of doing this. Even worse is that this implementation still allows the id to be set when creating a new record, but I don't know a way around this as when Sequelize generates the query it calls setterMethods.id to set the value to DEFAULT.
return sequelize.define('Foo',
{
title: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
validate: {
notEmpty: true
}
}
},
{
setterMethods: {
id: function (value) {
if (!this.isNewRecord) {
throw new sequelize.ValidationError(null, [
new sequelize.ValidationErrorItem('readonly', 'id may not be set', 'id', value)
]);
}
}
}
}
);
Look at this Sequelize plugin:
https://www.npmjs.com/package/sequelize-noupdate-attributes
It adds support for no update and read-only attributes in Sequelize models.
In your specific case, you could configure the attribute with the following flags:
{
title: {
type: DataTypes.STRING,
allowNull: false,
unique : true,
noUpdate : true
}
}
That will allow the initial set of the title attribute if is null, and then prevent any further modifications once is already set.
Disclaimer: I'm the plugin author.