Add title to popular posts route to improve site efficiency
This commit is contained in:
parent
3ee97b5d43
commit
1228112213
5 changed files with 59 additions and 22 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,2 +1,3 @@
|
|||
/target
|
||||
.env
|
||||
upvoters
|
||||
|
|
|
|||
7
db/migrations/002_create_slug_to_title.sql
Normal file
7
db/migrations/002_create_slug_to_title.sql
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS titles (
|
||||
slug text not null,
|
||||
title text not null,
|
||||
primary key (slug)
|
||||
);
|
||||
|
|
@ -13,6 +13,7 @@ use uuid::Uuid;
|
|||
use crate::{
|
||||
state::AppState,
|
||||
votes::{
|
||||
model::VoteRequest,
|
||||
repository::{delete_vote, get_top_n_slugs, insert_new_vote},
|
||||
service::get_votes_and_voted,
|
||||
},
|
||||
|
|
@ -51,10 +52,12 @@ async fn upvote_handler(
|
|||
jar: CookieJar,
|
||||
Path(slug): Path<String>,
|
||||
State(state): State<AppState>,
|
||||
Json(upvote_payload): Json<VoteRequest>,
|
||||
) -> impl IntoResponse {
|
||||
let (jar, voter_id) = get_or_init_voter_id(jar);
|
||||
|
||||
match insert_new_vote(&slug, &voter_id, &state.db).await {
|
||||
info!("{:?}", upvote_payload);
|
||||
match insert_new_vote(&slug, &voter_id, upvote_payload.title, &state.db).await {
|
||||
Ok(()) => {
|
||||
info!(slug = %slug, voter_id = %voter_id, "upvoted successfully");
|
||||
(StatusCode::OK, jar, "Successfully upvoted")
|
||||
|
|
@ -260,7 +263,7 @@ mod tests {
|
|||
let slug = "delete_vote_handler_removes_vote_for_cookie_voter";
|
||||
let voter_id = Uuid::from_u128(0xdef);
|
||||
delete_votes_for_slug(slug, &db).await.unwrap();
|
||||
insert_new_vote(slug, &voter_id, &db).await.unwrap();
|
||||
insert_new_vote(slug, &voter_id, None, &db).await.unwrap();
|
||||
|
||||
let app = crate::app(test_state(db.clone()));
|
||||
let request = Request::builder()
|
||||
|
|
@ -309,8 +312,10 @@ mod tests {
|
|||
let voter_id = Uuid::from_u128(0x123);
|
||||
let other_voter_id = Uuid::from_u128(0x456);
|
||||
delete_votes_for_slug(slug, &db).await.unwrap();
|
||||
insert_new_vote(slug, &voter_id, &db).await.unwrap();
|
||||
insert_new_vote(slug, &other_voter_id, &db).await.unwrap();
|
||||
insert_new_vote(slug, &voter_id, None, &db).await.unwrap();
|
||||
insert_new_vote(slug, &other_voter_id, None, &db)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let app = crate::app(test_state(db.clone()));
|
||||
let request = Request::builder()
|
||||
|
|
@ -337,7 +342,7 @@ mod tests {
|
|||
let slug = "get_votes_and_voted_handler_sets_cookie_for_new_voter";
|
||||
let existing_voter_id = Uuid::from_u128(0x789);
|
||||
delete_votes_for_slug(slug, &db).await.unwrap();
|
||||
insert_new_vote(slug, &existing_voter_id, &db)
|
||||
insert_new_vote(slug, &existing_voter_id, None, &db)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
|
@ -378,12 +383,16 @@ mod tests {
|
|||
Uuid::from_u128(0x101),
|
||||
Uuid::from_u128(0x102),
|
||||
] {
|
||||
insert_new_vote(slugs[0], &voter_id, &db).await.unwrap();
|
||||
insert_new_vote(slugs[0], &voter_id, None, &db)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
for voter_id in [Uuid::from_u128(0x200), Uuid::from_u128(0x201)] {
|
||||
insert_new_vote(slugs[1], &voter_id, &db).await.unwrap();
|
||||
insert_new_vote(slugs[1], &voter_id, None, &db)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
insert_new_vote(slugs[2], &Uuid::from_u128(0x300), &db)
|
||||
insert_new_vote(slugs[2], &Uuid::from_u128(0x300), None, &db)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,12 @@ use serde::{Deserialize, Serialize};
|
|||
use sqlx::prelude::FromRow;
|
||||
use uuid::Uuid;
|
||||
|
||||
/// Struct representing a vote request
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct VoteRequest {
|
||||
pub title: Option<String>,
|
||||
}
|
||||
|
||||
/// Struct representing a single vote (row) in the votes table
|
||||
#[derive(Debug, FromRow)]
|
||||
pub struct Vote {
|
||||
|
|
@ -16,4 +22,5 @@ pub struct Vote {
|
|||
pub struct BestSlugs {
|
||||
pub slug: String,
|
||||
pub vote_count: i64,
|
||||
pub title: String,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,12 @@ pub async fn vote_exists(slug: &str, voter_id: &Uuid, db: &PgPool) -> Result<boo
|
|||
.await?;
|
||||
Ok(count > 0)
|
||||
}
|
||||
pub async fn insert_new_vote(slug: &str, voter_id: &Uuid, db: &PgPool) -> Result<()> {
|
||||
pub async fn insert_new_vote(
|
||||
slug: &str,
|
||||
voter_id: &Uuid,
|
||||
title: Option<String>,
|
||||
db: &PgPool,
|
||||
) -> Result<()> {
|
||||
query(
|
||||
r#"insert into votes (slug, voter_id)
|
||||
values ($1, $2)
|
||||
|
|
@ -29,6 +34,14 @@ pub async fn insert_new_vote(slug: &str, voter_id: &Uuid, db: &PgPool) -> Result
|
|||
.bind(voter_id)
|
||||
.execute(db)
|
||||
.await?;
|
||||
|
||||
if let Some(title) = title {
|
||||
query(r#"insert into titles values ($1, $2)"#)
|
||||
.bind(slug)
|
||||
.bind(title)
|
||||
.execute(db)
|
||||
.await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -43,9 +56,9 @@ pub async fn get_vote_count_for_slug(slug: &str, db: &PgPool) -> Result<i64> {
|
|||
pub async fn get_top_n_slugs(n: i64, db: &PgPool) -> Result<Vec<BestSlugs>> {
|
||||
if n > 0 {
|
||||
let top_slugs = query_as::<_, BestSlugs>(
|
||||
r#"select slug, count(*) AS vote_count
|
||||
from votes
|
||||
group by slug
|
||||
r#"select slug, title, count(*) AS vote_count
|
||||
from votes natural join titles
|
||||
group by slug, title
|
||||
order by vote_count desc
|
||||
limit $1
|
||||
"#,
|
||||
|
|
@ -130,7 +143,7 @@ mod postgres_tests {
|
|||
cleanup(&db, &votes).await;
|
||||
|
||||
for (slug, voter_id) in votes.iter() {
|
||||
insert_new_vote(slug, voter_id, &db)
|
||||
insert_new_vote(slug, voter_id, None, &db)
|
||||
.await
|
||||
.expect("Insertions to db failed");
|
||||
}
|
||||
|
|
@ -196,22 +209,22 @@ mod postgres_tests {
|
|||
)];
|
||||
cleanup(&db, &votes).await;
|
||||
|
||||
insert_new_vote(&votes[0].0, &votes[0].1, &db)
|
||||
insert_new_vote(&votes[0].0, &votes[0].1, None, &db)
|
||||
.await
|
||||
.unwrap();
|
||||
insert_new_vote(&votes[0].0, &votes[0].1, &db)
|
||||
insert_new_vote(&votes[0].0, &votes[0].1, None, &db)
|
||||
.await
|
||||
.unwrap();
|
||||
insert_new_vote(&votes[0].0, &votes[0].1, &db)
|
||||
insert_new_vote(&votes[0].0, &votes[0].1, None, &db)
|
||||
.await
|
||||
.unwrap();
|
||||
insert_new_vote(&votes[0].0, &votes[0].1, &db)
|
||||
insert_new_vote(&votes[0].0, &votes[0].1, None, &db)
|
||||
.await
|
||||
.unwrap();
|
||||
insert_new_vote(&votes[0].0, &votes[0].1, &db)
|
||||
insert_new_vote(&votes[0].0, &votes[0].1, None, &db)
|
||||
.await
|
||||
.unwrap();
|
||||
insert_new_vote(&votes[0].0, &votes[0].1, &db)
|
||||
insert_new_vote(&votes[0].0, &votes[0].1, None, &db)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
|
@ -231,7 +244,7 @@ mod postgres_tests {
|
|||
)];
|
||||
cleanup(&db, &votes).await;
|
||||
|
||||
insert_new_vote(&votes[0].0, &votes[0].1, &db)
|
||||
insert_new_vote(&votes[0].0, &votes[0].1, None, &db)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
|
@ -265,10 +278,10 @@ mod postgres_tests {
|
|||
];
|
||||
cleanup(&db, &votes).await;
|
||||
|
||||
insert_new_vote(&votes[0].0, &votes[0].1, &db)
|
||||
insert_new_vote(&votes[0].0, &votes[0].1, None, &db)
|
||||
.await
|
||||
.unwrap();
|
||||
insert_new_vote(&votes[1].0, &votes[1].1, &db)
|
||||
insert_new_vote(&votes[1].0, &votes[1].1, None, &db)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue