returning sqlite3 query in Node - sql

I'm trying to write a function that returns a query from a sqlite3 database (using Node and Express)
This is how (likely) the function is called
app.get('/example',(req,res)=>{
console.log(getThings(db_connection))
}
And this is the function per se
getThings(db){
let sql = 'SELECT * FROM Table'
let results[]
db.all(sql, (err, rows) => {
if(err){throw err}
let i
for(i=0;i<rows.length;i++){
res.push(rows[i])
}
console.log(res)
})
return res
}
I expected the rows being returned at the end, but it always returns res before populating it first, and just then it prints res with the correctly
I might have understood why it does so, but I have no idea how to fix it properly (I'm still new at JS)

Callbacks are asynchronous, so res will not be populated before the return.
You need to make your callback into a Promise or use async/await.
Promisify the callback:
getThings(db){
return new Promise((resolve, reject) => {
db.all('SELECT * FROM Table', (err, rows) => {
if (err) reject(err)
resolve(rows)
})
})
}
app.get('/example', (req, res) => {
getThings(db_connection)
.then(rows => res.send(result))
.catch(err => res.send({
error: err.message
}))
}
or
Use async/await:
Wrapped in try/catch to catch err, then because you're simply looping over the rows you don't need the for loop.
When you see the following structure object.method('param', (err, rows) => { you can almost guarantee its Promise compatible, else if not you can use util.promisify(original) to make it so.
Cleaner and more verbose then then().catch() chaining:
app.get('/example', async (req, res) => {
let result = {}
try {
result = await getThings(db_connection)
} catch (err) {
result = {
error: err.message
}
}
res.send(result)
}
async getThings(db) {
return db.all('SELECT * FROM Table')
}

Related

Node Postgres Multiple Queries

I have a query:
const getRunsByProjectTable = {
text: 'Select pvt(); Execute pvtstmt;'
} ;
const getRunsByProjectTable = (req, res) => {
pool.query(queries.getRunsByProjectTable, (error, results) => {
if (error) throw error;
res.status(200).json(results.rows);
})
}
It does not return anything but on pgAdmin, I am getting the desired table. Does anyone know what the problem may be?

Pouch Couch DB error when sync and replicate

I am currently having a problem trying to sync or replicate the data from PouchDB to CouchDB. Whenever I try to sync or replicate I always get this error.
Cannot read properties of undefined (reading 'from').
Here is my code:
function openDB() {
return new PouchDB('cows.db', { adapter: 'react-native-sqlite' });
}
function openRemoteDB() {
return new PouchDB('http://admin:asdasd#127.0.0.1:5984/cows');
}
const runPouchDB = async () => {
const db = openDB();
console.log('db info:', await db.info());
const remotedb = openRemoteDB();
console.log('remote db info:', await remotedb.info());
db.replicate.to(remotedb, {})
.on('complete', async () => {
console.log('done!');
})
.on('error', function (err) {
console.error('failed to replicate:', err.message, err.stack);
});
db.sync(remotedb).on('complete', function () {
console.log('done');
// yay, we're in sync!
}).on('error', function (err) {
console.log('error', err);
// boo, we hit an error!
});
}
React.useEffect(() => {
runPouchDB().then(() => console.log('connected'));
}, [])
both approach always return an error. Not sure if it is a package issue or something I did wrong.
UPDATE:
Based on the example it is looking for global.base64FromArrayBuffer but base64FromArrayBuffer does not exist in my global context.
https://github.com/craftzdog/pouchdb-react-native/blob/138f3d6385238e5cf278366d0fb3d0434abbdced/example/src/App.js#L71
Not sure how to add since since I already added the shim which I though would fix the issue.
import { shim as shimBase64 } from 'react-native-quick-base64';
shimBase64();

Callback function 'next' is executed automatically without making a call to it

I have this POST method which uses FetchURL middleware to fetch data from the url submitted by the user.
router.post('/', FetchURL, (req, res) => {
console.info('data received');
...
})
Everything works with response.ok being true, but the contrary case doesn't quite work as expected.
I don't want next to be called when response.ok equals false.
But I get to see "data received" logged to the console which means the next function does get called on its own.
fetch_url.js
function FetchURL(req, res, next) {
fetch(req.body.input_url)
.then(response => {
if(response.ok)
return response.json();
// else render error message on the client machine
res.status(response.status)
.render('index', {
errStatus: [response.status, response.statusText]
});
/* Throwing an Error here is the only way I could prevent the next callback */
// throw new Error(`Request failed with status code ${response.status}.`);
})
.then(data => {
req.data = data;
next();
})
.catch(err => console.error(err));
}
I could not find anything relevant on the documentation of expressjs middleware. The only way I could prevent next from being called is by throwing an Error on the server.
What happens behind the scene here?
try making a second check before next is called like following
function FetchURL(req, res, next) {
fetch(req.body.input_url)
.then(response => {
if(response.ok) // wrap your response in a temporary object.
return { fail: false, data: response.json() } ;
// else render error message on the client machine
res.status(response.status)
.render('index', {
errStatus: [response.status, response.statusText]
});
/* Instead of throwing an Error, return something indicating error */
return { fail: true };
})
.then(data => {
// check if previous procedure has failed.
if(!data.fail) {
req.data = data.data;
next();
}
})
.catch(err => console.error(err));
}

Express Middleware Setting Header Error

I'm trying to implementation a fairly simple middleware function to my Express application that just adds a useCache value to the request object being passed to the main handler but for some reason, I'm getting a Can't set headers after they were sent error.
const cacheControl = (req, res, next) => {
if (lastPulled === null) lastPulled = Date().getDay()
req.useCache = Date().getDay() === lastPulled
next()
}
app.use(cacheControl)
app.get('/missions', (req, res) => {
if (req.useCache) res.status(200).json({ result: cache })
fetch(dumpUrl)
.then(data => data.text())
.then(result => {
cache = result
res.status(200).json({ result })
})
.catch(e => res.status(500).json({ result: e.message }))
})
I've read that most of the time if the error is produced by the middleware it is due to multiple next() calls, but that doesn't apply here, unless I'm missing something obvious.
When I remove the cacheControl middleware from the application, there is no longer an error, but I can't figure out what in the function is causing the error! Any pointers are helpful!
I'm guessing it's because res.json() is firing twice:
app.get('/missions', (req, res) => {
if (req.useCache) res.status(200).json({ result: cache })
fetch(dumpUrl)
.then(data => data.text())
.then(result => {
cache = result
res.status(200).json({ result })
})
.catch(e => res.status(500).json({ result: e.message }))
})
// if res.useCase is true, set headers and reply
if (req.useCache) res.status(200).json({ result: cache })
// then fetch and reply again (which generates the error)
fetch(dumpUrl)
.then(data => data.text())
.then(result => {
cache = result
res.status(200).json({ result })
Change it to this to utilize explicit return
app.get('/missions', (req, res) => {
if (req.useCache) return res.status(200).json({ result: cache })
return fetch(dumpUrl)
.then(data => data.text())
.then(result => {
cache = result
res.status(200).json({ result })
})
.catch(e => res.status(500).json({ result: e.message }))
})
The nature of the error is similar to when you do this:
problem
function problem() {
if (true === true) console.log('send problem')
console.log('send garbage by accident')
}
console.log(problem())
solution
function solution() {
if (true === true) return console.log('send solution')
return console.log('send nothing')
}
console.log(solution())
return is how you exit a function. Your issue is that your code was checking the if condition, but then continuing past it because it wasn't told to stop once it found that condition.
The old way or less terse way to write your function would be like:
app.get('/missions', (req, res) => {
if (req.useCache) {
res.status(200).json({ result: cache })
} else {
fetch(dumpUrl)
.then(data => data.text())
.then(result => {
cache = result
res.status(200).json({ result })
})
.catch(e => res.status(500).json({ result: e.message }))
}
})
Without the else in there, it executes every if statement it comes across until it reaches the end of the function, unless you use the return keyword as the cue to exit right there.
Keep in mind, using return inside a .then() function will resolve the promise, it won't exit from the upper scope if there are more .then()s chained on.

Return list from Graphql resolve

fetchFriends: {
type: new GraphQLList(UserType),
args: {
currentId: { type: new GraphQLNonNull(GraphQLID) }
},
resolve: (_, {currentId}) => {
return Promise.resolve()
.then(() => {
User.findById(currentId, (err, users) => {
users.getFriends((err, user) => {
console.log(user);
return user;
});
});
})
}
/* another version what i tried that returns only the initial findById user
resolve: (_, {currentId}) => {
var value = User.findById(currentId, (err, user) => {
new Promise((resolve, reject) => {
user.getFriends((err, user) => {
console.log('fetch: ', user);
err ? reject(err) : resolve(user)
});
})
})
return value;
}*/
},
I have a graphql resolve that i am getting the User object within the findById callback. that specific object calls getFriends which is a part of a mongoose plugin (friends-of-friends) and the console.log within getFriends callback contains the list in the terminal so i know getFriends
is returning the proper data but i cannot figure out how to return the value into my React-Native Component. i have tried for the past 8 hours everything i can think of and cannot get the value returned out of this function.
You're close, but there's a couple of things to keep in mind when working with resolvers:
Your resolver has to return either a value that matches the type/scalar specified in your schema or a Promise that will resolve to that value.
Mongoose operations can return a promises, and you should utilize this feature of them rather than trying to wrap callbacks inside Promises as this can easily get messy
Return statements inside callbacks at least in this context) don't actually do anything. Return statements inside a then, on the other hand, determine what the promise will resolve to (or what promise to invoke next in the chain).
I would imagine your resolver needs to look something like this:
resolve (_, {currentId}) => {
// calling exec() on the query turns it into a promise
return User.findById(currentId).exec()
// the value the promise resolves to is accessible in the "then" method
.then(user => {
// should make sure user is not null here, something like:
if (!user) return Promise.reject(new Error('no user found with that id'))
// we want the value returned by another async method, getFriends, so
// wrap that call in a promise, and return the promise
return new Promise((resolve, reject) => {
user.getFriends((error, friends) => {
if (error) reject(error)
resolve(friends)
})
})
})
}