fix(helpers): transactions

This commit is contained in:
Pascal Engélibert 2023-01-04 09:15:03 +01:00
parent 0c3ea546fd
commit c183747729
Signed by: tuxmain
GPG key ID: 3504BC6D362F7DCA
4 changed files with 134 additions and 102 deletions

12
Cargo.lock generated
View file

@ -1721,9 +1721,9 @@ dependencies = [
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.16.0" version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
[[package]] [[package]]
name = "opaque-debug" name = "opaque-debug"
@ -2937,9 +2937,9 @@ dependencies = [
[[package]] [[package]]
name = "toml_edit" name = "toml_edit"
version = "0.16.2" version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd30deba9a1cd7153c22aecf93e86df639e7b81c622b0af8d9255e989991a7b7" checksum = "a34cc558345efd7e88b9eda9626df2138b80bb46a7606f695e751c892bc7dac6"
dependencies = [ dependencies = [
"indexmap", "indexmap",
"itertools", "itertools",
@ -3003,9 +3003,9 @@ dependencies = [
[[package]] [[package]]
name = "typed-sled" name = "typed-sled"
version = "0.2.1" version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32b903ab728fcd56542a5c538dfc3d196aeffcdb1dc37e34c49f61782adc5cfa" checksum = "1060f05a4450ec5b758da60951b04f225a93a62079316630e76cf25c4034500d"
dependencies = [ dependencies = [
"bincode", "bincode",
"pin-project", "pin-project",

View file

@ -29,8 +29,8 @@ sled = "0.34.7"
tera = { version = "1.17.1", features = ["builtins", "date-locale"] } tera = { version = "1.17.1", features = ["builtins", "date-locale"] }
tide = { version = "0.16.0", default-features = false, features = ["h1-server", "cookies", "logger"] } tide = { version = "0.16.0", default-features = false, features = ["h1-server", "cookies", "logger"] }
tokio = { version = "1.23.0", features = ["macros", "rt-multi-thread"] } tokio = { version = "1.23.0", features = ["macros", "rt-multi-thread"] }
toml_edit = { version = "0.16.2", features = ["easy"] } toml_edit = { version = "0.17.1", features = ["easy"] }
typed-sled = "0.2.1" typed-sled = "0.2.3"
unic-langid = { version = "0.9.1", features = ["macros"] } unic-langid = { version = "0.9.1", features = ["macros"] }
[features] [features]

View file

@ -2,6 +2,10 @@ use base64::engine::Engine;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
use std::{net::IpAddr, path::Path}; use std::{net::IpAddr, path::Path};
pub use sled::transaction::{
ConflictableTransactionError, ConflictableTransactionResult, TransactionError,
};
pub use typed_sled::Tree; pub use typed_sled::Tree;
const DB_DIR: &str = "db"; const DB_DIR: &str = "db";

View file

@ -3,6 +3,7 @@ use crate::{config::Config, db::*, locales::Locales, queries::*};
use fluent_bundle::FluentArgs; use fluent_bundle::FluentArgs;
use log::error; use log::error;
use std::{net::IpAddr, str::FromStr}; use std::{net::IpAddr, str::FromStr};
use typed_sled::transaction::Transactional;
use unic_langid::LanguageIdentifier; use unic_langid::LanguageIdentifier;
pub fn new_pending_comment( pub fn new_pending_comment(
@ -11,16 +12,21 @@ pub fn new_pending_comment(
dbs: &Dbs, dbs: &Dbs,
) -> Result<CommentId, sled::Error> { ) -> Result<CommentId, sled::Error> {
let comment_id = CommentId::new(); let comment_id = CommentId::new();
dbs.comment (&dbs.comment, &dbs.comment_pending)
.insert(&comment_id, &(comment.clone(), CommentStatus::Pending))?; .transaction(|(db_comment, db_comment_pending)| {
dbs.comment_pending.insert( db_comment.insert(&comment_id, &(comment.clone(), CommentStatus::Pending))?;
&( db_comment_pending.insert(
comment.topic_hash.clone(), &(
comment.post_time, comment.topic_hash.clone(),
comment_id.clone(), comment.post_time,
), comment_id.clone(),
&(addr, false), ),
)?; &(addr, false),
)?;
ConflictableTransactionResult::<_>::Ok(())
})
.unwrap();
Ok(comment_id) Ok(comment_id)
} }
@ -40,18 +46,26 @@ pub fn edit_comment(
// TODO should we update ip address in comment_pending? // TODO should we update ip address in comment_pending?
} }
CommentStatus::Approved => { CommentStatus::Approved => {
dbs.comment_pending.insert( (&dbs.comment, &dbs.comment_pending)
&( .transaction(|(db_comment, db_comment_pending)| {
edited_comment.topic_hash.clone(), db_comment_pending.insert(
edited_comment.post_time, &(
comment_id.clone(), edited_comment.topic_hash.clone(),
), edited_comment.post_time,
&(addr, true), comment_id.clone(),
)?; ),
dbs.comment.insert( &(addr, true),
&comment_id, )?;
&(old_comment, CommentStatus::ApprovedEdited(edited_comment)), db_comment.insert(
)?; &comment_id,
&(
old_comment.clone(),
CommentStatus::ApprovedEdited(edited_comment.clone()),
),
)?;
ConflictableTransactionResult::<_>::Ok(())
})
.unwrap();
} }
CommentStatus::ApprovedEdited(_old_edited_comment) => { CommentStatus::ApprovedEdited(_old_edited_comment) => {
dbs.comment.insert( dbs.comment.insert(
@ -65,94 +79,108 @@ pub fn edit_comment(
} }
pub fn approve_comment(comment_id: CommentId, dbs: &Dbs) -> Result<(), sled::Error> { pub fn approve_comment(comment_id: CommentId, dbs: &Dbs) -> Result<(), sled::Error> {
if let Some((comment, CommentStatus::Pending)) = dbs.comment.get(&comment_id)? { (&dbs.comment, &dbs.comment_approved, &dbs.comment_pending)
dbs.comment_pending.remove(&( .transaction(|(db_comment, db_comment_approved, db_comment_pending)| {
comment.topic_hash.clone(), if let Some((comment, CommentStatus::Pending)) = db_comment.get(&comment_id)? {
comment.post_time, db_comment_pending.remove(&(
comment_id.clone(), comment.topic_hash.clone(),
))?; comment.post_time,
dbs.comment_approved.insert( comment_id.clone(),
&( ))?;
comment.topic_hash.clone(), db_comment_approved.insert(
comment.post_time, &(
comment_id.clone(), comment.topic_hash.clone(),
), comment.post_time,
&(), comment_id.clone(),
)?; ),
dbs.comment &(),
.insert(&comment_id, &(comment, CommentStatus::Approved))?; )?;
} db_comment.insert(&comment_id, &(comment, CommentStatus::Approved))?;
}
ConflictableTransactionResult::<_>::Ok(())
})
.unwrap();
Ok(()) Ok(())
} }
pub fn approve_edit(comment_id: CommentId, dbs: &Dbs) -> Result<Option<Comment>, sled::Error> { pub fn approve_edit(comment_id: CommentId, dbs: &Dbs) -> Result<Option<Comment>, sled::Error> {
if let Some((comment, CommentStatus::ApprovedEdited(edited_comment))) = Ok((&dbs.comment, &dbs.comment_pending)
dbs.comment.get(&comment_id)? .transaction(|(db_comment, db_comment_pending)| {
{ if let Some((comment, CommentStatus::ApprovedEdited(edited_comment))) =
dbs.comment_pending.remove(&( db_comment.get(&comment_id)?
edited_comment.topic_hash.clone(), {
edited_comment.post_time, db_comment_pending.remove(&(
comment_id.clone(), edited_comment.topic_hash.clone(),
))?; edited_comment.post_time,
dbs.comment comment_id.clone(),
.insert(&comment_id, &(edited_comment, CommentStatus::Approved))?; ))?;
return Ok(Some(comment)); db_comment.insert(&comment_id, &(edited_comment, CommentStatus::Approved))?;
} return ConflictableTransactionResult::<_>::Ok(Some(comment));
Ok(None) }
ConflictableTransactionResult::<_>::Ok(None)
})
.unwrap())
} }
pub fn remove_comment( pub fn remove_comment(
comment_id: CommentId, comment_id: CommentId,
dbs: &Dbs, dbs: &Dbs,
) -> Result<Option<(Comment, CommentStatus)>, sled::Error> { ) -> Result<Option<(Comment, CommentStatus)>, sled::Error> {
if let Some((comment, edited_comment)) = dbs.comment.remove(&comment_id)? { Ok((&dbs.comment, &dbs.comment_approved, &dbs.comment_pending)
match &edited_comment { .transaction(|(db_comment, db_comment_approved, db_comment_pending)| {
CommentStatus::Pending => { if let Some((comment, edited_comment)) = db_comment.remove(&comment_id)? {
dbs.comment_pending.remove(&( match &edited_comment {
comment.topic_hash.clone(), CommentStatus::Pending => {
comment.post_time, db_comment_pending.remove(&(
comment_id, comment.topic_hash.clone(),
))?; comment.post_time,
comment_id.clone(),
))?;
}
CommentStatus::Approved => {
db_comment_approved.remove(&(
comment.topic_hash.clone(),
comment.post_time,
comment_id.clone(),
))?;
}
CommentStatus::ApprovedEdited(edited_comment) => {
db_comment_pending.remove(&(
edited_comment.topic_hash.clone(),
edited_comment.post_time,
comment_id.clone(),
))?;
db_comment_approved.remove(&(
comment.topic_hash.clone(),
comment.post_time,
comment_id.clone(),
))?;
}
}
return ConflictableTransactionResult::<_>::Ok(Some((comment, edited_comment)));
} }
CommentStatus::Approved => { ConflictableTransactionResult::<_>::Ok(None)
dbs.comment_approved.remove(&( })
comment.topic_hash.clone(), .unwrap())
comment.post_time, }
comment_id,
))?; pub fn remove_edit(comment_id: CommentId, dbs: &Dbs) -> Result<Option<Comment>, sled::Error> {
} Ok((&dbs.comment, &dbs.comment_pending)
CommentStatus::ApprovedEdited(edited_comment) => { .transaction(|(db_comment, db_comment_pending)| {
dbs.comment_pending.remove(&( if let Some((comment, CommentStatus::ApprovedEdited(edited_comment))) =
db_comment.get(&comment_id)?
{
db_comment_pending.remove(&(
edited_comment.topic_hash.clone(), edited_comment.topic_hash.clone(),
edited_comment.post_time, edited_comment.post_time,
comment_id.clone(), comment_id.clone(),
))?; ))?;
dbs.comment_approved.remove(&( db_comment.insert(&comment_id, &(comment.clone(), CommentStatus::Approved))?;
comment.topic_hash.clone(), return ConflictableTransactionResult::<_>::Ok(Some(comment));
comment.post_time,
comment_id,
))?;
} }
} ConflictableTransactionResult::<_>::Ok(None)
return Ok(Some((comment, edited_comment))); })
} .unwrap())
Ok(None)
}
pub fn remove_edit(comment_id: CommentId, dbs: &Dbs) -> Result<Option<Comment>, sled::Error> {
if let Some((comment, CommentStatus::ApprovedEdited(edited_comment))) =
dbs.comment.get(&comment_id)?
{
dbs.comment_pending.remove(&(
edited_comment.topic_hash.clone(),
edited_comment.post_time,
comment_id.clone(),
))?;
dbs.comment
.insert(&comment_id, &(comment.clone(), CommentStatus::Approved))?;
return Ok(Some(comment));
}
Ok(None)
} }
pub fn iter_comments_by_topic<'a, V: typed_sled::KV>( pub fn iter_comments_by_topic<'a, V: typed_sled::KV>(