promise chain not executing in order

Viewed 78

I'm having a weird problem, I call "createProductLine" in the following code :

module.exports.postProductLine = (req, res) => {
    DAL.createProductLine(req.body.category, req.body.type, req.body.name, req.body.description, req.body.tags)
    .then(() => {
        res.sendStatus(200)
        console.log("SUCCESS")
    })
    .catch(err => {
        res.status(500).send(err.message)
        console.error(err)
    })
}

and here is the "createProductLine" function :

module.exports.createProductLine = async (category, type, name, description, tags) => {
    const [pool, dbErr] = await tryCatch(await database.pool)
    if(dbErr) return Promise.reject()
    const [connection, connectErr] = await tryCatch(pool.getConnection())
    if(connectErr) return Promise.reject()
    connection.beginTransaction()
    .then(() => {
        const query = `INSERT INTO product_lines (category,type,name,description,last_update,creation_date) VALUES (?,?,?,?,NOW(),NOW())`
        return connection.query(query, [category, type, name, description])
    })
    .then(({insertId: productLineId} = {}) => Promise.all([
        Promise.resolve(productLineId),
        ...tags.map(productLineTag => new Promise(async (resolve, reject) => {
            let query = "SELECT id FROM tags WHERE name=?"
            const [existingTag, err1] = await tryCatch(connection.query(query, [productLineTag]))
            if(err1) return reject(`could not get tag (${productLineTag}) id`)
            if(existingTag.length === 0) {
                query = "INSERT INTO tags (name) VALUES (?)"
                const [{insertId}, err2] = await tryCatch(connection.query(query, [productLineTag]))
                if(err2) return reject(`could not insert tag (${productLineTag})`)
                return resolve(insertId)
            }
            return resolve(existingTag[0].id)
        }))
    ]))
    // CHANGE OF ORDER HAPPENS HERE
    .then(ids => Promise.all(
        ids.reduce((acc, cur, i, arr) => {
            if(i === 0) return acc
            acc[i - 1] = connection.query(
                `INSERT INTO product_lines_tags (product_line_id, tag_id) VALUES (${arr[0]}, ${cur})`
            )
            return acc
        }, new Array(ids.length - 1))
    ))
    .then(async () => {
        console.log("THEN")
        await connection.commit()
        return connection.release()
    })
    .catch(async err => {
        console.log("CATCH", err)
        await connection.rollback()
        await connection.release()
        return err
    })
}

For some reason the execution order of the all the .then doesn't go as expected, after finishing the second one (inside "createProductLine") it executes the .then in the first block of code (postProductLine function) and then comes back to execute the rest.

I don't understand why does it behave like this, do anyone have any idea on how to fix this please ?

1 Answers
module.exports.createProductLine = async (category, type, name, description, tags) => {
    const pool = await database.pool
    const connection = await pool.getConnection()
    await connection.beginTransaction()
    try {
        const {insertId: productLineId} = await connection.query(
            "INSERT INTO product_lines (category,type,name,description) VALUES (?,?,?,?)", 
            [category, type, name, description]
        )
        const tagIds = await Promise.all(tags.map(async tag => {
            const existingTag = await connection.query(
                "SELECT id FROM tags WHERE name=?", [tag]
            )
            if(existingTag.length === 0) { 
                const {insertId} = await connection.query(
                    "INSERT INTO tags (name) VALUES (?)", [tag]
                )
                return insertId
            }
            return existingTag[0].id
        }))
        await Promise.all(tagIds.map(tagId => connection.query(
            `INSERT INTO product_lines_tags (product_line_id, tag_id) VALUES (${productLineId}, ${tagId})`
        )))
        await connection.commit()
        await connection.release()
        return true
    }
    catch(err) {
        await connection.rollback()
        await connection.release()
        return Promise.reject(err)
    }
}
Related