Nest js: How to received a dto field with array of predefined strings - nest

I have a dto which is called product and it has a field called units....which received array of strings and this strings are predefined.....
my valid strings are predefined in a array ...
let validItems = ['a', 'b', 'c', 'd', 'e']
the data I want to be accepted by my dto is ...
{
product_id: 1,
units: ['a', 'b', 'c']
}
{
product_id: 2,
units: ['c', 'e', 'd']
}
{
product_id: 3,
units: ['e', 'b', 'a']
}
my current dto(not requirement satisfied) is =>
export class Product {
#IsString({ message: 'Product id must be a string' })
product_id: string;
#IsArray({ message: 'unit must be array' })
#IsString({ each: true, message: 'must be a string' })
units: string[];
}
what will be my DTO in nest.js. As I am new to nest.js so kindly provide me some good docs for this decorators

😛 I tried a lot and found a way to solve this problem.
I spent quite some time on the swagger docs for an array of strings.
import { ApiProperty } from "#nestjs/swagger";
import { IsArray, IsString } from "class-validator";
export class MenuOptionsByNames {
#ApiProperty({ isArray: true, example: ["size_external_party"] })
#IsArray()
#IsString({ each: true, message: "Each item should be string" })
menu_names: Array<string>;
}

Related

Filter array based on a value in nested array with Ramda

I'm trying to learn Ramda, but I'm struggling with seemingly simple stuff. How would I write the filter and sort using Ramda's pipe?
const items = [
{ id: 1, subitems: [{name: 'Foo', price: 1000}]},
{ id: 2, subitems: [{name: 'Bar'}]},
{ id: 3, subitems: [{name: 'Foo', price: 500}]},
{ id: 4, subitems: [{name: 'Qux'}]},
]
const findFoo = value => value.name === 'Foo'
items
.filter(item => item.subitems.find(findFoo))
.sort((a, b) => a.subitems.find(findFoo).price > b.subitems.find(findFoo).price ? -1 : 1)
// [{ id: 3, subitems: [...] }, { id: 1, subitems: [...] })
I've tried something like this but it returns an empty array:
R.pipe(
R.filter(
R.compose(
R.path(['subitems']),
R.propEq('name', 'Foo')
)
),
// Todo: sorting...
)(items)
Ramda's sortBy may help here. You could just do the following:
const findFoo = pipe (prop ('subitems'), find (propEq ('name', 'Foo')))
const fn = pipe (
filter (findFoo),
sortBy (pipe (findFoo, prop ('price')))
)
const items = [{id: 1, subitems: [{name: 'Foo', price: 1000}]}, {id: 2, subitems: [{name: 'Bar'}]}, {id: 3, subitems: [{name: 'Foo', price: 500}]}, {id: 4, subitems: [{name: 'Qux'}]}]
console .log (fn (items))
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.28.0/ramda.min.js"></script>
<script> const {pipe, prop, find, propEq, filter, sortBy} = R </script>
Obviously if we tried, we could make this entirely point-free, and address the concerns about double-extracting the Foo subobject. Here's a working version that converts the elements into [fooSubObject, element] pairs (where the former may be nil), then runs a filter to collect the elements where the fooSubObject is not nil, sorts by their price, then unwraps the elements from the pairs.
const fn = pipe (
map (chain (pair) (pipe (prop ('subitems'), find (propEq ('name', 'Foo'))))),
pipe (filter (head), sortBy (pipe (head, prop ('price')))),
map (last)
)
const items = [{id: 1, subitems: [{name: 'Foo', price: 1000}]}, {id: 2, subitems: [{name: 'Bar'}]}, {id: 3, subitems: [{name: 'Foo', price: 500}]}, {id: 4, subitems: [{name: 'Qux'}]}]
console .log (fn (items))
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.28.0/ramda.min.js"></script>
<script> const {pipe, map, chain, pair, prop, find, propEq, filter, last, sortBy, head} = R</script>
But to my eyes, this is a horrible, unreadable mess. We can tame it a bit by extracting a helper taking a function to generate the gloss object we will need for filtering and sorting, and our main process function (that actually does the filtering and sorting) using the gloss function to create the [gloss, element] pairs as above, calling our process and then extracting the second element from each resulting pair. As per Ori Drori's answer, we'll name that function dsu. It might look like this:
const dsu = (gloss, process) =>
compose (map (last), process, map (chain (pair) (gloss)))
const fn = dsu (
pipe (prop ('subitems'), find (propEq ('name', 'Foo'))),
pipe (filter (head), sortBy (pipe (head, prop ('price'))))
)
const items = [{id: 1, subitems: [{name: 'Foo', price: 1000}]}, {id: 2, subitems: [{name: 'Bar'}]}, {id: 3, subitems: [{name: 'Foo', price: 500}]}, {id: 4, subitems: [{name: 'Qux'}]}]
console .log (fn (items))
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.28.0/ramda.min.js"></script>
<script> const {compose, map, last, chain, pair, pipe, prop, find, propEq, filter, head, sortBy} = R</script>
This is better, and maybe marginally acceptable. But I still prefer the first version above.
You can use a DSU sort:
Decorate - map the original array, and create a tuple with the price of the found item in the sub-array, or -Infinity if none, and the original object.
Sort by using the price (the 1st item in the tuple).
Undecorate - Map again an extract the original object.
const { pipe, propEq, find, map, applySpec, prop, propOr, identity, sortWith, descend, head, last } = R
const findItemByProp = pipe(propEq, find)
const dsu = (value) => pipe(
map(applySpec([ // decorate with the value of the item in the sub-array
pipe(
prop('subitems'), // get subitems
findItemByProp('name', value), // find an item with the name
propOr(-Infinity, 'price') // extract the price or use -Infinity as a fallback
),
identity // get the original item
])),
sortWith([descend(head)]), // sort using the decorative value
map(last) // get the original item
)
const items = [{"id":1,"subitems":[{"name":"Foo","price":1000}]},{"id":2,"subitems":[{"name":"Bar"}]},{"id":3,"subitems":[{"name":"Foo","price":500}]},{"id":4,"subitems":[{"name":"Qux"}]}]
const result = dsu('Foo')(items)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.28.0/ramda.min.js" integrity="sha512-t0vPcE8ynwIFovsylwUuLPIbdhDj6fav2prN9fEu/VYBupsmrmk9x43Hvnt+Mgn2h5YPSJOk7PMo9zIeGedD1A==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

Ramda reduce from array to object?

How can I switch from array to object data type in pipeline using ramda's reduce in point-free style?
I would like to achieve this:
(nodes) => nodes.reduce((acc, node: any) => {
acc[node.id] = {
out: node.outgoing_explicit,
in: node.incoming_explicit
};
return acc;
}, {})
Index the nodes by id, and the map them and use R.applySpec to change to the in/out format:
const { pipe, indexBy, map, applySpec, prop } = R
const fn = pipe(
indexBy(prop('id')),
map(applySpec({
out: prop('outgoing_explicit'),
in: prop('incoming_explicit'),
}))
)
const nodes = [{ id: 1, outgoing_explicit: 'abc1', incoming_explicit: 'xyz1' }, { id: 2, outgoing_explicit: 'abc2', incoming_explicit: 'xyz2' }, { id: 3, outgoing_explicit: 'abc3', incoming_explicit: 'xyz3' }]
const result = fn(nodes)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous"></script>
this could also be a solution:
const spec = {
in: R.prop('incoming_explicit'),
out: R.prop('outgoing_explicit'),
}
const fn = R.reduceBy(
R.flip(R.applySpec(spec)),
null,
R.prop('id'),
);
const data = [
{ id: 'a', incoming_explicit: 'Hello', outgoing_explicit: 'World' },
{ id: 'b', incoming_explicit: 'Hello', outgoing_explicit: 'Galaxy' },
{ id: 'c', incoming_explicit: 'Hello', outgoing_explicit: 'Universe' },
{ id: 'd', incoming_explicit: 'Hello', outgoing_explicit: 'Dimension' },
];
console.log(
fn(data),
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.js" integrity="sha512-3sdB9mAxNh2MIo6YkY05uY1qjkywAlDfCf5u1cSotv6k9CZUSyHVf4BJSpTYgla+YHLaHG8LUpqV7MHctlYzlw==" crossorigin="anonymous"></script>
The solutions involving applySpec are probably best, but just for variety, here's an alternative:
const convert = pipe (
map (juxt ([prop('id'), props(['incoming_explicit', 'outgoing_explicit'])])),
fromPairs,
map (zipObj (['in', 'out']))
)
const nodes = [{id: 'foo', outgoing_explicit: 43, incoming_explicit: 42}, {id: 'bar', outgoing_explicit: 20, incoming_explicit: 10}, {id: 'baz', outgoing_explicit: 309, incoming_explicit: 8675}]
console .log (convert (nodes))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js"></script>
<script>const {pipe, map, juxt, prop, props, fromPairs, zipObj} = R </script>
`juxt' is a bit of an oddball function. It works like this:
juxt([f, g, h, ...]) //=> (a, b, ...) -> [f(a, b, ...), g(a, b, ...), h(a, b, ...), ...]

Joi validate array of objects with when condition

First of all, sorry for bad English.
I can't find any docs about this.
WHAT I WANT TO DO
const docs = {
type: 'a', // ['a',' 'b', 'c'] is available.
items: [
{
a: 123,
b: 100 // => This value only available when type is 'a' or 'b'. otherwise, forbidden.
}
]
};
MY JOI SCHEMA(NOT WORKED)
Joi.object({
type: Joi.string().valid('a', 'b', 'c').required(),
items: Joi.array()
.items(
Joi.object({
a: Joi.number().required()
b: Joi.number()
})
)
.when('type', {
is: Joi.string().valid('a', 'b'),
then: Joi.array().items(Joi.object({ b: Joi.number().required() })),
otherwise: Joi.array().items(Joi.object({ b: Joi.number().forbidden() }))
})
})
This code is not working correctly.
When type is 'c', it validate passed.
How can I fix this?
You have added .items() to items: Joi.array() which overrides the .when() condition, try using
Joi.object({
type: Joi.string().valid('a', 'b', 'c').required(),
items: Joi.array()
.when('type', {
is: Joi.string().valid('a', 'b'),
then: Joi.array().items(Joi.object({
a: Joi.number().required(),
b: Joi.number().required()
})),
otherwise: Joi.array().items(Joi.object({
a: Joi.number().required()
}))
})
})
example

Vue - how to add reactive properties to objects in an array of objects?

I have an array of objects coming from the backend. I need to add additional data onto each object, to send.
My data coming in looks like this:
let arr = [
{
id: 1,
city: 'Orlando',
},
{
id: 2,
city: 'Miami',
},
{
id: 3,
city: 'Portland',
}
]
When the data comes loaded in through Vue, I need to have those properties be reactive. Meaning vue can see when those values change and call the appropiate lifecycle methods. See https://v2.vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats
let newArr = [
{
id: 1,
city: 'Orlando',
state: 'Fl',
country: 'USA',
},
{
id: 2,
city: 'Miami',
state: 'Fl',
country: 'USA',
},
{
id: 3,
city: 'Portland',
state: 'OR',
country: 'USA',
}
]
You can't just loop through and append properties to each object normally in vanillaJS, so how would you do this?
The vue docs suggests to use Object.assign when appending properties to make them reactive
// instead of `Object.assign(this.someObject, { a: 1, b: 2 })`
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })
But, this is only if you have to append one object.
For a list of objects, this is how you would initialize the data
newArr = arr.map(item => {
let newItem = Object.assign({}, item, {
state: undefined,
country: undefined,
});
return newItem;
});
Now all your objects properties in the array of objects are reactive
Vue also intercepts calls to Array.push, so you may like this better:
arr.forEach(item => newArr.push(item))
Quite late but thought of providing the answer as it can be useful to someone else in the future:
If you would like to add an additional property to a certain object within an array of objects then you can use something like this:
var searchId = 1
const cityInfo = arr.find(ele => ele.id === searchId)
Vue.set(identifiersNode, 'state', "Karnataka")
Vue.set(identifiersNode, 'country', "India")

Ramda: Is there a way to find particular key value is nested object?

I want to find particular key value is nested object or not.
{
'a': {
'area': 'abc'
},
'b': {
'area': {
'city': 'aaaa',
'state': 'ggggg'
}
}
}
In above example, I want to find 'a' and 'b' is object or nested object?
If you want to know whether all keys in the object contain nested objects then one possible solution is to convert all of the values of the object to boolean values using R.map and R.propSatisfies, representing whether the nested property was an object or not.
const fn = R.map(R.propSatisfies(R.is(Object), 'area'))
const example = {
'a': {
'area': 'abc'
},
'b': {
'area': {
'city': 'aaaa',
'state': 'ggggg'
}
}
}
console.log(fn(example))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
If you just want to know whether a specific key of an object contains a nested object, then you can do so with a composition of R.prop and R.propSatisfies.
const fn = R.pipe(R.prop, R.propSatisfies(R.is(Object), 'area'))
const example = {
'a': {
'area': 'abc'
},
'b': {
'area': {
'city': 'aaaa',
'state': 'ggggg'
}
}
}
console.log('a:', fn('a', example))
console.log('b:', fn('b', example))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>