I'm trying to register a user. The process is as follows - I first generate a hash for the user, then generate a token. Assuming these 2 steps are successful, I then add the user to the database.
This step involves adding the user to 2 tables - a user_credentials table containing just the hash, and using the id returned after this operation to add the other user details and token to a users table.
I am able to successfully add the user - however, when I try to access the user data returned by knex after adding the user to both tables, I always get Data: undefined
.
Not sure what's the correct way to send the row data back from createUser(), and have it available in the next then block (where it's console logged).
const handleRegister = (req, res, db, bcrypt, saltRounds) => {
// Get the details from the body
let user = req.body;
// Hash the plain text password using bcrypt
bcrypt.hash(user.password, saltRounds)
.then((hash) => {
delete user.password;
// set user's hash to encrypted pw
user.hash = hash;
})
// Create token to be sent back to the client to create a session
.then(() => createToken())
// Set user's token to created token
.then((token)=> {
user.token = token;
})
// Save hashed password to db for the user and save user data to db with created token
.then(() => createUser(user, db))
// Return info of created user
.then((data) => {
delete user.hash;
console.log("User:", user);
console.log("Data:", data);
res.status(201).json(user);
})
.catch((err) => {
console.log("This was the error:", err);
res.status(400).json("Something went wrong");
});
}
// creating a user in the database
const createUser = (user, db) => {
return db.transaction((trx) => {
trx.insert({
hash: user.hash
})
.into('user_credentials')
.returning('id')
.then((userId) => {
return trx('users')
.returning('*')
.insert({
user_id: userId[0],
email: user.email,
name: user.name,
token: user.token,
created_at: new Date()
});
})
.then((data)=> {
return trx.commit()
.then(() => data);
})
.catch((err) => {
trx.rollback();
throw err;
})
})
}
OK, after sleeping on it, seem to have found the solution.
It appears that db.transaction creates a pending promise, which is either resolved by trx.commit or rejected by trx.rollback. So the entire transaction with commit and rollback needed to be considered as one block, with a then
block afterwards returning the data rows after a successful insert. See code below.
References if someone wants to know more - https://github.com/tgriesser/knex/issues/1346 http://knexjs.org/#Transactions
const createUser = (user, db) => {
return db.transaction((trx) => {
trx.insert({
hash: user.hash
})
.into('user_credentials')
.returning('id')
.then((userId) => {
return trx('users')
.returning('*')
.insert({
user_id: userId[0],
email: user.email,
name: user.name,
token: user.token,
created_at: new Date()
});
})
.then(trx.commit)
.catch((err) => {
trx.rollback();
throw err;
})
})
//Return the data here instead of along with trx.commit
.then((data) => {
return data;
})
.catch((err) => {
console.log(err);
});
}