К сожалению, в моем случае невозможно заимствовать значение в замыкании, потому что abort
потребляет транзакцию. (Спасибо @vkurchatkin за объяснение этого)
На случай, если кому-то будет интересно, я разработал решение, которое удовлетворит меня независимо от проблемы. Мне удалось избежать вложения группы match
es.
. Я переместил все логи c, работающие с транзакцией, в отдельную функцию, а затем отложил оценку функции * 1007. * до запуска txn.abort()
(см. комментарии):
pub async fn get_user(db: Data<Database>, id: Identity) -> Result<Json<User>, Error> {
let username = id.identity().ok_or_else(|| error::ErrorUnauthorized(""))?;
let txn = db
.env
.begin_ro_txn()
.map_err(|_| error::ErrorInternalServerError(""))?;
let user = db_get_user(&db, &txn, &id, &username); // Execute separate function but do not evaluate the function Result yet, notice missing question mark operator!
txn.abort(); // Abort the transaction after running the code. (Doesn't matter if it was successful or not. This consumes the transaction and it cannot be used anymore.)
Ok(Json(user?)) // Now evaluate the Result using the question mark operator.
}
// New separate function that uses the transaction.
fn db_get_user(
db: &Database,
txn: &RoTransaction,
id: &Identity,
username: &str,
) -> Result<User, Error> {
let user_bytes = txn.get(db.handle_users, &username).map_err(|e| match e {
lmdb::Error::NotFound => {
id.forget();
error::ErrorUnauthorized("")
}
_ => error::ErrorInternalServerError(""),
})?;
serde_cbor::from_slice(user_bytes).map_err(|_| error::ErrorInternalServerError(""))
}