1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
use crate::error::RangerError;
use crate::models::Backlog;
use sqlx::sqlite::SqliteConnection;
pub async fn create(conn: &mut SqliteConnection, name: &str) -> Result<Backlog, RangerError> {
let backlog = sqlx::query_as::<_, Backlog>(
"INSERT INTO backlogs (name) VALUES (?) RETURNING id, name, created_at, updated_at",
)
.bind(name)
.fetch_one(&mut *conn)
.await?;
Ok(backlog)
}
pub async fn list(conn: &mut SqliteConnection) -> Result<Vec<Backlog>, RangerError> {
let backlogs = sqlx::query_as::<_, Backlog>(
"SELECT id, name, created_at, updated_at FROM backlogs ORDER BY name",
)
.fetch_all(&mut *conn)
.await?;
Ok(backlogs)
}
pub async fn get_by_name(conn: &mut SqliteConnection, name: &str) -> Result<Backlog, RangerError> {
let backlog = sqlx::query_as::<_, Backlog>(
"SELECT id, name, created_at, updated_at FROM backlogs WHERE name = ?",
)
.bind(name)
.fetch_optional(&mut *conn)
.await?
.ok_or_else(|| RangerError::BacklogNotFound(name.to_string()))?;
Ok(backlog)
}
pub async fn delete(conn: &mut SqliteConnection, name: &str) -> Result<Backlog, RangerError> {
let backlog = get_by_name(&mut *conn, name).await?;
sqlx::query("DELETE FROM backlogs WHERE id = ?")
.bind(backlog.id)
.execute(&mut *conn)
.await?;
Ok(backlog)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::db;
use tempfile::tempdir;
async fn test_pool() -> sqlx::SqlitePool {
let dir = tempdir().unwrap();
let dir = Box::leak(Box::new(dir));
db::connect(&dir.path().join("test.db")).await.unwrap()
}
#[tokio::test]
async fn create_and_get_backlog() {
let pool = test_pool().await;
let mut conn = pool.acquire().await.unwrap();
let backlog = create(&mut conn, "My Backlog").await.unwrap();
assert_eq!(backlog.name, "My Backlog");
let fetched = get_by_name(&mut conn, "My Backlog").await.unwrap();
assert_eq!(fetched.id, backlog.id);
}
#[tokio::test]
async fn list_backlogs() {
let pool = test_pool().await;
let mut conn = pool.acquire().await.unwrap();
create(&mut conn, "First").await.unwrap();
create(&mut conn, "Second").await.unwrap();
let backlogs = list(&mut conn).await.unwrap();
assert_eq!(backlogs.len(), 2);
}
#[tokio::test]
async fn get_by_name_not_found() {
let pool = test_pool().await;
let mut conn = pool.acquire().await.unwrap();
let result = get_by_name(&mut conn, "nonexistent").await;
assert!(result.is_err());
}
#[tokio::test]
async fn delete_backlog() {
let pool = test_pool().await;
let mut conn = pool.acquire().await.unwrap();
create(&mut conn, "ToDelete").await.unwrap();
let deleted = delete(&mut conn, "ToDelete").await.unwrap();
assert_eq!(deleted.name, "ToDelete");
let result = get_by_name(&mut conn, "ToDelete").await;
assert!(result.is_err());
}
#[tokio::test]
async fn delete_backlog_not_found() {
let pool = test_pool().await;
let mut conn = pool.acquire().await.unwrap();
let result = delete(&mut conn, "nonexistent").await;
assert!(result.is_err());
}
}