-
Notifications
You must be signed in to change notification settings - Fork 242
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Currently semi-blocked on rust-lang/rust#64477. Or rather, it would take a bunch of work to fix the last error in our code. Instead, there's a small change to std that would also fix it, so waiting on that: rust-lang/rust#64477 (comment)
- Loading branch information
Showing
33 changed files
with
3,898 additions
and
4,048 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
265 changes: 127 additions & 138 deletions
265
noria-benchmarks/lobsters/src/endpoints/natural/comment.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,154 +1,143 @@ | ||
use chrono; | ||
use futures; | ||
use futures::Future; | ||
use my; | ||
use my::prelude::*; | ||
use std::future::Future; | ||
use trawler::{CommentId, StoryId, UserId}; | ||
|
||
pub(crate) fn handle<F>( | ||
pub(crate) async fn handle<F>( | ||
c: F, | ||
acting_as: Option<UserId>, | ||
id: CommentId, | ||
story: StoryId, | ||
parent: Option<CommentId>, | ||
) -> Box<dyn Future<Item = (my::Conn, bool), Error = my::error::Error> + Send> | ||
) -> Result<(my::Conn, bool), my::error::Error> | ||
where | ||
F: 'static + Future<Item = my::Conn, Error = my::error::Error> + Send, | ||
F: 'static + Future<Output = Result<my::Conn, my::error::Error>> + Send, | ||
{ | ||
let c = c.await?; | ||
let user = acting_as.unwrap(); | ||
Box::new( | ||
c.and_then(move |c| { | ||
c.first_exec::<_, _, my::Row>( | ||
"SELECT `stories`.* \ | ||
FROM `stories` \ | ||
WHERE `stories`.`short_id` = ?", | ||
(::std::str::from_utf8(&story[..]).unwrap(),), | ||
) | ||
.map(|(c, story)| (c, story.unwrap())) | ||
}) | ||
.and_then(|(c, story)| { | ||
let author = story.get::<u32, _>("user_id").unwrap(); | ||
let id = story.get::<u32, _>("id").unwrap(); | ||
c.drop_exec( | ||
"SELECT `users`.* FROM `users` WHERE `users`.`id` = ?", | ||
(author,), | ||
) | ||
.map(move |c| (c, id)) | ||
}) | ||
.and_then(move |(c, story)| { | ||
let fut = if let Some(parent) = parent { | ||
// check that parent exists | ||
futures::future::Either::A( | ||
c.first_exec::<_, _, my::Row>( | ||
"SELECT `comments`.* FROM `comments` \ | ||
WHERE `comments`.`story_id` = ? \ | ||
AND `comments`.`short_id` = ?", | ||
(story, ::std::str::from_utf8(&parent[..]).unwrap()), | ||
) | ||
.map(move |(c, p)| { | ||
if let Some(p) = p { | ||
( | ||
c, | ||
Some(( | ||
p.get::<u32, _>("id").unwrap(), | ||
p.get::<Option<u32>, _>("thread_id").unwrap(), | ||
)), | ||
) | ||
} else { | ||
eprintln!( | ||
"failed to find parent comment {} in story {}", | ||
::std::str::from_utf8(&parent[..]).unwrap(), | ||
story | ||
); | ||
(c, None) | ||
} | ||
}), | ||
) | ||
} else { | ||
futures::future::Either::B(futures::future::ok((c, None))) | ||
}; | ||
fut.map(move |(c, parent)| (c, story, parent)) | ||
}) | ||
.map(|c| { | ||
// TODO: real site checks for recent comments by same author with same | ||
// parent to ensure we don't double-post accidentally | ||
c | ||
}) | ||
.and_then(move |(c, story, parent)| { | ||
// check that short id is available | ||
c.drop_exec( | ||
"SELECT 1 AS one FROM `comments` \ | ||
WHERE `comments`.`short_id` = ?", | ||
(::std::str::from_utf8(&id[..]).unwrap(),), | ||
let (c, story) = c | ||
.first_exec::<_, _, my::Row>( | ||
"SELECT `stories`.* \ | ||
FROM `stories` \ | ||
WHERE `stories`.`short_id` = ?", | ||
(::std::str::from_utf8(&story[..]).unwrap(),), | ||
) | ||
.await?; | ||
let story = story.unwrap(); | ||
let author = story.get::<u32, _>("user_id").unwrap(); | ||
let story = story.get::<u32, _>("id").unwrap(); | ||
c = c | ||
.drop_exec( | ||
"SELECT `users`.* FROM `users` WHERE `users`.`id` = ?", | ||
(author,), | ||
) | ||
.await?; | ||
|
||
let parent = if let Some(parent) = parent { | ||
// check that parent exists | ||
let (x, p) = c | ||
.first_exec::<_, _, my::Row>( | ||
"SELECT `comments`.* FROM `comments` \ | ||
WHERE `comments`.`story_id` = ? \ | ||
AND `comments`.`short_id` = ?", | ||
(story, ::std::str::from_utf8(&parent[..]).unwrap()), | ||
) | ||
.map(move |c| (c, story, parent)) | ||
}) | ||
.and_then(move |(c, story, parent)| { | ||
// TODO: real impl checks *new* short_id *again* | ||
.await?; | ||
c = x; | ||
|
||
if let Some(p) = p { | ||
Some(( | ||
p.get::<u32, _>("id").unwrap(), | ||
p.get::<Option<u32>, _>("thread_id").unwrap(), | ||
)) | ||
} else { | ||
eprintln!( | ||
"failed to find parent comment {} in story {}", | ||
::std::str::from_utf8(&parent[..]).unwrap(), | ||
story | ||
); | ||
None | ||
} | ||
} else { | ||
None | ||
}; | ||
|
||
// TODO: real site checks for recent comments by same author with same | ||
// parent to ensure we don't double-post accidentally | ||
|
||
// check that short id is available | ||
c = c | ||
.drop_exec( | ||
"SELECT 1 AS one FROM `comments` \ | ||
WHERE `comments`.`short_id` = ?", | ||
(::std::str::from_utf8(&id[..]).unwrap(),), | ||
) | ||
.await?; | ||
|
||
// TODO: real impl checks *new* short_id *again* | ||
|
||
// NOTE: MySQL technically does everything inside this and_then in a transaction, | ||
// but let's be nice to it | ||
let now = chrono::Local::now().naive_local(); | ||
let q = if let Some((parent, thread)) = parent { | ||
c.prep_exec( | ||
"INSERT INTO `comments` \ | ||
(`created_at`, `updated_at`, `short_id`, `story_id`, \ | ||
`user_id`, `parent_comment_id`, `thread_id`, \ | ||
`comment`, `markeddown_comment`) \ | ||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", | ||
( | ||
now, | ||
now, | ||
::std::str::from_utf8(&id[..]).unwrap(), | ||
story, | ||
user, | ||
parent, | ||
thread, | ||
"moar benchmarking", // lorem ipsum? | ||
"<p>moar benchmarking</p>\n", | ||
), | ||
) | ||
.await? | ||
} else { | ||
c.prep_exec( | ||
"INSERT INTO `comments` \ | ||
(`created_at`, `updated_at`, `short_id`, `story_id`, \ | ||
`user_id`, `comment`, `markeddown_comment`) \ | ||
VALUES (?, ?, ?, ?, ?, ?, ?)", | ||
( | ||
now, | ||
now, | ||
::std::str::from_utf8(&id[..]).unwrap(), | ||
story, | ||
user, | ||
"moar benchmarking", // lorem ipsum? | ||
"<p>moar benchmarking</p>\n", | ||
), | ||
) | ||
.await? | ||
}; | ||
let comment = q.last_insert_id().unwrap(); | ||
let c = q.drop_result().await?; | ||
// but why?! | ||
c = c | ||
.drop_exec( | ||
"SELECT `votes`.* FROM `votes` \ | ||
WHERE `votes`.`user_id` = ? \ | ||
AND `votes`.`story_id` = ? \ | ||
AND `votes`.`comment_id` = ?", | ||
(user, story, comment), | ||
) | ||
.await?; | ||
c = c | ||
.drop_exec( | ||
"INSERT INTO `votes` \ | ||
(`user_id`, `story_id`, `comment_id`, `vote`) \ | ||
VALUES (?, ?, ?, ?)", | ||
(user, story, comment, 1), | ||
) | ||
.await?; | ||
|
||
// NOTE: MySQL technically does everything inside this and_then in a transaction, | ||
// but let's be nice to it | ||
let now = chrono::Local::now().naive_local(); | ||
if let Some((parent, thread)) = parent { | ||
futures::future::Either::A(c.prep_exec( | ||
"INSERT INTO `comments` \ | ||
(`created_at`, `updated_at`, `short_id`, `story_id`, \ | ||
`user_id`, `parent_comment_id`, `thread_id`, \ | ||
`comment`, `markeddown_comment`) \ | ||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", | ||
( | ||
now, | ||
now, | ||
::std::str::from_utf8(&id[..]).unwrap(), | ||
story, | ||
user, | ||
parent, | ||
thread, | ||
"moar benchmarking", // lorem ipsum? | ||
"<p>moar benchmarking</p>\n", | ||
), | ||
)) | ||
} else { | ||
futures::future::Either::B(c.prep_exec( | ||
"INSERT INTO `comments` \ | ||
(`created_at`, `updated_at`, `short_id`, `story_id`, \ | ||
`user_id`, `comment`, `markeddown_comment`) \ | ||
VALUES (?, ?, ?, ?, ?, ?, ?)", | ||
( | ||
now, | ||
now, | ||
::std::str::from_utf8(&id[..]).unwrap(), | ||
story, | ||
user, | ||
"moar benchmarking", // lorem ipsum? | ||
"<p>moar benchmarking</p>\n", | ||
), | ||
)) | ||
} | ||
.and_then(|q| { | ||
let comment = q.last_insert_id().unwrap(); | ||
q.drop_result().map(move |t| (t, comment)) | ||
}) | ||
.and_then(move |(t, comment)| { | ||
// but why?! | ||
t.drop_exec( | ||
"SELECT `votes`.* FROM `votes` \ | ||
WHERE `votes`.`user_id` = ? \ | ||
AND `votes`.`story_id` = ? \ | ||
AND `votes`.`comment_id` = ?", | ||
(user, story, comment), | ||
) | ||
.map(move |t| (t, comment)) | ||
}) | ||
.and_then(move |(t, comment)| { | ||
t.drop_exec( | ||
"INSERT INTO `votes` \ | ||
(`user_id`, `story_id`, `comment_id`, `vote`) \ | ||
VALUES (?, ?, ?, ?)", | ||
(user, story, comment, 1), | ||
) | ||
}) | ||
}) | ||
.map(|c| (c, false)), | ||
) | ||
Ok((c, false)) | ||
} |
Oops, something went wrong.