i am new in sequelize and ORMs and i am trying to create a model. This is what i have:
/* Carrier model definition */
const carrier = sequelize.define('carrier', {
/* The unique carrier id */
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false
},
/* The iata code of the carrier */
iata: {
type: Sequelize.STRING,
validate: {
is: {
args: ["^[A-Z]{1}[0-9]{1}$|^[A-Z]{1}[A-Z]{1}$|^[0-9]{1}[A-Z]{1}$|^\s*$"],
msg: "Carrier iata code is invalid."
}
}
},
/* The icao code of the carrier */
icao: {
type: Sequelize.STRING,
validate: {
is: {
args: ["^[A-Z]{3}$|^\s*$"],
msg: "Carrier icao code is invalid."
}
}
},
/* The deleted flag of the carrier */
isdeleted: {
type: Sequelize.INTEGER,
validate: {
isIn: {
args: [
[0, 1]
],
msg: "Carrier \"is deleted value\" can be 0 or 1."
}
}
}
}, {
/* Perform model validations */
validate: {
carrierValidator() {
/* Ensure that at least an iata or an icao code exists */
if ((this.iata == "") && (this.icao == "")) {
throw new Error('Carrier must have at least an iata code or an icao code or both.');
}
}
},
/* Apply hooks */
hooks: {
beforeValidate: (carrier, options) => {
/* Capitalize carrier iata code */
carrier.iata = (typeof carrier.iata === 'undefined') ? "" : carrier.iata.toUpperCase();
/* Capitalize carrier icao code */
carrier.icao = (typeof carrier.icao === 'undefined') ? "" : carrier.icao.toUpperCase();
/* Set default isdeleted value to 0 */
carrier.isdeleted = (typeof carrier.isdeleted === 'undefined') ? 0 : parseInt(carrier.isdeleted);
}
}
})
The isdeleted property is a column which defines if an entry is deleted or not. If it is deleted it's value is 1 and if not 0.
Now, i want to prevent the insert of a new carrier, if one of the following is true:
If a carrier with the same iata code, and isdeleted = 0 exists
If a carrier with the same icao code, and isdeleted = 0 exists
I managed to achieve it, by adding the following block inside validate (for iata case):
if (this.iata != ""){
sequelize.models.carrier.findAndCountAll({
where: {
iata: this.iata,
isdeleted:0
}
}).then((result) => {
if (result.rows != 0){
throw new Error("Carrier iata code already exists.");
}
})
}
and when i attempt to insert a duplicate i get a very ugly response:
Is there a way to get an instance of ValidationError in order to handle it and display iteasier?
Well it looks like i was a bit tired and i missed a return...
if (this.iata != ""){
return sequelize.models.carrier.findAndCountAll({
where: {
iata: this.iata,
isdeleted:0
}
}).then((result) => {
if (result.rows != 0){
throw new Error("Carrier iata code already exists.");
}
})
}
Thanks to florin from sequelize slack!
Related
I'm trying to store history of workout in realm, my addHistory function looks like this
export function addHistory(workout, exercise, sets, _id) {
console.log({
workout,
exercise,
sets,
_id,
});
if (
_id !== undefined &&
workout !== undefined &&
exercise !== undefined &&
sets !== undefined
) {
// return console.log("HISTORY ", { workout, exercise, sets, _id });
return realm.write(() => {
return realm.create("workoutData", {
_id: _id,
exercise,
workout,
sets,
workoutDate: new Date(Date.now()),
});
});
} else {
alert("History is incomplete");
}
}
Schema of the workoutData is as follows:
exports.workoutData = {
name: "workoutData",
primaryKey: "_id",
properties: {
_id: "int",
workout: "workouts",
exercise: "exercise",
workoutDate: "date",
sets: "sets[]",
},
};
Now when I add sets and click on finishWorkoutHandler the logic works fine before the addHistory function but when addHistory is executed it throws the error as stated in the question.
//finish workout handler
const finishWorkoutHandler = () => {
if (sets.length == 0) {
return;
}
let setsFromRealm = realm.objects("sets");
let workoutData = realm.objects("workoutData");
let setsArray = [];
exercises.forEach((exercise) => {
sets
.filter((items) => items.exercise._id == exercise._id)
.forEach((sets) => {
let _id = 0;
if (setsFromRealm.length > 0) {
_id = realm.objects("sets").max("_id") + 1;
}
addSet(
sets.name,
parseInt(sets.weight),
parseInt(sets.reps),
parseInt(sets.rmValue),
sets.isHeighest,
sets.exercise,
_id,
sets.profile,
sets.failedSet,
sets.warmupSet,
sets.notes
);
let indiSet = {
name: sets.name,
weight: parseInt(sets.weight),
reps: parseInt(sets.reps),
rmValue: parseInt(sets.rmValue),
isHeighest: sets.isHeighest,
_id: _id,
profile: sets.profile,
failedSet: sets.failedSet,
warmupSet: sets.warmupSet,
notes: sets.notes,
createdDate: new Date(Date.now()),
};
setsArray.push(indiSet);
});
let workoutDataId = 0;
let setsArrcopy = setsArray;
console.log("SETS ", realm.objects("sets"));
console.log("SETS ", setsArrcopy);
if (workoutData.length > 0) {
workoutDataId = realm.objects("workoutData").max("_id") + 1;
}
**WORKING AS EXPECTED TILL HERE**
// problem lies here
addHistory(params.workout, exercise, setsArrcopy, workoutDataId);
});
dispatch(setsEx([]));
goBack();
};
the structure of setsArrCopy containing sets is as follows
[
({
_id: 6,
createdDate: 2022-09-29T16:27:06.128Z,
failedSet: false,
isHeighest: false,
name: "Thai",
notes: "",
profile: [Object],
reps: 12,
rmValue: 64,
warmupSet: false,
weight: 56,
},
{
_id: 7,
createdDate: 2022-09-29T16:27:06.151Z,
failedSet: false,
isHeighest: false,
name: "Thsi 3",
notes: "",
profile: [Object],
reps: 10,
rmValue: 75,
warmupSet: false,
weight: 66,
})
];
the logic is also working fine in terms of assigning new ids to the sets being added in a loop. But somehow its throwing error when passing setArrCopy to addHistory function. Although its an array of sets not a single object?
Hi i'm using detox and i would like to know how can I get the number of matches to
one element(length).
For example "card" match three times, how can I get the three.
const z = await element(by.id("card"))
https://github.com/wix/Detox/blob/master/docs/APIRef.Expect.md
https://github.com/wix/Detox/blob/master/docs/APIRef.Matchers.md
They don't support it in the API /:
z output:
Element {
_invocationManager: InvocationManager {
executionHandler: Client {
isConnected: true,
configuration: [Object],
ws: [AsyncWebSocket],
slowInvocationStatusHandler: null,
slowInvocationTimeout: undefined,
successfulTestRun: true,
pandingAppCrash: undefined
}
},
matcher: Matcher { predicate: { type: 'id', value: 'card' } }
}
A workaround could be
async function getMatchesLength(elID) {
let index = 0;
try {
while (true) {
await expect(element(by.id(elID)).atIndex(index)).toExist();
index++;
}
} catch (error) {
console.log('find ', index, 'matches');
}
return index;
}
then you can use
const length = await getMatchesLength('card');
jestExpect(length).toBe(3);
Here is my solution in typescript:
async function elementCount(matcher: Detox.NativeMatcher) {
const attributes = await element(matcher).getAttributes();
// If the query matches multiple elements, the attributes of all matched elements is returned as an array of objects under the elements key.
https://wix.github.io/Detox/docs/api/actions-on-element/#getattributes
if ("elements" in attributes) {
return attributes.elements.length;
} else {
return 1;
}
}
Then you can use it like this:
const jestExpect = require("expect");
jestExpect(await elementCount(by.id("some-id"))).toBe(2);
I tried my best to write a custom directive in apollo server express to validate if an input type field of type [Int] does not have more than max length but do not know if its the right way to do. Appreciate if somebody could help me correct any mistakes in the code below.
// schema.js
directive #listLength(max: Int) on INPUT_FIELD_DEFINITION
input FiltersInput {
filters: Filters
}
input Filters {
keys: [Int] #listLength(max: 10000)
}
// Custom directive
const { SchemaDirectiveVisitor } = require('apollo-server-express');
import {
GraphQLList,
GraphQLScalarType,
GraphQLInt,
Kind,
DirectiveLocation,
GraphQLDirective
} from "graphql";
export class ListLengthDirective extends SchemaDirectiveVisitor {
static getDirectiveDeclaration(directiveName) {
return new GraphQLDirective({
name: directiveName,
locations: [DirectiveLocation.INPUT_FIELD_DEFINITION],
args: {
max: { type: GraphQLInt },
}
});
}
// Replace field.type with a custom GraphQLScalarType that enforces the
// length restriction.
wrapType(field) {
const fieldName = field.astNode.name.value;
const { type } = field;
if (field.type instanceof GraphQLList) {
field.type = new LimitedLengthType(fieldName, type, this.args.max);
} else {
throw new Error(`Not a scalar type: ${field.type}`);
}
}
visitInputFieldDefinition(field) {
this.wrapType(field);
}
}
class LimitedLengthType extends GraphQLScalarType {
constructor(name, type, maxLength) {
super({
name,
serialize(value) {
return type.serialize(value);
},
parseValue(value) {
value = type.serialize(value);
return type.parseValue(value);
},
parseLiteral(ast) {
switch (ast.kind) {
case Kind.LIST:
if (ast.values.length > maxLength) {
throw {
code: 400,
message: `'${name}' parameter cannot extend ${maxLength} values`,
};
}
const arrayOfInts = ast.values.map(valueObj => parseInt(valueObj['value']));
return arrayOfInts;
}
throw new Error('ast kind should be Int of ListValue')
},
});
}
}
Does this look right?
Thanks
I'm using vue-tags-input component. In its docs we can find validation. I'm trying to create validation so valid input must have:
min 3 signs
two numbers
comma between numbers
this is what I have:
validation: [{
classes: 'min-length',
rule: tag => tag.text.length < 3,
},{
classes: 'min-length',
rule: ({ text }) => {
const comma = text.indexOf(',') === -1;
if(comma) {
const arr = text.split(',')
if(arr[0] && arr[1]) {
if(arr[0].typeof === 'number' && arr[1].typeof === 'number') {
return true;
}
}
}
return false;
}
}]
So I'm spliting string to array by ,. In result I should have array with two elements. Then I check if both elemenets are numbers. How ever this not work properly because it treat 111 as valid but it shoudn't.
I've created demo on codesanbox.
To check if comma exists you have to check if indexOf comma not equals -1.
const comma = text.indexOf(",") !== -1;
You have to convert the string to number using Number(string).
if (typeof Number(arr[0]) === "number") {..
You have to return false if validation succeeds and true if there is an error,
you are doing the opposite.
The complete code will be:
{
classes: "custom",
rule: ({ text }) => {
const comma = text.indexOf(",") !== -1;
if (comma) {
const arr = text.split(",");
if (arr[0] && arr[1]) {
if (typeof Number(arr[0]) === "number" && typeof Number(arr[1]) === "number") {
return false;
}
}
}
return true;
}
}
A shorter regex rule will be:
{
classes: "custom",
rule: ({ text }) => {
return !text.match(/^\d+,\d+$/);
}
}
I have a bug in my application where I am trying to update a phone number and when I click on save, I get the error message and the original phone number stays populated:
Obviously, something has gone wrong with validation. I was hoping it was perhaps the regex although it has a solid one, but I changed it like so:
const regex = {
userName: /^[-.\sa-zA-Z]+$/,
cardName: /^[-\sa-zA-Z]+$/,
password: /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[##$%^&*()\-+!\\.]?).{8,}$/,
zip: /(^\d{5}$)|(^\d{5}-\d{4}$)/,
memberId: /^\d+$/,
// phoneNumber: /^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$/,
phoneNumber: /^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$/im,
email: /^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/,
};
That did not help.
I am thinking it has to be the validation function, but I am staring at this thing and I can't see anything that sticks out:
_validate = props => {
const validationErrors = {
businessName: props.businessName ? '' : 'Is Required',
businessPhoneNumber:
props.businessPhoneNumber.length === 0 ||
regex.phoneNumber.test(props.businessPhoneNumber)
? ''
: 'Phone number must be valid and contain 10 digits',
};
const isValid = Object.keys(validationErrors).reduce((acc, curr) => {
if (validationErrors[curr] !== '') {
return false;
}
return acc;
}, true);
this.setState({validationErrors, displayErrors: !isValid});
return isValid;
};
UPDATE
I tried the solution in the below answer, but unfortunately that did not work.
Here is whats going on:
When I add the phone number and save it, it is in props here:
_validate = props => { and you can see that here:
{screenProps: undefined, navigation: {…}, businessName: "Ceramic Tile Distributors", businessWebsite: "", businessPhoneNumber: "8667073945", …}
but then it ceases to exist in the validationErrors object here:
const validationErrors = {
businessName: props.businessName ? "" : "Is Required",
businessPhoneNumber:
props.businessPhoneNumber.length === 0 ||
regex.phoneNumber.test(props.businessPhoneNumber)
? ""
: "Phone number must be valid and contain 10 digits"
};
and you can see that here:
{businessName: "", businessPhoneNumber: ""}
Why its re-rendering with the above as empty strings I do not know.
I can tell you that this here:
const isValid = Object.keys(validationErrors).reduce((acc, curr) => {
console.log("On line 84 of BusinessDetails: ", isValid);
if (validationErrors[acc] !== "") {
return false;
}
return acc;
}, true);
returns undefined, but why I do not know.
_validate is being used inside the _saveChanges function like so:
_saveChanges = () => {
const isValid = this._validate(this.props);
if (isValid) {
this.setState({ displaySpinner: true });
this.props
.updateInformation()
.then(() => {
this.setState({ displaySpinner: false }, () => {
this.props.navigation.goBack();
});
})
.catch(() => {
Alert.alert(
"Error",
this.props.businessPhoneNumber.length === 0
? "Please provide a business phone number. If your business phone number no longer exists, please call 1-800-NFIB-NOW to have this information deleted."
: "We couldn't save your changes. Please try again.",
[
{
text: "OK",
onPress: () => this.setState({ displaySpinner: false })
}
],
{ cancelable: false }
);
});
}
};
I can tell you that const isValid = this._validate(this.props); returns false.
When I test your code, it looks like there is no problem with your regex. But the below line is not correct
if (validationErrors[curr] !== '') {
return false;
}
You should use acc to get the values. consider the below code
if (validationErrors[acc] !== '') {
return false;
}
However, I can't run your code in my system. .reduce not working here. As a workaround, you can use below code
_validate = props => {
const validationErrors = {
businessName: props.businessName ? '' : 'Is Required',
businessPhoneNumber:
props.businessPhoneNumber.length === 0 ||
regex.phoneNumber.test(props.businessPhoneNumber)
? ''
: 'Phone number must be valid and contain 10 digits',
};
let isValid = true
Object.keys(validationErrors).map((acc, curr) => {
if (validationErrors[acc] !== '') {
isValid= false
}
});
this.setState({validationErrors, displayErrors: !isValid});
return isValid;
};