Skip to content

Commit 7bffbde

Browse files
fix: clippy lints
1 parent 8d69f15 commit 7bffbde

6 files changed

Lines changed: 84 additions & 82 deletions

File tree

src/app.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ impl AppState {
4242

4343
let content = std::str::from_utf8(&content_bytes)
4444
.map_err(|_| anyhow::anyhow!("Template {} not valid UTF-8", path))?;
45-
templates.push((path.into_owned(), content.to_owned()))
45+
templates.push((path.into_owned(), content.to_owned()));
4646
}
4747

4848
tera.add_raw_templates(templates)

src/post.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,16 @@ pub enum ContentType {
1818
impl From<String> for ContentType {
1919
fn from(s: String) -> Self {
2020
match s.as_str() {
21-
"post" => ContentType::Post,
2221
"link" => ContentType::Link,
2322
"quote" => ContentType::Quote,
2423
_ => ContentType::Post,
2524
}
2625
}
2726
}
2827

29-
impl Into<String> for ContentType {
30-
fn into(self) -> String {
31-
match self {
28+
impl From<ContentType> for String {
29+
fn from(val: ContentType) -> Self {
30+
match val {
3231
ContentType::Post => "post".into(),
3332
ContentType::Link => "link".into(),
3433
ContentType::Quote => "quote".into(),

src/routes.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,10 @@ pub async fn get_image(Path(id): Path<String>, state: State<AppState>) -> impl I
8383
return StatusCode::BAD_REQUEST.into_response();
8484
}
8585

86-
let filename = format!("images/{}", id);
86+
let filename = format!("images/{id}");
8787
match state.image_service.get_image_data(&filename).await {
8888
Ok(Some(data)) => {
89-
let content_type = match id.split('.').last() {
89+
let content_type = match id.split('.').next_back() {
9090
Some("png") => "image/png",
9191
Some("jpg" | "jpeg") => "image/jpeg",
9292
Some("gif") => "image/gif",
@@ -144,7 +144,7 @@ pub async fn search(Query(params): Query<SearchParams>, state: State<AppState>)
144144
context.insert("posts", &posts);
145145
context.insert("current_page", &page);
146146

147-
let total_pages = (total as f64 / per_page as f64).ceil() as usize;
147+
let total_pages = total.div_ceil(per_page);
148148
context.insert("total_pages", &total_pages);
149149
context.insert("per_page", &per_page);
150150
context.insert("total_results", &total);

src/rss.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ impl From<Post> for RssEntry {
2424
),
2525
ContentType::Link => {
2626
let link_title = post.title.as_deref().unwrap_or("this link");
27-
let title = format!("Link: {}", link_title);
27+
let title = format!("Link: {link_title}");
2828
let link_html = post.link.map_or_else(String::new, |link| {
29-
format!(r#"<p>Link: <a href="{}">{}</a></p>"#, link, link_title)
29+
format!(r#"<p>Link: <a href="{link}">{link_title}</a></p>"#)
3030
});
3131
(title, format!("{}{}", link_html, post.content))
3232
}
@@ -35,9 +35,9 @@ impl From<Post> for RssEntry {
3535
let title = post
3636
.title
3737
.clone()
38-
.unwrap_or_else(|| format!("Quote from {}", author));
38+
.unwrap_or_else(|| format!("Quote from {author}"));
3939
let attribution = post.quote_author.map_or_else(String::new, |name| {
40-
format!("<figcaption>— {}</figcaption>", name)
40+
format!("<figcaption>— {name}</figcaption>")
4141
});
4242
let blockquote =
4343
format!("<blockquote>{}</blockquote>{}", post.content, attribution);
@@ -92,11 +92,10 @@ pub async fn feed(app: State<AppState>) -> impl IntoResponse {
9292
<description>Jonathan's Blog</description>
9393
<language>en-us</language>
9494
<atom:link href="https://jonathansm.com/feed" rel="self" type="application/rss+xml" />
95-
{}
95+
{rss_items}
9696
</channel>
9797
</rss>
98-
"#,
99-
rss_items
98+
"#
10099
);
101100

102101
(

src/services/post.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ impl PostService {
6969

7070
pub async fn get_paginated_posts(&self, page: usize) -> Result<(Vec<Post>, usize, usize)> {
7171
const POSTS_PER_PAGE: i64 = 10;
72+
#[allow(clippy::cast_possible_wrap)]
7273
let offset = (page as i64 - 1) * POSTS_PER_PAGE;
7374

7475
let pool = self.pool.clone();
@@ -102,7 +103,8 @@ impl PostService {
102103
.context("Failed to count posts")?
103104
};
104105

105-
let total_pages = (total_posts as f64 / POSTS_PER_PAGE as f64).ceil() as usize;
106+
let total_pages = usize::try_from((total_posts + POSTS_PER_PAGE - 1) / POSTS_PER_PAGE)
107+
.context("Total pages exceeds usize range")?;
106108
let posts = self.bulk_convert_to_posts(queried).await?;
107109

108110
Ok((posts, page, total_pages))
@@ -129,7 +131,7 @@ impl PostService {
129131
rusqlite::Error::QueryReturnedNoRows => {
130132
anyhow::anyhow!("Post not found: {}", id_for_error)
131133
}
132-
_ => e.into(),
134+
_ => e,
133135
}
134136
} else {
135137
e
@@ -160,7 +162,7 @@ impl PostService {
160162
rusqlite::Error::QueryReturnedNoRows => {
161163
anyhow::anyhow!("Special page not found: {}", id_for_error)
162164
}
163-
_ => e.into(),
165+
_ => e,
164166
}
165167
} else {
166168
e
@@ -203,15 +205,16 @@ impl PostService {
203205
.cloned()
204206
.collect();
205207

206-
let commits_map = if !all_commit_ids.is_empty() {
208+
let commits_map = if all_commit_ids.is_empty() {
209+
HashMap::new()
210+
} else {
207211
let pool = self.pool.clone();
208212
let ids = all_commit_ids.clone();
209213
task::spawn_blocking(move || {
210214
let conn = pool.get()?;
211215
let placeholders = ids.iter().map(|_| "?").collect::<Vec<_>>().join(",");
212216
let sql = format!(
213-
"SELECT id, date, subject, body FROM commits WHERE id IN ({})",
214-
placeholders
217+
"SELECT id, date, subject, body FROM commits WHERE id IN ({placeholders})"
215218
);
216219

217220
let mut stmt = conn.prepare(&sql)?;
@@ -238,8 +241,6 @@ impl PostService {
238241
})
239242
.await
240243
.context("Failed to join blocking task")??
241-
} else {
242-
HashMap::new()
243244
};
244245

245246
for post in &mut posts {

src/services/search.rs

Lines changed: 62 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,61 @@ impl SearchService {
1919
PostService::row_to_post(row)
2020
}
2121

22+
fn build_search_query(
23+
owned_query: &SearchQuery,
24+
post_types_as_strings: &[String],
25+
) -> (String, Vec<Box<dyn rusqlite::ToSql>>) {
26+
let mut conditions = vec![];
27+
let mut params: Vec<Box<dyn rusqlite::ToSql>> = vec![];
28+
29+
if !owned_query.text_query.is_empty() {
30+
conditions.push("posts_fts MATCH ?".to_string());
31+
params.push(Box::new(owned_query.text_query.clone()));
32+
}
33+
34+
for tag in &owned_query.tags {
35+
conditions.push(
36+
"EXISTS (SELECT 1 FROM json_each(posts.tags) WHERE value = ?)".to_string(),
37+
);
38+
params.push(Box::new(tag.clone()));
39+
}
40+
41+
if let Some(date) = &owned_query.from_date {
42+
conditions.push("posts.date >= ?".to_string());
43+
params.push(Box::new(date.clone()));
44+
}
45+
if let Some(date) = &owned_query.to_date {
46+
conditions.push("posts.date <= ?".to_string());
47+
params.push(Box::new(date.clone()));
48+
}
49+
50+
if !post_types_as_strings.is_empty() {
51+
let placeholders = post_types_as_strings
52+
.iter()
53+
.map(|_| "?")
54+
.collect::<Vec<_>>()
55+
.join(", ");
56+
conditions.push(format!("posts.content_type IN ({placeholders})"));
57+
for pt_str in post_types_as_strings {
58+
params.push(Box::new(pt_str.clone()));
59+
}
60+
}
61+
62+
let where_clause = if conditions.is_empty() {
63+
String::new()
64+
} else {
65+
format!("WHERE {}", conditions.join(" AND "))
66+
};
67+
68+
let order_clause = if owned_query.text_query.is_empty() {
69+
"ORDER BY date DESC".to_string()
70+
} else {
71+
"ORDER BY rank".to_string()
72+
};
73+
74+
(format!("{where_clause} {order_clause}"), params)
75+
}
76+
2277
pub async fn search(
2378
&self,
2479
query: &SearchQuery,
@@ -31,7 +86,7 @@ impl SearchService {
3186
tags: query.tags.clone(),
3287
from_date: query.from_date.clone(),
3388
to_date: query.to_date.clone(),
34-
post_type: Default::default(),
89+
post_type: Vec::default(),
3590
};
3691
let post_types_as_strings: Vec<String> = query
3792
.post_type
@@ -49,60 +104,11 @@ impl SearchService {
49104
"FROM posts INNER JOIN posts_fts ON posts.rowid = posts_fts.rowid".to_string()
50105
};
51106

52-
let mut conditions = vec![];
53-
let mut params: Vec<Box<dyn rusqlite::ToSql>> = vec![];
54-
55-
if !owned_query.text_query.is_empty() {
56-
conditions.push("posts_fts MATCH ?".to_string());
57-
params.push(Box::new(owned_query.text_query.clone()));
58-
}
59-
60-
for tag in &owned_query.tags {
61-
conditions.push(
62-
"EXISTS (SELECT 1 FROM json_each(posts.tags) WHERE value = ?)".to_string(),
63-
);
64-
params.push(Box::new(tag));
65-
}
66-
67-
if let Some(date) = &owned_query.from_date {
68-
conditions.push("posts.date >= ?".to_string());
69-
params.push(Box::new(date));
70-
}
71-
if let Some(date) = &owned_query.to_date {
72-
conditions.push("posts.date <= ?".to_string());
73-
params.push(Box::new(date));
74-
}
75-
76-
if !post_types_as_strings.is_empty() {
77-
let placeholders = post_types_as_strings
78-
.iter()
79-
.map(|_| "?")
80-
.collect::<Vec<_>>()
81-
.join(", ");
82-
conditions.push(format!("posts.content_type IN ({})", placeholders));
83-
for pt_str in &post_types_as_strings {
84-
params.push(Box::new(pt_str.clone()));
85-
}
86-
}
87-
88-
let where_clause = if !conditions.is_empty() {
89-
format!("WHERE {}", conditions.join(" AND "))
90-
} else {
91-
"".to_string()
92-
};
93-
94-
let order_clause = if owned_query.text_query.is_empty() {
95-
"ORDER BY date DESC".to_string()
96-
} else {
97-
"ORDER BY rank".to_string()
98-
};
107+
let (filter_clauses, mut params) = Self::build_search_query(&owned_query, &post_types_as_strings);
99108

100109
// Prepare count query first (borrows params immutably)
101110
let count_query = format!(
102-
"SELECT COUNT(*)
103-
{}
104-
{}",
105-
base_query, where_clause
111+
"SELECT COUNT(*) {base_query} {filter_clauses}"
106112
);
107113
let total: i64 = conn.query_row(
108114
&count_query,
@@ -112,16 +118,13 @@ impl SearchService {
112118

113119
// Main query to fetch posts (takes ownership of params)
114120
let posts_query = format!(
115-
"SELECT posts.*
116-
{}
117-
{}
118-
{}
119-
LIMIT ? OFFSET ?",
120-
base_query, where_clause, order_clause
121+
"SELECT posts.* {base_query} {filter_clauses} LIMIT ? OFFSET ?"
121122
);
122123

123124
let mut stmt = conn.prepare(&posts_query)?;
125+
#[allow(clippy::cast_possible_wrap)]
124126
params.push(Box::new(per_page as i64));
127+
#[allow(clippy::cast_possible_wrap)]
125128
params.push(Box::new(offset as i64));
126129

127130
// Execute query and collect results
@@ -134,7 +137,7 @@ impl SearchService {
134137
posts.push(post?);
135138
}
136139

137-
Ok::<_, anyhow::Error>((posts, total as usize))
140+
Ok::<_, anyhow::Error>((posts, usize::try_from(total)?))
138141
})
139142
.await?
140143
.context("Search execution failed")?;

0 commit comments

Comments
 (0)