error: invalid input syntax for integer: when passing strings - node.js

I have the following function in node.js that makes a query to postgres based based on name_url. Sometimes it works and sometimes it just doesn't work.
Also I'm using lib pg-promise:
exports.getLawyerByUrlName = function (name_url, callback) {
console.log(typeof name_url) //NOTICE: output string
db.one({
text: "SELECT * FROM " + lawyersTable + " WHERE name_url LIKE $1::varchar",
values: name_url,
name: "get-lawyer-by-name_url"
})
.then(function (lawyer) {
callback(lawyer);
})
.catch(function (err) {
console.log("getLawyerByUrlName() " + err)
});
}
When it does not work it throws error:
getLawyerByUrlName() error: invalid input syntax for integer: "roberto-guzman-barquero"
This is a very weird bug I can't seem to catch why its happening. I'm checking before in console.log that I'm actually passing a string:
console.log(typeof name_url) //NOTICE: output string
My table field for name_url is:
CREATE TABLE lawyers(
...
name_url VARCHAR check(translate(name_url, 'abcdefghijklmnopqrstuvwxyz-', '') = '') NOT NULL UNIQUE,

It seems to be unlikely that that particular query could ever throw that error so I'll suggest three possibilities. The first is that the code that's causing the error is actually someplace else and that:
.catch(function (err) {
console.log("getLawyerByUrlName() " + err)
was cut and pasted into a different part of the code.
The 2nd possibility is that the "lawersTable" variable is getting populated with something unexpected.
The 3rd possibility is that my first two scenarios are wrong. ;-)

Related

Cannot convert object to primitive value when attempting to run word count on array created from Firebase records

I am trying to write a node js program that reads values from a Firebase database and aggregates all the words in a specific field for all the
records, but I am getting the below errors ..
[2019-06-24T14:52:14.083Z] #firebase/database: FIREBASE WARNING: Exception was thrown by user callback. TypeError: Cannot convert object to primitive value at C:\Users\xxx\Projects\NodeProjects\QuestionAppNode\index.js:52:38
TypeError: Cannot convert object to primitive value
Below is my node.js code ..
retrieveQuestions();
function retrieveQuestions(){
userQuestionsFBRef.once("value", function(snapshot) {
var fetchedQuestions = [];
snapshot.forEach(function(snapshotChild){
var itemVal = snapshotChild.val();
fetchedQuestions.push(itemVal);
})
var arrayOfQuestions = [];
fetchedQuestions.forEach(function(question){
arrayOfQuestions += question.question
})
console.log("Fetched questions are " + JSON.stringify(fetchedQuestions));
console.log("arrayOfQuestions is " +JSON.stringify(arrayOfQuestions));
var wordcnt = arrayOfQuestions.replace(/[^\w\s]/g, "").split(/\s+/).reduce(function(map, word){
map[word] = (map[word]||0)+1;
return map;
}, Object.create(null));
console.log("Word count is " + wordcnt)
}, function (errorObject) {
console.log("The read failed: " + errorObject.code);
});
}
The similar code does work if I run it in Chrome console i.e.
var arrayOfQuestions = [{"dateTime":"2019-06-24T14:06:36.983Z","name":"AMA09","question":"Who let the dogs out?"},{"dateTime":"2019-06-24T14:07:11.501Z","name":"AMA09","question":"What is the capital of Senegal?"},{"dateTime":"2019-06-24T14:20:25.222Z","name":"AMA34","question":"Is Free will an illusion?"}];
var newArray = [];
arrayOfQuestions.forEach(question => newArray += question.question);
var wordcnt = newArray.replace(/[^\w\s]/g, "").split(/\s+/).reduce(function(map, word){
map[word] = (map[word]||0)+1;
return map;
}, Object.create(null));
Does anyone have any idea why this is happening?
I realise that the approach I am taking to aggregate the words in these records is probably not the correct way to go i.e. adding all the text in the
question field of the fb records is probably a bit stupid and wouldn't work for large datasets so if someone could offer any suggestions on a
different approach that would be appreciated as well.
Many thanks.
The problem appears to be this line:
console.log("Word count is " + wordcnt)
Since wordcnt is an object without a prototype, that is, Object.create(null), it has no toString method, hence the error "TypeError: Cannot convert object to primitive value".
Solution 1 - Use object literal syntax in your reduce expression:
var wordcnt = arrayOfQuestions
.replace(/[^\w\s]/g, "")
.split(/\s+/)
.reduce(function(map, word){
map[word] = (map[word]||0)+1;
return map;
}, {}); // Object literal instead of Object.create(null)
This creates an object with the usual Object prototype, which has a toString method.
Solution 2 - Don't concatenate in console.log but rather use multiple arguments:
console.log("Word count is", wordcnt) // instead of " + wordcnt)
This allows console.log to do its normal stringifying of objects.
Solution 3 - Convert the wordcnt map to a json string.
console.log("Word count is " + JSON.stringify(wordcnt))
This converts your object to a JSON representation of itself.

If statements not working with JSON array

I have a JSON file of 2 discord client IDs `{
{
"premium": [
"a random string of numbers that is a client id",
"a random string of numbers that is a client id"
]
}
I have tried to access these client IDs to do things in the program using a for loop + if statement:
for(i in premium.premium){
if(premium.premium[i] === msg.author.id){
//do some stuff
}else{
//do some stuff
When the program is ran, it runs the for loop and goes to the else first and runs the code in there (not supposed to happen), then runs the code in the if twice. But there are only 2 client IDs and the for loop has ran 3 times, and the first time it runs it goes instantly to the else even though the person who sent the message has their client ID in the JSON file.
How can I fix this? Any help is greatly appreciated.
You may want to add a return statement within your for loop. Otherwise, the loop will continue running until a condition has been met, or it has nothing else to loop over. See the documentation on for loops here.
For example, here it is without return statements:
const json = {
"premium": [
"aaa-1",
"bbb-1"
]
}
for (i in json.premium) {
if (json.premium[i] === "aaa-1") {
console.log("this is aaa-1!!!!")
} else {
console.log("this is not what you're looking for-1...")
}
}
And here it is with return statements:
const json = {
"premium": [
"aaa-2",
"bbb-2"
]
}
function loopOverJson() {
for (i in json.premium) {
if (json.premium[i] === "aaa-2") {
console.log("this is aaa-2!!!!")
return
} else {
console.log("this is not what you're looking for-2...")
return
}
}
}
loopOverJson()
Note: without wrapping the above in a function, the console will show: "Syntax Error: Illegal return statement."
for(i in premium.premium){
if(premium.premium[i] === msg.author.id){
//do some stuff
} else{
//do some stuff
}
}
1) It will loop through all your premium.premium entries. If there are 3 entries it will execute three times. You could use a break statement if you want to exit the loop once a match is found.
2) You should check the type of your msg.author.id. Since you are using the strict comparison operator === it will evaluate to false if your msg.author.id is an integer since you are comparing to a string (based on your provided json).
Use implicit casting: if (premium.premium[i] == msg.author.id)
Use explicit casting: if (premium.premium[i] === String(msg.author.id))
The really fun and easy way to solve problems like this is to use the built-in Array methods like map, reduce or filter. Then you don't have to worry about your iterator values.
eg.
const doSomethingAuthorRelated = (el) => console.log(el, 'whoohoo!');
const authors = premiums
.filter((el) => el === msg.author.id)
.map(doSomethingAuthorRelated);
As John Lonowski points out in the comment link, using for ... in for JavaScript arrays is not reliable, because its designed to iterate over Object properties, so you can't be really sure what its iterating on, unless you've clearly defined the data and are working in an environment where you know no other library has mucked with the Array object.

How to abstract null/undefined checking with Flow?

sessionStorage.getItem() is treated as Maybe/Optional type by Flow. So the following is necessary to make the result usable as a string type that is not of Optional type or of Maybe type:
const accessToken1 = sessionStorage.getItem('accessToken')
if (!accessToken1) throw new Error('Unwrapping not possible because the variable is null or undefined!')
'Hello ' + accessToken1 // no complaints by Flow
Now I want to abstract the null/undefined checking, but Flow does not stop complaining about the possible null and undefined types:
function unwrap<T>(value: T): T {
if (!value) throw new Error('Unwrapping not possible because the variable is null or undefined!')
return value // at this point Flow should understand it cannot be of type Optional or Maybe
}
'Hello ' + unwrap('World!') // works
'Hello ' + unwrap(null) // complains as expected with "null This type cannot be added to string"
'Hello ' + unwrap(undefined) // complains as expected with "null This type cannot be added to string"
const nullString = 'null'
'Hello ' + unwrap(nullString) // works
const accessToken2 = sessionStorage.getItem('accessToken')
'Hello ' + unwrap(accessToken2) // null/undefined This type cannot be added to string
const accessToken3 = (sessionStorage.getItem('accessToken'): string) // null/undefined This type cannot be added to string
'Hello ' + unwrap(accessToken3) // no complaints by Flow
Your return type is widening the refinement back to its original type. Try
function unwrap<T>(value: ?T): T { // Note the `?T`
if (!value) throw new Error('Unwrapping not possible because the variable is null or undefined!')
return value // at this point Flow should understand it cannot be of type Optional or Maybe
}
Some of your comments seem misguided. Here are the necessary corrections that I see:
'Hello ' + unwrap(null) // Not an error (I've opted for runtime errors with my `throw`)
'Hello ' + unwrap(undefined) // Not an error (I've opted for runtime errors with my `throw`)

LokiJS - remove and findAndRemove do not work (saveDatabase not saving)

I'm using LokiJS and it's fine for most parts. Except that I can't seem to delete a record from the database.
The find gets me the right record to delete, but neither remove() not findAndRemove() remove it after saveDatabase. What am I doing wrong?
(Note: I've tried saveDatabase outside the loadDatabase(...) callback - no change. whenever I re-run it, the record I thought I deleted is still there)
Here's the code: dbName is a valid path to the file
var db = new loki(dbName);
db.loadDatabase({}, function (e) {
var orders = db.getCollection("orders");
console.log(orders.count() + " orders found... iterating");
orders.find().forEach((v, i) => {
console.log(i + "." + v.key + " " + v.places.display + " " + v.theme + " " + moment(v.date).format("DD MMM YYYY HH:mm"));
});
}
let dKey = "some key that is valid";
if (!dKey) {
console.log("no key specified, returning");
return;
}
console.log("deleting specific record " + dKey);
let dObj = orders.find({ key: dKey });
if (!dObj || dObj.length == 0) {
console.log("no such record, returning");
return;
}
console.log(dObj[0]);
orders.remove(dObj[0]);
db.saveDatabase((e) => {
console.log("save complete");
});
}
});
Try: orders.chain().find({ key: dKey }).remove()
I faced the same issue while working with lokijs, so putting it here so that it can help anyone else looking for the same issue in future.
I was trying to lookup a record in db with a particular $loki value, but I was getting an empty ResultSet. Then I tried this.
data.chain().find({"$loki":{$aeq:serial}}).remove().data().
Here, data is my db instance and serial is the $loki value I was looking for and passing to find().
It seems like lokijs stores them as strings thats why $aeq worked and I was able to find and delete the required record

named parameter binding with sql-wildcard not working

I'm using the node-sqlite3 package to access my db.
I'm trying to get rows from a Clients table with this code:
var st = db.prepare("SELECT * FROM Clients where name LIKE '%$name%'");
st.all({ $name: "test" }, function (err, rows) {
console.log("this: " + JSON.stringify(this));
if (err)
console.log(err);
else {
console.log("found: " + JSON.stringify(rows));
}
});
Output of err is this:
{ [Error: SQLITE_RANGE: bind or column index out of range] errno: 25, code: 'SQLITE_RANGE' }
The query works and doesn't throw errors when I change the sql to SELECT * FROM Clients where name LIKE '%$name%'. So I guess the problem is, that node-sqlite3 tries to find a variable called $name% or something like that in the object passed as first parameter to Statement#all.
I've searched the API doc for more hints about this, but couldn't find any.
Do I need to escape something? How do I get my query to work with named binding and the sql wildcards %?
This is not the way bindings work.
You can have
SELECT * FROM Clients where name LIKE $name
and
var name = "%"+"test"+"%";
..
{ $name: name }
bound variables are negociated with the backend database as a "whole" variable and you should not confuse this with variable replacement.
you should also be able to use the concatenate function of sqlite (not tested) :
SELECT * FROM Clients where name LIKE '%'||$name||'%'
..
{ $name: test }

Resources