Validate delimiter separated values using JOI - validation

I have a use case where I need to validate a set of values separated by | .
I followed https://github.com/hapijs/joi/issues/570 but it throws a number of errors.
Is there any way I can do this?
Example- AA|BB|CC|DD
Now, I need to validate that all of the values (AA, BB, CC, DD) are strings.
I believe I can't use regex as it would validate just the first value.
Also, there are a number of other validations in my code, so I don't wish to loop the validation process.
Please let me know if I'm unclear. Thanks!

TL;DR:
const Joi = require('joi').extend(joi => ({
base: joi.array(),
coerce: (value, helpers) => ({
value: value.split ? value.split('|') : value,
}),
type: 'versionArray',
}))
The .extend function signature has changed since that comment was written; the name property has been removed and the CoerceFunction should return an object with value as the property.
> Joi.versionArray().validate('AA|BB|CC|DD')
{ value: [ 'AA', 'BB', 'CC', 'DD' ] }
> Joi.versionArray().validate('AA|BB,CC|DD')
{ value: [ 'AA', 'BB,CC', 'DD' ] }
From here on, you can use the .items(...) function to validate each of the strings in the returned array:
> const regex = new RegExp('^[a-zA-Z]+$') // every character must be a-z or A-Z
undefined
> Joi.versionArray().items(Joi.string().regex(regex)).validate('AA|BB|CC|DD')
{ value: [ 'AA', 'BB', 'CC', 'DD' ] }
> Joi.versionArray().items(Joi.string().regex(regex)).validate('AA|BB|CC|00')
{ value: [ 'AA', 'BB', 'CC', '00' ],
error:
{ ValidationError: "[3]" with value "00" fails to match the required pattern: /^[a-zA-Z]+$/ _original: 'AA|BB|CC|00', details: [ [Object] ] } }
> Joi.versionArray().items(Joi.string().regex(regex)).validate('AA|BB,CC|DD')
{ value: [ 'AA', 'BB,CC', 'DD' ],
error:
{ ValidationError: "[1]" with value "BB,CC" fails to match the required pattern: /^[a-zA-Z]+$/ _original: 'AA|BB,CC|DD', details: [ [Object] ] } }

Related

Laravel validation Form - Don't accept number into double quotes

I have this POST request:
{
"documentType": "1",
"metadata": []
}
And i have this validation rules:
const POST_RULES = [
'documentType' => 'required|int',
'metadata' => 'array',
];
The problem is:
I don't want accept this value of documentType ("1") because it's a string. Users of the application can send a string.
I need to accept only number (1, 2, 3, 4 etc ...) whitout double quotes.
It's possible to create rule for that ?
Thank's in advance,
In the POST request, send number without quotes
{
"documentType": 1,
"metadata": []
}
You required an INT, not a STRING.
Or, you can accept the "1" and then check if that is a number:
if (is_numeric($request->documentType)) {
// Do other stuff
return true
}

Use one of the two incoming observable stream to filter data in angular

I have the below code I have the formcontrol value (its a multicheckbox list), the values is an array of true/false, [true, false, true, true, ...]. This is one of the many lists
I also have the data list - collection of objects of structure {id: number, desc: string, disabled: boolean, selected: boolean}
I need to retrieve the id matching the true by matching index, and set an observable
I have the below code
valueChanged(e: any, name: string, key: string, valuesArray: string) {
this.hasChanged = true;
from(name).pipe(
debounceTime(200),
withLatestFrom(this[name].value), // this[name] is form array, gives [true, false, false,..]
mergeMap(values => forkJoin(
of(values),
this[valuesArray].find(val => val.name === name).data
)),
mergeMap(([values, data]) => {
flatMap((val, i) => val ? data[i].id : null),
filter(id => id !== null),
map(ids => {
this.selectedFilters[key] = ids;
switch (key) {
case 'groupId':
this.curGroup.next(ids);
break;
}
});
})
);
}
I need help on the line flatmap where I want to use values, for each of the value (true/false), if val[i] is true, include data[i].id in the output i want he id array of true values [1,2,4,5,..]. I get the error
Argument of type '([values, data]: [[string, unknown], unknown]) => void' is not assignable to parameter of type '(value: [[string, unknown], unknown], index: number) => ObservableInput'.
Type 'void' is not assignable to type 'ObservableInput'.ts(2345)
Need help on how to use solve this issue. Thanks in advance.

Chaining rxjs 6 observables with nested array

I have to do 3 dependent request to an API.
The first retreive an array of user id's.
The second have to iterate over the user id's array and for each retreive an array of project id's related to the user.
The third have to iterate over the project id's array and retreive data related to projects.
I want this kind of result:
[{'username': 'richard', projects: [{"id": 1, "name": "test"}]}, ...]
But i'm totally stuck with mergeMap, forkJoin etc..
The thing i have tried:
getUserTeamMembers(): Observable<any> {
return this.http.get(`${environment.serverUrl}/user/profil`).pipe(
mergeMap((teamUsers: any) =>
this.http.get(
`api/user/${teamUsers.data._id}/team`
)
),
mergeMap((teamUsers: any) =>
forkJoin(
...teamUsers.data.map((user: any) =>
this.http.get(`api/user/${user.id}`)
)
)
),
map((res: any) =>
res
.map((user: any) => {
if (user.data) {
return {
firstname: user.data.local.firstname,
lastname: user.data.local.lastname,
email: user.data.local.email,
projects: user.data.local.projects,
language: user.data.local.lang
};
}
})
.filter((user: any) => user !== undefined)
),
tap(t => console.log(t)),
catchError(err => throwError(err))
);}
I try so many things, but i have no clue where to populate my array of projects which is currently only contains id's, not data related:
[{'username': 'richard', projects: ['id1', 'id2']}, ...]
have made a similar example hope it clear the idea.
of course did't use http instead made it local using of
and stored the final result in an array called results
we have a source to get the list of all users, another source that given the user id it will return the list of this user's projects' ids projectList, and finally a source that give one project id will returns it's details(projcectsDetails)
let users = of([ 1, 2, 3 ])
let projectsList = (userId) => of([ userId, userId*2 ])
let projectsDetails = (projectId) => of({ id: projectId, details: `details about ${projectId}` })
let results = [];
users
.pipe(
tap(users => {
users.forEach(userId => results.push({ userId, projects: [] }));
return users
}),
switchMap(users => forkJoin(users.map(userId => projectsList(userId)))),
switchMap(projectsArray => forkJoin(
projectsArray.map(
oneProjectArray =>
forkJoin(oneProjectArray.map(projectId => projectsDetails(projectId)))
)
)
),
tap(projectDetailsArray => {
projectDetailsArray.forEach((projectsArray, index) =>{
results[index]['projects'] = [ ...projectsArray ]
})
})
)
.subscribe(() => console.warn('final',results))
explanation
1- initalize the result array from the given users
[
{ userId: X, projcts: [] },
{ userId: Y, projcts: [] },
....
]
2- for each give users we want the projects ids he/she has
so the first switchMap will return (in order)
[
[ 1, 2, 3, ...] project ids for the first user,
[ 8, 12, 63, ...] project ids for the second user,
...
]
3- in the second switchMap we iterate over the previous array
(which is an array that each item in it is an array of projects ids)
so we needed two forkJoin the outer will iterate over each array of projects ids(the big outer
array previously mentioned)
the inner one will iterate over each single project id and resolve it's observable value(which is the
project details)
4- finally in the tap process we have an array of array like the 2nd step but this time each
array has the projects details and not the projects ids
[
{ userId:1, projects: [ { id:1, details: 'details about 1' }, { id:2, details: 'details about 2' }]},
{ userId:2, projects: [ { id:2, details: 'details about 2' }, { id:4, details: 'details about 4' }]},
{ userId:3, projects: [ { id:3, details: 'details about 3' }, { id:6, details: 'details about 6' }]}
]

Filter an Array in an Observable

Here is an edited sample from learnrxjs. I want to filter the values in the type array. But thats not how it works: 'This condition will always return 'true' since the types 'string[]' and 'string' have no overlap.'
I am new to rxjs and cant figure out how to filter the array. Any advices? Is it possible?
const source = from([
{ name: 'Joe', age: 31, type: ['a', 'b'] },
{ name: 'Bob', age: 25, type: ['a'] }
]);
//filter out people with type b
const example = source.pipe(filter(person => person.type != 'a'));
//output: "People with type b: Bob"
const subscribe = example.subscribe(val => console.log(`Type a: ${val.name}`));
the filter() you are applying takes a function with signature T => boolean meaning that you will have to return a boolean true/false so it can filter out elements from the stream.
Your elements T are of type Object {name:string, age:number, type:array} so to filter on values in the type Array you will need to use the Array.indexOf prototype function:
source.pipe(filter(person => person.type.indexOf('b') == -1) // filter out people who have type b

Meteor SimpleSchema says random stuff is valid

I'm using aldeed:collection2 and aldeed:simple-schema packages. I want to validate a doc against the schema. My schema contains e.g. a string field with allowedValues array and an array of nested object, described with sub-schema. Like this:
...
type: {
type: String,
allowedValues: [ 'A', 'B', 'C' ],
defaultValue: 'A',
index: 1,
},
nestedStuff: {
type: [ new SimpleSchema(nestedStuffSchema.schema(Meteor, SimpleSchema)) ],
defaultValue: [],
},
...
I have a 'bad' doc which has e.g. "D" in type field and invalid nested array items.
At client I'm trying to:
Contacts.simpleSchema().namedContext().validate(badDoc);
and it returns true. SimpleSchema says the doc is valid even though its fields do not abide to schema.
Validating 'bad' type field individually also returns true.
What am I doing wrong? Why could SimpleSchema assume random stuff to be valid?
if you want to validate an array of strings you need to keep String inside [ ].See the below code it may help
type: {
type: [String],
allowedValues: [ 'A', 'B', 'C' ],
defaultValue: ['A'],
index: 1,
},
nestedStuff: {
type: [ new SimpleSchema(nestedStuffSchema.schema(Meteor,SimpleSchema)) ],
defaultValue: [],
},
Thanks

Resources