ER_TOO_LONG_KEY in SailsJS 1.0 with sails-mysql - sails.js

I got this error with sails when I try to sails lift:
info: ·• Auto-migrating... (drop)
error: A hook (`orm`) failed to load!
error:
error: Error: ER_TOO_LONG_KEY: Specified key was too long; max key length is 767 bytes
I just have one model for now: 
module.exports = {
datastore: 'default',
tableName: 'sci_user',
attributes: {
email: {
type: 'string',
required: true,
unique: true
},
password: {
type: 'string',
required: true
}
}
It's really simple and I got it from the documentation. I don't understand. It seems it's because of the unique: true.

This is due to a combination of factors, but the most pertinent one is that sails-mysql currently defaults to using the utf8mb4 character set for string attributes, to allow the use of emojis and other extended characters. We're working on a patch to make this configurable rather than the default, but in the meantime the quickest workaround is to declare the columnType for your attributes directly:
module.exports = {
datastore: 'default',
tableName: 'sci_user',
attributes: {
email: {
type: 'string',
required: true,
unique: true,
columnType: 'varchar'
},
password: {
type: 'string',
required: true,
columnType: 'varchar'
}
}

Related

Mongoose 6 - How to get only the custom validation error message without the error?

const userSchema = new mongoose.Schema({
email: {
type: String,
unique: true,
required: [true, 'Email address is required'],
minlength: [4, 'Must be at least 4 characters long']
}
});
When I log the error I get:
User validation failed: email: Must be at least 4 characters long
How can I get only my custom message:
Must be at least 4 characters long
The only thing I do as of now is
const messageString = message.split(':');
messageString[3]
But is there a better way? I saw some solutions for this but its all for mongoose version 5 or less and it doesnt apply to version 6 as the error object has different properties.
On a side note (maybe this should be a seperate question) but as the error object is different now, how can I check if its a mongoose validation error? The err object doesnt come with it anymore.
Error: User validation failed: email: Must be at least 4 characters long
at ValidationError.inspect (/Users/... {
errors: {
email: ValidatorError: Must be at least 4 characters long
at validate (/Users/user/....
at processTicksAndRejections (node:internal/process/task_queues:78:11) {
properties: [Object],
kind: 'minlength',
path: 'email',
value: 'hgg',
reason: undefined,
[Symbol(mongoose:validatorError)]: true
}
},
_message: 'User validation failed'
}
Also, I dont want to have to access the modal property 'email' when accessing any other property as in my errorhandler, I want to keep it reusable for other errors too

Loopback 4/MongoDB - Foreign key not converted to ObjectID

I am trying to set up an hasMany relation using a Mongo database.
I have followed the guide to create an hasMany relation in the loopback 4 documentation (https://loopback.io/doc/en/lb4/HasMany-relation.html) and tryied to set differents properties but the foreign key custId is saved as a string and not as an ObjectID.
I also found a few other properties or options from others topics but people were using Loopback 3 and it doesn't seem to work with Loopback 4.
Did I miss something or is there any workaround ?
Here are my models :
#model()
export class Order extends Entity {
#property({
type: 'string',
id: true,
generated: true,
})
id: string;
#property({
type: 'array',
itemType: 'string',
required: true,
})
product: string[];
#property({
type: 'number',
required: true,
})
price: number;
#property({
type: 'string',
id: true,
generated: true,
})
custId: string;
constructor(data?: Partial<Order>) {
super(data);
}
}
#model()
export class Customer extends Entity {
#property({
type: 'string',
id: true,
generated: true,
})
id: string;
#property({
type: 'string',
required: true,
})
name: string;
#property({
type: 'string',
})
adress?: string;
#hasMany(() => Order, {keyTo: 'custId'})
orders?: Order[];
constructor(data?: Partial<Customer>) {
super(data);
}
}
This is currently a bug. The hasMany / belongsTo will end up saving the relation id as a string instead of an ObjectId. You can verify this by changing the id in the database directly to an ObjectId and then it will find it.
Reference: https://github.com/strongloop/loopback-next/issues/2085
It is also mentioned on the latest Monthly Milestone here, so hopefully it will be resolved soon: https://github.com/strongloop/loopback-next/issues/2313
Edit: I was able to get it working by adding strictObjectIDCoercion to the model, but that can break other things according to issue 2085 linked above.
#model({
settings: {
strictObjectIDCoercion: true,
}
})
For hasMany relationship you need to update order Model.
Update order.model with :
1.Import Customer Model
import {Customer} from './customer.model';
remove custId: string;
2.For reference customer Id Just update code with
#belongsTo(() => Customer)
custId: number;
Reference Example : here

Meteor - node simple schema validate data to match schema

I want to change my Rest-API validation to node simple schema for schema definition and collection2#core for schema validation.
I want to use the Person schema to validate the data provided by the users.
Schemas = {};
Schemas.Person = new SimpleSchema({
name: {
type: String,
label: "Person's Name",
unique: true,
max: 200
},
surname: {
type: String,
unique: true,
label: "person's surname"
},
};
validData = API.utility.validate(data, Schemas.Person });
API: {
utility: {
validate: function(data, schema) {
return "The SimpleSchema Validation";
}
}
};
This case is described in the simpl-schema documentation
With your schema definition you can just do:
Schemas.person.validate(data);
If right after that you want to look at the result or the errors:
Schemas.person.isValid();
Schemas.person.validationErrors();

"email" validation rule crash sails server - Mongo with Sails.js

while the email validation rule fails on module of the sails.js, the server is crashing.
Here the snippet of my module:
// The user's email address
email: {
type: 'string',
email: true,
required: true,
unique: true
},
And the error as below :
err: Error (E_VALIDATION) :: 1 attribute is invalid
at WLValidationError.WLError (C:\Users\yuri\AppData\Roaming\npm\node_modules\sails\node_modules\waterline\lib\waterline\error\WLError.js:26:15)
at new WLValidationError (C:\Users\yuri\AppData\Roaming\npm\node_modules\sails\node_modules\waterline\lib\waterline\error\WLValidationError.js:20:28)
at C:\Users\yuri\AppData\Roaming\npm\node_modules\sails\node_modules\waterline\lib\waterline\query\validate.js:45:43
at allValidationsChecked (C:\Users\yuri\AppData\Roaming\npm\node_modules\sails\node_modules\waterline\lib\waterline\core\validations.js:203:5)
at done (C:\Users\yuri\AppData\Roaming\npm\node_modules\sails\node_modules\async\lib\async.js:135:19)
at C:\Users\yuri\AppData\Roaming\npm\node_modules\sails\node_modules\async\lib\async.js:32:16
at C:\Users\yuri\AppData\Roaming\npm\node_modules\sails\node_modules\waterline\lib\waterline\core\validations.js:184:23
at done (C:\Users\yuri\AppData\Roaming\npm\node_modules\sails\node_modules\async\lib\async.js:135:19)
at C:\Users\yuri\AppData\Roaming\npm\node_modules\sails\node_modules\async\lib\async.js:32:16
at C:\Users\yuri\AppData\Roaming\npm\node_modules\sails\node_modules\waterline\lib\waterline\core\validations.js:157:64
at C:\Users\yuri\AppData\Roaming\npm\node_modules\sails\node_modules\async\lib\async.js:125:13
at Array.forEach (native)
at _each (C:\Users\yuri\AppData\Roaming\npm\node_modules\sails\node_modules\async\lib\async.js:46:24)
at Object.async.each (C:\Users\yuri\AppData\Roaming\npm\node_modules\sails\node_modules\async\lib\async.js:124:9)
at validate (C:\Users\yuri\AppData\Roaming\npm\node_modules\sails\node_modules\waterline\lib\waterline\core\validations.js:156:11)
at C:\Users\yuri\AppData\Roaming\npm\node_modules\sails\node_modules\async\lib\async.js:125:13
Invalid attributes sent to User:
• email
• undefined should be a email (instead of "admin#gmailasd", which is a string)
The correct way to declare an email field is like this :
email: {
type: 'email',
required: true,//Email field will be required for insert or update
unique: true //Insert or update will crash if you try to insert duplicate email
},
You can see all different attribut types here http://sailsjs.org/documentation/concepts/models-and-orm/attributes
If you want to catch insert/update errors you can do this on your controller :
MyModel.create({email:email}).exec(function(err, model)
{
if(err)
{
//Check if it's a validation error or a crash
if(err.code == "E_VALIDATION")
sails.log.debug("valid fail, check form");
else
sails.log.debug("crash");
}
else
{
//do what you want to do with the data
}
});
Her the answer.
Thanks to jaumard, i found the problem.
I used undefined field in error, without checking if exists before
err.originalError.code but it was undefined.
So the correct way is :
err.originalError && err.originalError.code && err.originalError.code === 11000
and not
err.originalError.code === 11000.
Previous versions of Sails recommended that email validation was achieved like this
email: {
type: 'string',
email: true,
required: true
},
The current version should be like this
email: {
type: 'email',
required: true
},

Avoiding global leaking when using JayData 1.3.4 local item store

Out of the box Entities defined by using $data.Entity.extend will be globally accessible. e.g. in the example taken from JayData's home page Todo will leak.
// Case 1: local item store example from http://jaydata.org/
$data.Entity.extend("Todo", {
Id: { type: "int", key: true, computed: true },
Task: { type: String, required: true, maxLength: 200 },
DueDate: { type: Date },
Completed: { type: Boolean }
});
console.log('Leaks Todo?', typeof window.Todo !== 'undefined');
//Result: true
In a JayData forum post I found a reference to $data.createContainer(), which can be used as container during Entity definition. In this case Todo2 won't leak.
// Case2: creating Todo2 in a container
$data.Entity.extend("Todo2", container, {
Id: { type: "int", key: true, computed: true },
Task: { type: String, required: true, maxLength: 200 },
DueDate: { type: Date },
Completed: { type: Boolean }
});
console.log('Leaks Todo2?', typeof window.Todo2 !== 'undefined');
//Result: false
Unfortunately after accessing stores there'll be other variables that leak globally even if the Entity itself is associated with a container.
console.log('Before store access: Leaks Todo2_items?',
typeof window.Todo2_items !== 'undefined');
//Result: false
$data('Todo2').save({ Task: 'Initialized Todo2'})
console.log('After store access: Leaks Todo2_items?',
typeof window.Todo2_items !== 'undefined');
//Result: true
Complete fiddle can be found at http://jsfiddle.net/RainerAtSpirit/nXaYn/.
In an ideal world every variable that is created for entities that run in a container would be associated with the same container. Is there an option to accomplish that or is the behavior described in Case2 the best that can be currently accomplished?