Using chain validation to check existence of optional fields with Express Validator - node.js

I am trying to check for the existence of an optional field in an API request, and if that field exists, perform a nested validation to check if two other fields (one or the other, or implicitly both) exist inside of it. I am using Express Validator to try and accomplish this task.
// Sample request body
{
<...>
thresholds: {
min: 3,
max: 5
}
}
// (Attempted) validation chain
check('thresholds').optional()
.custom( innerBody => {
console.log('THRESHOLDS', innerBody);
oneOf([
check('innerBody.min').optional(),
check('innerBody.max').optional()
]);
})
The above snippet is part of a larger validation chain I'm validating the full request body on. I also tried removing the innerBody. string from the inner checks but still no luck. I am console.loging the threshold body, and it prints out correctly, however I still get a validation error, when I'm trying to get my integration test to pass:
{"name":"ValidationError","message":"ValidationError: Validation failed","errors":[{"location":"body","param":"thresholds","value":{"min":3,"max":5},"msg":"Invalid value"}]}
I am relatively new to Express Validator so if I'm chaining the validation wrong/not using oneOf correctly or something would love some pointers!
Thanks

Looks like the .custom function needs to return a Promise. Answer below:
.custom(innerBody => {
if (!(innerBody.min) || !(innerBody.max)) return Promise.reject('Missing min or max');
return Promise.resolve();
})

Remember: Always return a boolean value from the callback of .custom()
function. Otherwise your validation might not work as desired.
Source: Custom validation guide
In general, you might have needs in use of Promises if you deal with asynchronous .custom() function. Then you'll be obligated to return Promise.resolve() / Promise.reject() for correct validator behaviour.
Source: SO answer

Related

Getting children of an element in Puppeteer: element.children.length works but element.children returns undefined

I have this code snippet:
const historicalDataTable = await findElementByClass(
"table",
elementClass,
page
); // This is a custom function I wrote. Works as expected.
const tableBody = await historicalDataTable.$eval(
"tbody",
(el) => el.children.length
);
console.log(tableBody);
This works as expected and returns the correct amount of children. However when I do
const tableBody = await historicalDataTable.$eval(
"tbody",
(el) => el.children
);
And remove the length, it returns undefined. What is going on here?
el.children (Element#children) will yield an HTMLCollection which is not serializable and can't be marshalled from the page's execution context into yours, so evaluate returns undefined instead.
Now, this isn't fully obvious when looking at the elementHandle.$eval docs as the only indication is that the return value is <Promise<Serializable>>, but it becomes clear from the executionContext.evaluate docs:
returns: <Promise<Serializable>> Promise which resolves to the return value of pageFunction
[...]
If the function passed to the executionContext.evaluate returns a non-Serializable value, then executionContext.evaluate resolves to undefined. DevTools Protocol also supports transferring some additional values that are not serializable by JSON: -0, NaN, Infinity, -Infinity, and bigint literals.
(Emphasis mine.)
el.children.length (HTMLCollection#length) on the other hand is a simple number which is serializable.
You have to do whatever you want to do with those elements inside of your pageFunction and return only some serializable value.
Alternatively, you could also use elementHandle.evaluateHandle to return a JSHandle to the HTMLCollection and use that handle later in another call to an evaluate-type function. (Note that that would be the only thing you can do with it though. You couldn't access .length for example from your own execution context, only from another pageFunction1.)
1: This is not entirely true, since you could for example use jsHandle.getProperty to get another JSHandle for the length, followed by jsHandle.jsonValue to get the value as number - but both of these operations are asynchronous and probably it's a lot more efficient to write your code in such a way that you can handle all the necessary operations inside the page's execution context in the first place, without too many context switches.

How to pass nested data structures as properties in LitElement?

In a parent component I have something like:
render() => {
const data = {a:1,b:[1,2,3]}; // of course this is a simplified version of the code
return html`<child-component data=${data}></child-component>`
}
Which is basically equivalent to:
render() => {
const data = {a:1,b:[1,2,3]}; // of course this is a simplified version of the code
return html`<child-component data="[object Object]"></child-component>`
}
Which is basically useless...
Is there a simple way to pass complex object hierarchies into litElement components?
As far as I can tell, my options are:
Option 1. Use attributes: I'm a bit of a litElement noob so I'm not sure if this will work and I'm not sure how to make it work without having to make extra function calls. It would be nice if I could just do all the necessary work inside html.
Research in progress.
Option 2. Use Json.
Stringify the object in the parent component
render() => {
const data = {a:1,b:[1,2,3]}; // of course this is a simplified version of the code
return html`<child-component data=${JSON.stringify(data)}></child-component>`
}
then parse the json in the child component.
This just seems a bit inelegant to me though.
But it works.
In this case what you probably want is to pass the object as a property rather than as an attribute. For complex data such as objects, arrays, functions, etc. that's the preferred method.
You can do it with the following syntax:
render() => {
const data = {a:1,b:[1,2,3]};
// note the period (.), that's the token used to identify that you're passing data as a property
return html`<child-component .data=${data}></child-component>`
}
In general, you should probably give Lit's templating guide a read as some of the most common use cases are covered throughout it.

NodeJS (gettting error notes.push is not a function)

When I run this code I get push is not a function. I have gone over the code so many times and can't figure out where I went wrong. i have also read many of post and I still can't figure it out. I am new to programming and could use the help.
const fs= require('fs')
const getNotes = function() {
    return 'This just returns get notes'
        
enter code here
};
const addNote  = function (title, body) {
    const notes = loadNotes()
    
    notes.push({
        title: title,
        boby: body
    })
    saveNotes(notes)
    
};
const saveNotes = function (notes) {
    const dataJSON = JSON.stringify(notes)
    fs.writeFileSync('notes.json',dataJSON)
}
// Code below loads the notes. Above, addNote adds the note.
const loadNotes = function () {
    try {
        const dataBuffer = fs.readFileSync('notes.json')
        const dataJSON= dataBuffer.toString()
        return JSON.parse(dataJSON)
    } catch (error) {
        return('Note such file')
    }
    
    
}
module.exports ={
    getNotes: getNotes,
    addNote: addNote
}
So, you have this:
const notes = loadNotes()
notes.push({
title: title,
boby: body
});
If you're getting an error that notes.push is not a function, then that is because loadNotes() is not return an array. That could be for a couple reasons:
JSON.parse(dataJson) successfully parses your json, but its top level object is not an array.
JSON.parse(dataJson) throws and you end up returning a string instead of an array.
You can fairly easily diagnose this by adding a console.log() statement like this:
const notes = loadNotes();
console.log(notes); // see what this shows
notes.push({
title: title,
boby: body
});
FYI, returning a string fromloadNotes()as an error really doesn't make much sense unless you're going to check for a string after calling that function. IMO, it would make more sense to either return null for an error or just let it throw. Both would be simpler and easier to check after calling loadNotes().
And, in either case, you must check for an error return value after calling loadNotes() unless you want loadNotes() to throw upon error like it is.

Making Mongoose/MongoDB query helper plugin return zero results

I'm developing a Mongoose Query Helper plugin that provides the chainable method .search(query). On certain conditions, I want the query to return zero results, no matter how the other methods in the query builder chain behave. Turns out this isn't so easy as I have assumed.
Basically, I have the following code:
schema.query.search = function search(query) {
if ("query is invalid") {
// return no results => no easy way to achieve that?
}
return this.find(query);
};
Now, I want SomeModel.find({}).search(someQuery).exec() to return no results in case the query is invalid. I first tried to return this.limit(0), but turns out a limit of 0 is equivalent to setting no limit.
As a temporary solution, I do return this.find({ nonExistingField: 'something' }) which always results in no results, but this does seem a bit awkward and is probably also not so optimal in terms of performance as it triggers a search when no search is needed.
Thanks in advance for your help!

How does pluck hook work in feathersjs

In the feathersjs docs the explanation provided is as follows:
pluck discards all fields except for the specified ones, either from
the data submitted or from the result. If the data is an array or a
paginated find result the hook will remove the field(s) for every
item.
import _pluck from '../common/_pluck';
import checkContextIf from './check-context-if';
import getItems from './get-items';
import replaceItems from './replace-items';
export default function (...fieldNames) {
return context => {
checkContextIf(context, 'before', ['create', 'update', 'patch'], 'pluck');
if(context.params.provider) {
replaceItems(context, _pluck(getItems(context), fieldNames));
}
return context;
};
}
The getItems utility returns the items in either hook.data or
hook.result depending on whether the hook is being used as a before or
after hook. hook.result.data or hook.result is returned for a find
method.
The returned items are always an array to simplify further processing.
The replaceItems utility is the reverse of getItems , returning the
items where they came from.
My question relates to the checkContextIf function. This function prevents the pluck hook from being called except before the create,update and patch methods. How then does the pluck hook work on the results of the query. Are not the results produced after the service call and handled in an after hook?
As the documentation states:
The getItems utility returns the items in either hook.data or hook.result depending on whether the hook is being used as a before or after hook.
hook.data is the data (body) sent with a create, patch or update request so it can be used to omit fields that you do not want to be saved to the database. This is also documented in the hooks API:
data - The request data (for create, update and patch)

Resources