I am writing a Node.js script to populate an SQL database with a test dataset.
In the promise chain illustrated in the code snippet below (the real code is a bit more hairy), the function insertData()
requires the db
object to be passed through from the previous stage. However, asynchronous calls inside dropAndCreateTables()
on the previous stage use db
object but do not return it. I came up with a solution that wraps promises inside dropAndCreateTables()
into another promise object that resolves to a db
object. However:
- I heard that using
Promise()
constructor in non-library code is an antipattern and may lead to subtle and hard-to-diagnose mistakes - I heard that nesting
then()
-chains is also an antipattern - It does not allow me to ignore errors from the
promiseDrop
(for example, I don't care if tables don't exist on drop) - It is ugly
Questions:
- Is there a simpler, nicer and more socially accepted way to override the return value of a promise? (in this case, created with
Promise.all()
) - Is there a way to restructure my code in a way that this problem does not occur? (That is, I don't exclude the possibility of "XY problem" here)
Code:
const dropAndCreateTables = (db, startClean) => {
if(startClean) {
const sqlDrop = fs.readFileSync('drop.sql').toString()
const promiseDrop = db.raw(sqlDrop)
const sqlCreate = fs.readFileSync('create.sql').toString()
const promiseCreate = db.raw(sqlCreate)
/********* Problems here? ************************************/
return new Promise((resolve, reject) => { // Ew?
Promise.all([promiseDrop, promiseCreate])
.then(() => {
resolve(db) // Override the returned value
})
.catch(reject)
})
}
return Promise.resolve(db)
}
initDB({ debug: false })
.then((db) => {
return dropAndCreateTables(db, START_CLEAN) // Without my hack this does not return `db`
})
.then((db) => {
return insertData(db, DO_UPSERT) // This needs the `db` object
})
.then(() => {
console.info(`\n${timestamp()} done`)
})
.catch(handleError)