Pass connections instead of pool to ops functions
Enables callers to compose multiple ops within a single
transaction when atomicity is needed.
Assisted-by: Claude Opus 4.6 via pi
diff --git a/src/bin/ranger/commands/backlog.rs b/src/bin/ranger/commands/backlog.rs
index 7afea79..a86d3f3 100644
--- a/src/bin/ranger/commands/backlog.rs
+++ b/src/bin/ranger/commands/backlog.rs
@@ -26,22 +26,24 @@ pub enum BacklogCommands {
}
pub async fn run(pool: &SqlitePool, command: BacklogCommands, json: bool) -> Result<()> {
+ let mut conn = pool.acquire().await?;
+
match command {
BacklogCommands::Create { name } => {
- let backlog = ops::backlog::create(pool, &name).await?;
+ let backlog = ops::backlog::create(&mut conn, &name).await?;
output::print(&backlog, json, print_backlog);
}
BacklogCommands::List => {
- let backlogs = ops::backlog::list(pool).await?;
+ let backlogs = ops::backlog::list(&mut conn).await?;
output::print_list(&backlogs, json, print_backlog);
}
BacklogCommands::Show { name } => {
- let backlog = ops::backlog::get_by_name(pool, &name).await?;
+ let backlog = ops::backlog::get_by_name(&mut conn, &name).await?;
if json {
let mut state_groups = serde_json::Map::new();
for state in [State::Done, State::InProgress, State::Queued, State::Icebox] {
- let tasks = ops::task::list(pool, backlog.id, Some(state.clone())).await?;
+ let tasks = ops::task::list(&mut conn, backlog.id, Some(state.clone())).await?;
if !tasks.is_empty() {
state_groups
.insert(state.to_string(), serde_json::to_value(&tasks).unwrap());
@@ -56,7 +58,7 @@ pub async fn run(pool: &SqlitePool, command: BacklogCommands, json: bool) -> Res
print_backlog_detail(&backlog);
for state in [State::Done, State::InProgress, State::Queued, State::Icebox] {
- let tasks = ops::task::list(pool, backlog.id, Some(state.clone())).await?;
+ let tasks = ops::task::list(&mut conn, backlog.id, Some(state.clone())).await?;
if !tasks.is_empty() {
println!("\n[{}]", state);
for t in &tasks {
diff --git a/src/bin/ranger/commands/blocker.rs b/src/bin/ranger/commands/blocker.rs
index 9a126c8..cf3f958 100644
--- a/src/bin/ranger/commands/blocker.rs
+++ b/src/bin/ranger/commands/blocker.rs
@@ -24,19 +24,21 @@ pub enum BlockerCommands {
}
pub async fn run(pool: &SqlitePool, command: BlockerCommands, json: bool) -> Result<()> {
+ let mut conn = pool.acquire().await?;
+
match command {
BlockerCommands::Add { task, blocked_by } => {
- let t = ops::task::get_by_key_prefix(pool, &task).await?;
- let bt = ops::task::get_by_key_prefix(pool, &blocked_by).await?;
- let blocker = ops::blocker::add(pool, t.id, bt.id).await?;
+ let t = ops::task::get_by_key_prefix(&mut conn, &task).await?;
+ let bt = ops::task::get_by_key_prefix(&mut conn, &blocked_by).await?;
+ let blocker = ops::blocker::add(&mut conn, t.id, bt.id).await?;
output::print(&blocker, json, |_| {
println!("{} blocked by {} {}", &t.key[..8], &bt.key[..8], bt.title);
});
}
BlockerCommands::Remove { task, blocked_by } => {
- let t = ops::task::get_by_key_prefix(pool, &task).await?;
- let bt = ops::task::get_by_key_prefix(pool, &blocked_by).await?;
- ops::blocker::remove(pool, t.id, bt.id).await?;
+ let t = ops::task::get_by_key_prefix(&mut conn, &task).await?;
+ let bt = ops::task::get_by_key_prefix(&mut conn, &blocked_by).await?;
+ ops::blocker::remove(&mut conn, t.id, bt.id).await?;
println!("Removed blocker {} from {}", &bt.key[..8], &t.key[..8]);
}
}
diff --git a/src/bin/ranger/commands/comment.rs b/src/bin/ranger/commands/comment.rs
index d304ce1..15704d6 100644
--- a/src/bin/ranger/commands/comment.rs
+++ b/src/bin/ranger/commands/comment.rs
@@ -22,17 +22,19 @@ pub enum CommentCommands {
}
pub async fn run(pool: &SqlitePool, command: CommentCommands, json: bool) -> Result<()> {
+ let mut conn = pool.acquire().await?;
+
match command {
CommentCommands::Add { task, body } => {
- let t = ops::task::get_by_key_prefix(pool, &task).await?;
- let comment = ops::comment::add(pool, t.id, &body).await?;
+ let t = ops::task::get_by_key_prefix(&mut conn, &task).await?;
+ let comment = ops::comment::add(&mut conn, t.id, &body).await?;
output::print(&comment, json, |c| {
println!("[{}] {}", c.created_at, c.body);
});
}
CommentCommands::List { task } => {
- let t = ops::task::get_by_key_prefix(pool, &task).await?;
- let comments = ops::comment::list(pool, t.id).await?;
+ let t = ops::task::get_by_key_prefix(&mut conn, &task).await?;
+ let comments = ops::comment::list(&mut conn, t.id).await?;
output::print_list(&comments, json, |c| {
println!("[{}] {}", c.created_at, c.body);
});
diff --git a/src/bin/ranger/commands/tag.rs b/src/bin/ranger/commands/tag.rs
index 4ff0487..b6e5826 100644
--- a/src/bin/ranger/commands/tag.rs
+++ b/src/bin/ranger/commands/tag.rs
@@ -12,9 +12,11 @@ pub enum TagCommands {
}
pub async fn run(pool: &SqlitePool, command: TagCommands, json: bool) -> Result<()> {
+ let mut conn = pool.acquire().await?;
+
match command {
TagCommands::List => {
- let tags = ops::tag::list(pool).await?;
+ let tags = ops::tag::list(&mut conn).await?;
output::print_list(&tags, json, |t| {
println!("{}", t.name);
});
diff --git a/src/bin/ranger/commands/task.rs b/src/bin/ranger/commands/task.rs
index 8cb2bc6..f333300 100644
--- a/src/bin/ranger/commands/task.rs
+++ b/src/bin/ranger/commands/task.rs
@@ -1,6 +1,6 @@
use clap::{Args, Subcommand};
use color_eyre::eyre::Result;
-use ranger::db::SqlitePool;
+use ranger::db::{SqliteConnection, SqlitePool};
use ranger::models::{State, Task};
use ranger::ops;
@@ -18,14 +18,14 @@ pub struct PositionArgs {
}
impl PositionArgs {
- async fn resolve(self, pool: &SqlitePool) -> Result<(Option<i64>, Option<i64>)> {
+ async fn resolve(self, conn: &mut SqliteConnection) -> Result<(Option<i64>, Option<i64>)> {
let before_id = if let Some(k) = &self.before {
- Some(ops::task::get_by_key_prefix(pool, k).await?.id)
+ Some(ops::task::get_by_key_prefix(conn, k).await?.id)
} else {
None
};
let after_id = if let Some(k) = &self.after {
- Some(ops::task::get_by_key_prefix(pool, k).await?.id)
+ Some(ops::task::get_by_key_prefix(conn, k).await?.id)
} else {
None
};
@@ -36,7 +36,6 @@ impl PositionArgs {
#[derive(Subcommand)]
pub enum TaskCommands {
/// Create a new task
- #[command(visible_alias = "new")]
Create {
/// Task title
title: String,
@@ -59,7 +58,6 @@ pub enum TaskCommands {
position: PositionArgs,
},
/// List tasks
- #[command(visible_alias = "ls")]
List {
/// Filter by backlog key or prefix
#[arg(long, env = "RANGER_DEFAULT_BACKLOG")]
@@ -88,7 +86,6 @@ pub enum TaskCommands {
state: Option<String>,
},
/// Move a task's position within a backlog
- #[command(visible_alias = "mv")]
Move {
/// Task key or prefix
key: String,
@@ -115,7 +112,6 @@ pub enum TaskCommands {
backlog: String,
},
/// Delete a task entirely
- #[command(visible_alias = "rm")]
Delete {
/// Task key or prefix
key: String,
@@ -123,6 +119,8 @@ pub enum TaskCommands {
}
pub async fn run(pool: &SqlitePool, command: TaskCommands, json: bool) -> Result<()> {
+ let mut conn = pool.acquire().await?;
+
match command {
TaskCommands::Create {
title,
@@ -133,17 +131,21 @@ pub async fn run(pool: &SqlitePool, command: TaskCommands, json: bool) -> Result
tag,
position,
} => {
- let bl = ops::backlog::get_by_name(pool, &backlog).await?;
+ let bl = ops::backlog::get_by_name(&mut conn, &backlog).await?;
let parent_id = if let Some(parent_key) = &parent {
- Some(ops::task::get_by_key_prefix(pool, parent_key).await?.id)
+ Some(
+ ops::task::get_by_key_prefix(&mut conn, parent_key)
+ .await?
+ .id,
+ )
} else {
None
};
- let (before_id, after_id) = position.resolve(pool).await?;
+ let (before_id, after_id) = position.resolve(&mut conn).await?;
let state = state.map(|s| s.parse::<State>()).transpose()?;
let task = ops::task::create(
- pool,
+ &mut conn,
ops::task::CreateTask {
title: &title,
backlog_id: bl.id,
@@ -158,8 +160,8 @@ pub async fn run(pool: &SqlitePool, command: TaskCommands, json: bool) -> Result
if let Some(tags) = &tag {
for tag_name in tags.split(',').map(str::trim) {
- let t = ops::tag::get_or_create(pool, tag_name).await?;
- ops::tag::add_to_task(pool, task.id, t.id).await?;
+ let t = ops::tag::get_or_create(&mut conn, tag_name).await?;
+ ops::tag::add_to_task(&mut conn, task.id, t.id).await?;
}
}
@@ -169,15 +171,15 @@ pub async fn run(pool: &SqlitePool, command: TaskCommands, json: bool) -> Result
let state = state.map(|s| s.parse::<State>()).transpose()?;
if let Some(backlog_key) = &backlog {
- let bl = ops::backlog::get_by_name(pool, backlog_key).await?;
- let tasks = ops::task::list(pool, bl.id, state).await?;
+ let bl = ops::backlog::get_by_name(&mut conn, backlog_key).await?;
+ let tasks = ops::task::list(&mut conn, bl.id, state).await?;
output::print_list(&tasks, json, print_task);
} else {
// List all tasks (no backlog filter)
- let backlogs = ops::backlog::list(pool).await?;
+ let backlogs = ops::backlog::list(&mut conn).await?;
let mut all_tasks = Vec::new();
for bl in &backlogs {
- let tasks = ops::task::list(pool, bl.id, state.clone()).await?;
+ let tasks = ops::task::list(&mut conn, bl.id, state.clone()).await?;
for t in tasks {
if !all_tasks.iter().any(|at: &Task| at.id == t.id) {
all_tasks.push(t);
@@ -188,10 +190,10 @@ pub async fn run(pool: &SqlitePool, command: TaskCommands, json: bool) -> Result
}
}
TaskCommands::Show { key } => {
- let task = ops::task::get_by_key_prefix(pool, &key).await?;
- let comments = ops::comment::list(pool, task.id).await?;
- let tags = ops::tag::list_for_task(pool, task.id).await?;
- let blockers = ops::blocker::list_for_task(pool, task.id).await?;
+ let task = ops::task::get_by_key_prefix(&mut conn, &key).await?;
+ let comments = ops::comment::list(&mut conn, task.id).await?;
+ let tags = ops::tag::list_for_task(&mut conn, task.id).await?;
+ let blockers = ops::blocker::list_for_task(&mut conn, task.id).await?;
if json {
let detail = serde_json::json!({
@@ -210,7 +212,8 @@ pub async fn run(pool: &SqlitePool, command: TaskCommands, json: bool) -> Result
if !blockers.is_empty() {
println!("Blocked by:");
for b in &blockers {
- if let Ok(bt) = ops::task::get_by_id(pool, b.blocked_by_task_id).await {
+ if let Ok(bt) = ops::task::get_by_id(&mut conn, b.blocked_by_task_id).await
+ {
println!(" {} {}", &bt.key[..8], bt.title);
}
}
@@ -232,9 +235,9 @@ pub async fn run(pool: &SqlitePool, command: TaskCommands, json: bool) -> Result
} => {
let state = state.map(|s| s.parse::<State>()).transpose()?;
- let task = ops::task::get_by_key_prefix(pool, &key).await?;
+ let task = ops::task::get_by_key_prefix(&mut conn, &key).await?;
let updated = ops::task::edit(
- pool,
+ &mut conn,
task.id,
title.as_deref(),
description.as_deref(),
@@ -248,28 +251,28 @@ pub async fn run(pool: &SqlitePool, command: TaskCommands, json: bool) -> Result
backlog,
position,
} => {
- let bl = ops::backlog::get_by_name(pool, &backlog).await?;
- let task = ops::task::get_by_key_prefix(pool, &key).await?;
- let (before_id, after_id) = position.resolve(pool).await?;
+ let bl = ops::backlog::get_by_name(&mut conn, &backlog).await?;
+ let task = ops::task::get_by_key_prefix(&mut conn, &key).await?;
+ let (before_id, after_id) = position.resolve(&mut conn).await?;
- ops::task::move_task(pool, task.id, bl.id, before_id, after_id).await?;
+ ops::task::move_task(&mut conn, task.id, bl.id, before_id, after_id).await?;
println!("Moved {} {}", &task.key[..8], task.title);
}
TaskCommands::Add { task, backlog } => {
- let t = ops::task::get_by_key_prefix(pool, &task).await?;
- let bl = ops::backlog::get_by_name(pool, &backlog).await?;
- ops::task::add_to_backlog(pool, t.id, bl.id).await?;
+ let t = ops::task::get_by_key_prefix(&mut conn, &task).await?;
+ let bl = ops::backlog::get_by_name(&mut conn, &backlog).await?;
+ ops::task::add_to_backlog(&mut conn, t.id, bl.id).await?;
println!("Added {} to {}", &t.key[..8], bl.name);
}
TaskCommands::Remove { task, backlog } => {
- let t = ops::task::get_by_key_prefix(pool, &task).await?;
- let bl = ops::backlog::get_by_name(pool, &backlog).await?;
- ops::task::remove_from_backlog(pool, t.id, bl.id).await?;
+ let t = ops::task::get_by_key_prefix(&mut conn, &task).await?;
+ let bl = ops::backlog::get_by_name(&mut conn, &backlog).await?;
+ ops::task::remove_from_backlog(&mut conn, t.id, bl.id).await?;
println!("Removed {} from {}", &t.key[..8], bl.name);
}
TaskCommands::Delete { key } => {
- let task = ops::task::get_by_key_prefix(pool, &key).await?;
- ops::task::delete(pool, task.id).await?;
+ let task = ops::task::get_by_key_prefix(&mut conn, &key).await?;
+ ops::task::delete(&mut conn, task.id).await?;
println!("Deleted {} {}", &task.key[..8], task.title);
}
}
diff --git a/src/db.rs b/src/db.rs
index 0eaa40c..35d6f6c 100644
--- a/src/db.rs
+++ b/src/db.rs
@@ -3,6 +3,7 @@ use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions};
use std::path::Path;
pub use sqlx::SqlitePool;
+pub type SqliteConnection = sqlx::sqlite::SqliteConnection;
pub async fn connect(path: &Path) -> Result<SqlitePool, RangerError> {
if let Some(parent) = path.parent() {
diff --git a/src/ops/backlog.rs b/src/ops/backlog.rs
index 4f48ce7..31babef 100644
--- a/src/ops/backlog.rs
+++ b/src/ops/backlog.rs
@@ -1,9 +1,9 @@
use crate::error::RangerError;
use crate::key;
use crate::models::Backlog;
-use sqlx::SqlitePool;
+use sqlx::sqlite::SqliteConnection;
-pub async fn create(pool: &SqlitePool, name: &str) -> Result<Backlog, RangerError> {
+pub async fn create(conn: &mut SqliteConnection, name: &str) -> Result<Backlog, RangerError> {
// key column still exists in the schema but is unused; generate a dummy value
let key = key::generate_key();
let backlog = sqlx::query_as::<_, Backlog>(
@@ -11,26 +11,26 @@ pub async fn create(pool: &SqlitePool, name: &str) -> Result<Backlog, RangerErro
)
.bind(&key)
.bind(name)
- .fetch_one(pool)
+ .fetch_one(&mut *conn)
.await?;
Ok(backlog)
}
-pub async fn list(pool: &SqlitePool) -> Result<Vec<Backlog>, RangerError> {
+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(pool)
+ .fetch_all(&mut *conn)
.await?;
Ok(backlogs)
}
-pub async fn get_by_name(pool: &SqlitePool, name: &str) -> Result<Backlog, RangerError> {
+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(pool)
+ .fetch_optional(&mut *conn)
.await?
.ok_or_else(|| RangerError::KeyNotFound(name.to_string()))?;
Ok(backlog)
@@ -42,7 +42,7 @@ mod tests {
use crate::db;
use tempfile::tempdir;
- async fn test_pool() -> SqlitePool {
+ 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()
@@ -51,27 +51,30 @@ mod tests {
#[tokio::test]
async fn create_and_get_backlog() {
let pool = test_pool().await;
- let backlog = create(&pool, "My Backlog").await.unwrap();
+ 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(&pool, "My Backlog").await.unwrap();
+ 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;
- create(&pool, "First").await.unwrap();
- create(&pool, "Second").await.unwrap();
+ let mut conn = pool.acquire().await.unwrap();
+ create(&mut conn, "First").await.unwrap();
+ create(&mut conn, "Second").await.unwrap();
- let backlogs = list(&pool).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 result = get_by_name(&pool, "nonexistent").await;
+ let mut conn = pool.acquire().await.unwrap();
+ let result = get_by_name(&mut conn, "nonexistent").await;
assert!(result.is_err());
}
}
diff --git a/src/ops/blocker.rs b/src/ops/blocker.rs
index 83876cf..5446cc6 100644
--- a/src/ops/blocker.rs
+++ b/src/ops/blocker.rs
@@ -1,9 +1,9 @@
use crate::error::RangerError;
use crate::models::Blocker;
-use sqlx::SqlitePool;
+use sqlx::sqlite::SqliteConnection;
pub async fn add(
- pool: &SqlitePool,
+ conn: &mut SqliteConnection,
task_id: i64,
blocked_by_task_id: i64,
) -> Result<Blocker, RangerError> {
@@ -13,30 +13,33 @@ pub async fn add(
)
.bind(task_id)
.bind(blocked_by_task_id)
- .fetch_one(pool)
+ .fetch_one(&mut *conn)
.await?;
Ok(blocker)
}
pub async fn remove(
- pool: &SqlitePool,
+ conn: &mut SqliteConnection,
task_id: i64,
blocked_by_task_id: i64,
) -> Result<(), RangerError> {
sqlx::query("DELETE FROM blockers WHERE task_id = ? AND blocked_by_task_id = ?")
.bind(task_id)
.bind(blocked_by_task_id)
- .execute(pool)
+ .execute(&mut *conn)
.await?;
Ok(())
}
-pub async fn list_for_task(pool: &SqlitePool, task_id: i64) -> Result<Vec<Blocker>, RangerError> {
+pub async fn list_for_task(
+ conn: &mut SqliteConnection,
+ task_id: i64,
+) -> Result<Vec<Blocker>, RangerError> {
let blockers = sqlx::query_as::<_, Blocker>(
"SELECT id, task_id, blocked_by_task_id FROM blockers WHERE task_id = ?",
)
.bind(task_id)
- .fetch_all(pool)
+ .fetch_all(&mut *conn)
.await?;
Ok(blockers)
}
@@ -48,7 +51,7 @@ mod tests {
use crate::ops::{backlog, task};
use tempfile::tempdir;
- async fn test_pool() -> SqlitePool {
+ 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()
@@ -57,9 +60,10 @@ mod tests {
#[tokio::test]
async fn add_and_list_blockers() {
let pool = test_pool().await;
- let bl = backlog::create(&pool, "Test").await.unwrap();
+ let mut conn = pool.acquire().await.unwrap();
+ let bl = backlog::create(&mut conn, "Test").await.unwrap();
let t1 = task::create(
- &pool,
+ &mut conn,
task::CreateTask {
title: "Blocked",
backlog_id: bl.id,
@@ -73,7 +77,7 @@ mod tests {
.await
.unwrap();
let t2 = task::create(
- &pool,
+ &mut conn,
task::CreateTask {
title: "Blocker",
backlog_id: bl.id,
@@ -87,9 +91,9 @@ mod tests {
.await
.unwrap();
- add(&pool, t1.id, t2.id).await.unwrap();
+ add(&mut conn, t1.id, t2.id).await.unwrap();
- let blockers = list_for_task(&pool, t1.id).await.unwrap();
+ let blockers = list_for_task(&mut conn, t1.id).await.unwrap();
assert_eq!(blockers.len(), 1);
assert_eq!(blockers[0].blocked_by_task_id, t2.id);
}
@@ -97,9 +101,10 @@ mod tests {
#[tokio::test]
async fn remove_blocker() {
let pool = test_pool().await;
- let bl = backlog::create(&pool, "Test").await.unwrap();
+ let mut conn = pool.acquire().await.unwrap();
+ let bl = backlog::create(&mut conn, "Test").await.unwrap();
let t1 = task::create(
- &pool,
+ &mut conn,
task::CreateTask {
title: "Blocked",
backlog_id: bl.id,
@@ -113,7 +118,7 @@ mod tests {
.await
.unwrap();
let t2 = task::create(
- &pool,
+ &mut conn,
task::CreateTask {
title: "Blocker",
backlog_id: bl.id,
@@ -127,10 +132,10 @@ mod tests {
.await
.unwrap();
- add(&pool, t1.id, t2.id).await.unwrap();
- remove(&pool, t1.id, t2.id).await.unwrap();
+ add(&mut conn, t1.id, t2.id).await.unwrap();
+ remove(&mut conn, t1.id, t2.id).await.unwrap();
- let blockers = list_for_task(&pool, t1.id).await.unwrap();
+ let blockers = list_for_task(&mut conn, t1.id).await.unwrap();
assert_eq!(blockers.len(), 0);
}
}
diff --git a/src/ops/comment.rs b/src/ops/comment.rs
index 8196b74..fe3f966 100644
--- a/src/ops/comment.rs
+++ b/src/ops/comment.rs
@@ -1,25 +1,29 @@
use crate::error::RangerError;
use crate::models::Comment;
-use sqlx::SqlitePool;
+use sqlx::sqlite::SqliteConnection;
-pub async fn add(pool: &SqlitePool, task_id: i64, body: &str) -> Result<Comment, RangerError> {
+pub async fn add(
+ conn: &mut SqliteConnection,
+ task_id: i64,
+ body: &str,
+) -> Result<Comment, RangerError> {
let comment = sqlx::query_as::<_, Comment>(
"INSERT INTO comments (task_id, body) VALUES (?, ?) \
RETURNING id, task_id, body, created_at",
)
.bind(task_id)
.bind(body)
- .fetch_one(pool)
+ .fetch_one(&mut *conn)
.await?;
Ok(comment)
}
-pub async fn list(pool: &SqlitePool, task_id: i64) -> Result<Vec<Comment>, RangerError> {
+pub async fn list(conn: &mut SqliteConnection, task_id: i64) -> Result<Vec<Comment>, RangerError> {
let comments = sqlx::query_as::<_, Comment>(
"SELECT id, task_id, body, created_at FROM comments WHERE task_id = ? ORDER BY created_at",
)
.bind(task_id)
- .fetch_all(pool)
+ .fetch_all(&mut *conn)
.await?;
Ok(comments)
}
@@ -40,9 +44,10 @@ mod tests {
#[tokio::test]
async fn add_and_list_comments() {
let pool = test_pool().await;
- let bl = backlog::create(&pool, "Test").await.unwrap();
+ let mut conn = pool.acquire().await.unwrap();
+ let bl = backlog::create(&mut conn, "Test").await.unwrap();
let t = task::create(
- &pool,
+ &mut conn,
task::CreateTask {
title: "Task",
backlog_id: bl.id,
@@ -56,10 +61,10 @@ mod tests {
.await
.unwrap();
- add(&pool, t.id, "First comment").await.unwrap();
- add(&pool, t.id, "Second comment").await.unwrap();
+ add(&mut conn, t.id, "First comment").await.unwrap();
+ add(&mut conn, t.id, "Second comment").await.unwrap();
- let comments = list(&pool, t.id).await.unwrap();
+ let comments = list(&mut conn, t.id).await.unwrap();
assert_eq!(comments.len(), 2);
assert_eq!(comments[0].body, "First comment");
assert_eq!(comments[1].body, "Second comment");
diff --git a/src/ops/tag.rs b/src/ops/tag.rs
index 178228c..e09d842 100644
--- a/src/ops/tag.rs
+++ b/src/ops/tag.rs
@@ -1,46 +1,53 @@
use crate::error::RangerError;
use crate::models::Tag;
-use sqlx::SqlitePool;
+use sqlx::sqlite::SqliteConnection;
/// Get or create a tag by name.
-pub async fn get_or_create(pool: &SqlitePool, name: &str) -> Result<Tag, RangerError> {
+pub async fn get_or_create(conn: &mut SqliteConnection, name: &str) -> Result<Tag, RangerError> {
// Try insert, ignore conflict
sqlx::query("INSERT OR IGNORE INTO tags (name) VALUES (?)")
.bind(name)
- .execute(pool)
+ .execute(&mut *conn)
.await?;
let tag = sqlx::query_as::<_, Tag>("SELECT id, name FROM tags WHERE name = ?")
.bind(name)
- .fetch_one(pool)
+ .fetch_one(&mut *conn)
.await?;
Ok(tag)
}
-pub async fn list(pool: &SqlitePool) -> Result<Vec<Tag>, RangerError> {
+pub async fn list(conn: &mut SqliteConnection) -> Result<Vec<Tag>, RangerError> {
let tags = sqlx::query_as::<_, Tag>("SELECT id, name FROM tags ORDER BY name")
- .fetch_all(pool)
+ .fetch_all(&mut *conn)
.await?;
Ok(tags)
}
-pub async fn add_to_task(pool: &SqlitePool, task_id: i64, tag_id: i64) -> Result<(), RangerError> {
+pub async fn add_to_task(
+ conn: &mut SqliteConnection,
+ task_id: i64,
+ tag_id: i64,
+) -> Result<(), RangerError> {
sqlx::query("INSERT OR IGNORE INTO task_tags (task_id, tag_id) VALUES (?, ?)")
.bind(task_id)
.bind(tag_id)
- .execute(pool)
+ .execute(&mut *conn)
.await?;
Ok(())
}
-pub async fn list_for_task(pool: &SqlitePool, task_id: i64) -> Result<Vec<Tag>, RangerError> {
+pub async fn list_for_task(
+ conn: &mut SqliteConnection,
+ task_id: i64,
+) -> Result<Vec<Tag>, RangerError> {
let tags = sqlx::query_as::<_, Tag>(
"SELECT t.id, t.name FROM tags t \
JOIN task_tags tt ON tt.tag_id = t.id \
WHERE tt.task_id = ? ORDER BY t.name",
)
.bind(task_id)
- .fetch_all(pool)
+ .fetch_all(&mut *conn)
.await?;
Ok(tags)
}
@@ -52,7 +59,7 @@ mod tests {
use crate::ops::{backlog, task};
use tempfile::tempdir;
- async fn test_pool() -> SqlitePool {
+ 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()
@@ -61,18 +68,20 @@ mod tests {
#[tokio::test]
async fn get_or_create_is_idempotent() {
let pool = test_pool().await;
- let t1 = get_or_create(&pool, "urgent").await.unwrap();
- let t2 = get_or_create(&pool, "urgent").await.unwrap();
+ let mut conn = pool.acquire().await.unwrap();
+ let t1 = get_or_create(&mut conn, "urgent").await.unwrap();
+ let t2 = get_or_create(&mut conn, "urgent").await.unwrap();
assert_eq!(t1.id, t2.id);
}
#[tokio::test]
async fn list_tags() {
let pool = test_pool().await;
- get_or_create(&pool, "beta").await.unwrap();
- get_or_create(&pool, "alpha").await.unwrap();
+ let mut conn = pool.acquire().await.unwrap();
+ get_or_create(&mut conn, "beta").await.unwrap();
+ get_or_create(&mut conn, "alpha").await.unwrap();
- let tags = list(&pool).await.unwrap();
+ let tags = list(&mut conn).await.unwrap();
assert_eq!(tags.len(), 2);
assert_eq!(tags[0].name, "alpha");
assert_eq!(tags[1].name, "beta");
@@ -81,9 +90,10 @@ mod tests {
#[tokio::test]
async fn add_tag_to_task_and_list() {
let pool = test_pool().await;
- let bl = backlog::create(&pool, "Test").await.unwrap();
+ let mut conn = pool.acquire().await.unwrap();
+ let bl = backlog::create(&mut conn, "Test").await.unwrap();
let t = task::create(
- &pool,
+ &mut conn,
task::CreateTask {
title: "Task",
backlog_id: bl.id,
@@ -96,11 +106,11 @@ mod tests {
)
.await
.unwrap();
- let tag = get_or_create(&pool, "important").await.unwrap();
+ let tag = get_or_create(&mut conn, "important").await.unwrap();
- add_to_task(&pool, t.id, tag.id).await.unwrap();
+ add_to_task(&mut conn, t.id, tag.id).await.unwrap();
- let tags = list_for_task(&pool, t.id).await.unwrap();
+ let tags = list_for_task(&mut conn, t.id).await.unwrap();
assert_eq!(tags.len(), 1);
assert_eq!(tags[0].name, "important");
}
@@ -108,9 +118,10 @@ mod tests {
#[tokio::test]
async fn add_tag_to_task_is_idempotent() {
let pool = test_pool().await;
- let bl = backlog::create(&pool, "Test").await.unwrap();
+ let mut conn = pool.acquire().await.unwrap();
+ let bl = backlog::create(&mut conn, "Test").await.unwrap();
let t = task::create(
- &pool,
+ &mut conn,
task::CreateTask {
title: "Task",
backlog_id: bl.id,
@@ -123,12 +134,12 @@ mod tests {
)
.await
.unwrap();
- let tag = get_or_create(&pool, "dup").await.unwrap();
+ let tag = get_or_create(&mut conn, "dup").await.unwrap();
- add_to_task(&pool, t.id, tag.id).await.unwrap();
- add_to_task(&pool, t.id, tag.id).await.unwrap();
+ add_to_task(&mut conn, t.id, tag.id).await.unwrap();
+ add_to_task(&mut conn, t.id, tag.id).await.unwrap();
- let tags = list_for_task(&pool, t.id).await.unwrap();
+ let tags = list_for_task(&mut conn, t.id).await.unwrap();
assert_eq!(tags.len(), 1);
}
}
diff --git a/src/ops/task.rs b/src/ops/task.rs
index 3a58069..1ddd695 100644
--- a/src/ops/task.rs
+++ b/src/ops/task.rs
@@ -2,7 +2,7 @@ use crate::error::RangerError;
use crate::key;
use crate::models::{State, Task};
use crate::position;
-use sqlx::SqlitePool;
+use sqlx::sqlite::SqliteConnection;
pub struct CreateTask<'a> {
pub title: &'a str,
@@ -14,7 +14,10 @@ pub struct CreateTask<'a> {
pub after_task_id: Option<i64>,
}
-pub async fn create(pool: &SqlitePool, params: CreateTask<'_>) -> Result<Task, RangerError> {
+pub async fn create(
+ conn: &mut SqliteConnection,
+ params: CreateTask<'_>,
+) -> Result<Task, RangerError> {
let key = key::generate_key();
let state = params.state.unwrap_or(State::Icebox);
@@ -28,11 +31,11 @@ pub async fn create(pool: &SqlitePool, params: CreateTask<'_>) -> Result<Task, R
.bind(params.title)
.bind(params.description)
.bind(state.as_str())
- .fetch_one(pool)
+ .fetch_one(&mut *conn)
.await?;
let new_pos = resolve_position(
- pool,
+ &mut *conn,
params.backlog_id,
task.id,
params.before_task_id,
@@ -44,14 +47,14 @@ pub async fn create(pool: &SqlitePool, params: CreateTask<'_>) -> Result<Task, R
.bind(params.backlog_id)
.bind(task.id)
.bind(&new_pos)
- .execute(pool)
+ .execute(&mut *conn)
.await?;
Ok(task)
}
pub async fn list(
- pool: &SqlitePool,
+ conn: &mut SqliteConnection,
backlog_id: i64,
state_filter: Option<State>,
) -> Result<Vec<Task>, RangerError> {
@@ -66,7 +69,7 @@ pub async fn list(
)
.bind(backlog_id)
.bind(state.as_str())
- .fetch_all(pool)
+ .fetch_all(&mut *conn)
.await?
} else {
sqlx::query_as::<_, Task>(
@@ -78,31 +81,34 @@ pub async fn list(
ORDER BY bt.position",
)
.bind(backlog_id)
- .fetch_all(pool)
+ .fetch_all(&mut *conn)
.await?
};
Ok(tasks)
}
-pub async fn get_by_id(pool: &SqlitePool, id: i64) -> Result<Task, RangerError> {
+pub async fn get_by_id(conn: &mut SqliteConnection, id: i64) -> Result<Task, RangerError> {
let task = sqlx::query_as::<_, Task>(
"SELECT id, key, parent_id, title, description, state, created_at, updated_at \
FROM tasks WHERE id = ?",
)
.bind(id)
- .fetch_one(pool)
+ .fetch_one(&mut *conn)
.await?;
Ok(task)
}
-pub async fn get_by_key_prefix(pool: &SqlitePool, prefix: &str) -> Result<Task, RangerError> {
+pub async fn get_by_key_prefix(
+ conn: &mut SqliteConnection,
+ prefix: &str,
+) -> Result<Task, RangerError> {
let pattern = format!("{prefix}%");
let matches = sqlx::query_as::<_, Task>(
"SELECT id, key, parent_id, title, description, state, created_at, updated_at \
FROM tasks WHERE key LIKE ?",
)
.bind(&pattern)
- .fetch_all(pool)
+ .fetch_all(&mut *conn)
.await?;
match matches.len() {
@@ -113,7 +119,7 @@ pub async fn get_by_key_prefix(pool: &SqlitePool, prefix: &str) -> Result<Task,
}
pub async fn edit(
- pool: &SqlitePool,
+ conn: &mut SqliteConnection,
task_id: i64,
title: Option<&str>,
description: Option<&str>,
@@ -123,21 +129,21 @@ pub async fn edit(
sqlx::query("UPDATE tasks SET title = ?, updated_at = strftime('%Y-%m-%dT%H:%M:%SZ', 'now') WHERE id = ?")
.bind(title)
.bind(task_id)
- .execute(pool)
+ .execute(&mut *conn)
.await?;
}
if let Some(description) = description {
sqlx::query("UPDATE tasks SET description = ?, updated_at = strftime('%Y-%m-%dT%H:%M:%SZ', 'now') WHERE id = ?")
.bind(description)
.bind(task_id)
- .execute(pool)
+ .execute(&mut *conn)
.await?;
}
if let Some(state) = &state {
sqlx::query("UPDATE tasks SET state = ?, updated_at = strftime('%Y-%m-%dT%H:%M:%SZ', 'now') WHERE id = ?")
.bind(state.as_str())
.bind(task_id)
- .execute(pool)
+ .execute(&mut *conn)
.await?;
}
@@ -146,7 +152,7 @@ pub async fn edit(
FROM tasks WHERE id = ?",
)
.bind(task_id)
- .fetch_one(pool)
+ .fetch_one(&mut *conn)
.await?;
Ok(task)
}
@@ -158,7 +164,7 @@ pub async fn edit(
/// to those tasks. `task_id` is excluded from adjacent-position lookups
/// (relevant for moves where the task already has a position).
async fn resolve_position(
- pool: &SqlitePool,
+ conn: &mut SqliteConnection,
backlog_id: i64,
task_id: i64,
before_task_id: Option<i64>,
@@ -172,7 +178,7 @@ async fn resolve_position(
ORDER BY bt.position DESC LIMIT 1",
)
.bind(backlog_id)
- .fetch_optional(pool)
+ .fetch_optional(&mut *conn)
.await?;
return Ok(position::midpoint(last_pos.as_deref(), None));
@@ -186,7 +192,7 @@ async fn resolve_position(
)
.bind(backlog_id)
.bind(id)
- .fetch_optional(pool)
+ .fetch_optional(&mut *conn)
.await?
} else {
None
@@ -198,7 +204,7 @@ async fn resolve_position(
)
.bind(backlog_id)
.bind(id)
- .fetch_optional(pool)
+ .fetch_optional(&mut *conn)
.await?
} else {
None
@@ -217,7 +223,7 @@ async fn resolve_position(
.bind(backlog_id)
.bind(task_id)
.bind(low)
- .fetch_optional(pool)
+ .fetch_optional(&mut *conn)
.await?;
(Some(low.clone()), next)
}
@@ -231,7 +237,7 @@ async fn resolve_position(
.bind(backlog_id)
.bind(task_id)
.bind(up)
- .fetch_optional(pool)
+ .fetch_optional(&mut *conn)
.await?;
(prev, Some(up.clone()))
}
@@ -242,34 +248,40 @@ async fn resolve_position(
}
pub async fn move_task(
- pool: &SqlitePool,
+ conn: &mut SqliteConnection,
task_id: i64,
backlog_id: i64,
before_task_id: Option<i64>,
after_task_id: Option<i64>,
) -> Result<(), RangerError> {
- let new_pos =
- resolve_position(pool, backlog_id, task_id, before_task_id, after_task_id).await?;
+ let new_pos = resolve_position(
+ &mut *conn,
+ backlog_id,
+ task_id,
+ before_task_id,
+ after_task_id,
+ )
+ .await?;
sqlx::query("UPDATE backlog_tasks SET position = ? WHERE backlog_id = ? AND task_id = ?")
.bind(&new_pos)
.bind(backlog_id)
.bind(task_id)
- .execute(pool)
+ .execute(&mut *conn)
.await?;
Ok(())
}
pub async fn add_to_backlog(
- pool: &SqlitePool,
+ conn: &mut SqliteConnection,
task_id: i64,
backlog_id: i64,
) -> Result<(), RangerError> {
// Get the task's state to find proper position
let state: String = sqlx::query_scalar("SELECT state FROM tasks WHERE id = ?")
.bind(task_id)
- .fetch_one(pool)
+ .fetch_one(&mut *conn)
.await?;
let last_pos: Option<String> = sqlx::query_scalar(
@@ -280,7 +292,7 @@ pub async fn add_to_backlog(
)
.bind(backlog_id)
.bind(&state)
- .fetch_optional(pool)
+ .fetch_optional(&mut *conn)
.await?;
let new_pos = position::midpoint(last_pos.as_deref(), None);
@@ -289,29 +301,29 @@ pub async fn add_to_backlog(
.bind(backlog_id)
.bind(task_id)
.bind(&new_pos)
- .execute(pool)
+ .execute(&mut *conn)
.await?;
Ok(())
}
pub async fn remove_from_backlog(
- pool: &SqlitePool,
+ conn: &mut SqliteConnection,
task_id: i64,
backlog_id: i64,
) -> Result<(), RangerError> {
sqlx::query("DELETE FROM backlog_tasks WHERE backlog_id = ? AND task_id = ?")
.bind(backlog_id)
.bind(task_id)
- .execute(pool)
+ .execute(&mut *conn)
.await?;
Ok(())
}
-pub async fn delete(pool: &SqlitePool, task_id: i64) -> Result<(), RangerError> {
+pub async fn delete(conn: &mut SqliteConnection, task_id: i64) -> Result<(), RangerError> {
sqlx::query("DELETE FROM tasks WHERE id = ?")
.bind(task_id)
- .execute(pool)
+ .execute(&mut *conn)
.await?;
Ok(())
}
@@ -324,7 +336,7 @@ mod tests {
use crate::ops::backlog;
use tempfile::tempdir;
- async fn test_pool() -> SqlitePool {
+ 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()
@@ -333,9 +345,10 @@ mod tests {
#[tokio::test]
async fn create_task_in_backlog() {
let pool = test_pool().await;
- let bl = backlog::create(&pool, "Test").await.unwrap();
+ let mut conn = pool.acquire().await.unwrap();
+ let bl = backlog::create(&mut conn, "Test").await.unwrap();
let task = create(
- &pool,
+ &mut conn,
CreateTask {
title: "My Task",
backlog_id: bl.id,
@@ -359,7 +372,7 @@ mod tests {
)
.bind(bl.id)
.bind(task.id)
- .fetch_one(&pool)
+ .fetch_one(&mut *conn)
.await
.unwrap();
assert_eq!(count, 1);
@@ -368,9 +381,10 @@ mod tests {
#[tokio::test]
async fn list_tasks_ordered_by_position() {
let pool = test_pool().await;
- let bl = backlog::create(&pool, "Test").await.unwrap();
+ let mut conn = pool.acquire().await.unwrap();
+ let bl = backlog::create(&mut conn, "Test").await.unwrap();
let t1 = create(
- &pool,
+ &mut conn,
CreateTask {
title: "First",
backlog_id: bl.id,
@@ -384,7 +398,7 @@ mod tests {
.await
.unwrap();
let t2 = create(
- &pool,
+ &mut conn,
CreateTask {
title: "Second",
backlog_id: bl.id,
@@ -398,7 +412,7 @@ mod tests {
.await
.unwrap();
let t3 = create(
- &pool,
+ &mut conn,
CreateTask {
title: "Third",
backlog_id: bl.id,
@@ -412,7 +426,7 @@ mod tests {
.await
.unwrap();
- let tasks = list(&pool, bl.id, None).await.unwrap();
+ let tasks = list(&mut conn, bl.id, None).await.unwrap();
assert_eq!(tasks.len(), 3);
assert_eq!(tasks[0].id, t1.id);
assert_eq!(tasks[1].id, t2.id);
@@ -422,9 +436,10 @@ mod tests {
#[tokio::test]
async fn list_tasks_with_state_filter() {
let pool = test_pool().await;
- let bl = backlog::create(&pool, "Test").await.unwrap();
+ let mut conn = pool.acquire().await.unwrap();
+ let bl = backlog::create(&mut conn, "Test").await.unwrap();
create(
- &pool,
+ &mut conn,
CreateTask {
title: "Icebox task",
backlog_id: bl.id,
@@ -438,7 +453,7 @@ mod tests {
.await
.unwrap();
create(
- &pool,
+ &mut conn,
CreateTask {
title: "Queued task",
backlog_id: bl.id,
@@ -452,11 +467,11 @@ mod tests {
.await
.unwrap();
- let icebox = list(&pool, bl.id, Some(State::Icebox)).await.unwrap();
+ let icebox = list(&mut conn, bl.id, Some(State::Icebox)).await.unwrap();
assert_eq!(icebox.len(), 1);
assert_eq!(icebox[0].title, "Icebox task");
- let queued = list(&pool, bl.id, Some(State::Queued)).await.unwrap();
+ let queued = list(&mut conn, bl.id, Some(State::Queued)).await.unwrap();
assert_eq!(queued.len(), 1);
assert_eq!(queued[0].title, "Queued task");
}
@@ -464,9 +479,10 @@ mod tests {
#[tokio::test]
async fn get_task_by_key_prefix() {
let pool = test_pool().await;
- let bl = backlog::create(&pool, "Test").await.unwrap();
+ let mut conn = pool.acquire().await.unwrap();
+ let bl = backlog::create(&mut conn, "Test").await.unwrap();
let task = create(
- &pool,
+ &mut conn,
CreateTask {
title: "Find me",
backlog_id: bl.id,
@@ -480,16 +496,17 @@ mod tests {
.await
.unwrap();
- let found = get_by_key_prefix(&pool, &task.key[..3]).await.unwrap();
+ let found = get_by_key_prefix(&mut conn, &task.key[..3]).await.unwrap();
assert_eq!(found.id, task.id);
}
#[tokio::test]
async fn edit_task_fields() {
let pool = test_pool().await;
- let bl = backlog::create(&pool, "Test").await.unwrap();
+ let mut conn = pool.acquire().await.unwrap();
+ let bl = backlog::create(&mut conn, "Test").await.unwrap();
let task = create(
- &pool,
+ &mut conn,
CreateTask {
title: "Original",
backlog_id: bl.id,
@@ -504,7 +521,7 @@ mod tests {
.unwrap();
let updated = edit(
- &pool,
+ &mut conn,
task.id,
Some("Updated"),
Some("A description"),
@@ -521,10 +538,11 @@ mod tests {
#[tokio::test]
async fn add_task_to_second_backlog() {
let pool = test_pool().await;
- let bl1 = backlog::create(&pool, "First").await.unwrap();
- let bl2 = backlog::create(&pool, "Second").await.unwrap();
+ let mut conn = pool.acquire().await.unwrap();
+ let bl1 = backlog::create(&mut conn, "First").await.unwrap();
+ let bl2 = backlog::create(&mut conn, "Second").await.unwrap();
let task = create(
- &pool,
+ &mut conn,
CreateTask {
title: "Shared",
backlog_id: bl1.id,
@@ -538,10 +556,10 @@ mod tests {
.await
.unwrap();
- add_to_backlog(&pool, task.id, bl2.id).await.unwrap();
+ add_to_backlog(&mut conn, task.id, bl2.id).await.unwrap();
- let tasks1 = list(&pool, bl1.id, None).await.unwrap();
- let tasks2 = list(&pool, bl2.id, None).await.unwrap();
+ let tasks1 = list(&mut conn, bl1.id, None).await.unwrap();
+ let tasks2 = list(&mut conn, bl2.id, None).await.unwrap();
assert_eq!(tasks1.len(), 1);
assert_eq!(tasks2.len(), 1);
assert_eq!(tasks1[0].id, tasks2[0].id);
@@ -550,9 +568,10 @@ mod tests {
#[tokio::test]
async fn remove_task_from_backlog() {
let pool = test_pool().await;
- let bl = backlog::create(&pool, "Test").await.unwrap();
+ let mut conn = pool.acquire().await.unwrap();
+ let bl = backlog::create(&mut conn, "Test").await.unwrap();
let task = create(
- &pool,
+ &mut conn,
CreateTask {
title: "Remove me",
backlog_id: bl.id,
@@ -566,18 +585,21 @@ mod tests {
.await
.unwrap();
- remove_from_backlog(&pool, task.id, bl.id).await.unwrap();
+ remove_from_backlog(&mut conn, task.id, bl.id)
+ .await
+ .unwrap();
- let tasks = list(&pool, bl.id, None).await.unwrap();
+ let tasks = list(&mut conn, bl.id, None).await.unwrap();
assert_eq!(tasks.len(), 0);
}
#[tokio::test]
async fn move_task_before() {
let pool = test_pool().await;
- let bl = backlog::create(&pool, "Test").await.unwrap();
+ let mut conn = pool.acquire().await.unwrap();
+ let bl = backlog::create(&mut conn, "Test").await.unwrap();
let t1 = create(
- &pool,
+ &mut conn,
CreateTask {
title: "First",
backlog_id: bl.id,
@@ -591,7 +613,7 @@ mod tests {
.await
.unwrap();
let t2 = create(
- &pool,
+ &mut conn,
CreateTask {
title: "Second",
backlog_id: bl.id,
@@ -605,7 +627,7 @@ mod tests {
.await
.unwrap();
let t3 = create(
- &pool,
+ &mut conn,
CreateTask {
title: "Third",
backlog_id: bl.id,
@@ -620,11 +642,11 @@ mod tests {
.unwrap();
// Move t3 before t1 — should produce order: t3, t1, t2
- move_task(&pool, t3.id, bl.id, Some(t1.id), None)
+ move_task(&mut conn, t3.id, bl.id, Some(t1.id), None)
.await
.unwrap();
- let tasks = list(&pool, bl.id, None).await.unwrap();
+ let tasks = list(&mut conn, bl.id, None).await.unwrap();
assert_eq!(tasks[0].id, t3.id, "t3 should be first");
assert_eq!(tasks[1].id, t1.id, "t1 should be second");
assert_eq!(tasks[2].id, t2.id, "t2 should be third");
@@ -633,9 +655,10 @@ mod tests {
#[tokio::test]
async fn move_task_after() {
let pool = test_pool().await;
- let bl = backlog::create(&pool, "Test").await.unwrap();
+ let mut conn = pool.acquire().await.unwrap();
+ let bl = backlog::create(&mut conn, "Test").await.unwrap();
let t1 = create(
- &pool,
+ &mut conn,
CreateTask {
title: "First",
backlog_id: bl.id,
@@ -649,7 +672,7 @@ mod tests {
.await
.unwrap();
let t2 = create(
- &pool,
+ &mut conn,
CreateTask {
title: "Second",
backlog_id: bl.id,
@@ -663,7 +686,7 @@ mod tests {
.await
.unwrap();
let t3 = create(
- &pool,
+ &mut conn,
CreateTask {
title: "Third",
backlog_id: bl.id,
@@ -678,11 +701,11 @@ mod tests {
.unwrap();
// Move t1 after t3 — should produce order: t2, t3, t1
- move_task(&pool, t1.id, bl.id, None, Some(t3.id))
+ move_task(&mut conn, t1.id, bl.id, None, Some(t3.id))
.await
.unwrap();
- let tasks = list(&pool, bl.id, None).await.unwrap();
+ let tasks = list(&mut conn, bl.id, None).await.unwrap();
assert_eq!(tasks[0].id, t2.id, "t2 should be first");
assert_eq!(tasks[1].id, t3.id, "t3 should be second");
assert_eq!(tasks[2].id, t1.id, "t1 should be third");
@@ -691,9 +714,10 @@ mod tests {
#[tokio::test]
async fn move_task_after_into_middle() {
let pool = test_pool().await;
- let bl = backlog::create(&pool, "Test").await.unwrap();
+ let mut conn = pool.acquire().await.unwrap();
+ let bl = backlog::create(&mut conn, "Test").await.unwrap();
let t1 = create(
- &pool,
+ &mut conn,
CreateTask {
title: "First",
backlog_id: bl.id,
@@ -707,7 +731,7 @@ mod tests {
.await
.unwrap();
let t2 = create(
- &pool,
+ &mut conn,
CreateTask {
title: "Second",
backlog_id: bl.id,
@@ -721,7 +745,7 @@ mod tests {
.await
.unwrap();
let t3 = create(
- &pool,
+ &mut conn,
CreateTask {
title: "Third",
backlog_id: bl.id,
@@ -736,11 +760,11 @@ mod tests {
.unwrap();
// Move t3 after t1 (but before t2) — should produce order: t1, t3, t2
- move_task(&pool, t3.id, bl.id, None, Some(t1.id))
+ move_task(&mut conn, t3.id, bl.id, None, Some(t1.id))
.await
.unwrap();
- let tasks = list(&pool, bl.id, None).await.unwrap();
+ let tasks = list(&mut conn, bl.id, None).await.unwrap();
assert_eq!(tasks[0].id, t1.id, "t1 should be first");
assert_eq!(tasks[1].id, t3.id, "t3 should be second (after t1)");
assert_eq!(tasks[2].id, t2.id, "t2 should be third");
@@ -749,9 +773,10 @@ mod tests {
#[tokio::test]
async fn move_task_before_from_middle() {
let pool = test_pool().await;
- let bl = backlog::create(&pool, "Test").await.unwrap();
+ let mut conn = pool.acquire().await.unwrap();
+ let bl = backlog::create(&mut conn, "Test").await.unwrap();
let t1 = create(
- &pool,
+ &mut conn,
CreateTask {
title: "First",
backlog_id: bl.id,
@@ -765,7 +790,7 @@ mod tests {
.await
.unwrap();
let t2 = create(
- &pool,
+ &mut conn,
CreateTask {
title: "Second",
backlog_id: bl.id,
@@ -779,7 +804,7 @@ mod tests {
.await
.unwrap();
let t3 = create(
- &pool,
+ &mut conn,
CreateTask {
title: "Third",
backlog_id: bl.id,
@@ -794,11 +819,11 @@ mod tests {
.unwrap();
// Move t1 before t3 (but after t2) — should produce order: t2, t1, t3
- move_task(&pool, t1.id, bl.id, Some(t3.id), None)
+ move_task(&mut conn, t1.id, bl.id, Some(t3.id), None)
.await
.unwrap();
- let tasks = list(&pool, bl.id, None).await.unwrap();
+ let tasks = list(&mut conn, bl.id, None).await.unwrap();
assert_eq!(tasks[0].id, t2.id, "t2 should be first");
assert_eq!(tasks[1].id, t1.id, "t1 should be second (before t3)");
assert_eq!(tasks[2].id, t3.id, "t3 should be third");
@@ -807,9 +832,10 @@ mod tests {
#[tokio::test]
async fn move_task_between() {
let pool = test_pool().await;
- let bl = backlog::create(&pool, "Test").await.unwrap();
+ let mut conn = pool.acquire().await.unwrap();
+ let bl = backlog::create(&mut conn, "Test").await.unwrap();
let t1 = create(
- &pool,
+ &mut conn,
CreateTask {
title: "First",
backlog_id: bl.id,
@@ -823,7 +849,7 @@ mod tests {
.await
.unwrap();
let t2 = create(
- &pool,
+ &mut conn,
CreateTask {
title: "Second",
backlog_id: bl.id,
@@ -837,7 +863,7 @@ mod tests {
.await
.unwrap();
let t3 = create(
- &pool,
+ &mut conn,
CreateTask {
title: "Third",
backlog_id: bl.id,
@@ -852,11 +878,11 @@ mod tests {
.unwrap();
// Move t3 after t1 and before t2 — should produce order: t1, t3, t2
- move_task(&pool, t3.id, bl.id, Some(t2.id), Some(t1.id))
+ move_task(&mut conn, t3.id, bl.id, Some(t2.id), Some(t1.id))
.await
.unwrap();
- let tasks = list(&pool, bl.id, None).await.unwrap();
+ let tasks = list(&mut conn, bl.id, None).await.unwrap();
assert_eq!(tasks[0].id, t1.id, "t1 should be first");
assert_eq!(tasks[1].id, t3.id, "t3 should be second");
assert_eq!(tasks[2].id, t2.id, "t2 should be third");
@@ -865,9 +891,10 @@ mod tests {
#[tokio::test]
async fn delete_task() {
let pool = test_pool().await;
- let bl = backlog::create(&pool, "Test").await.unwrap();
+ let mut conn = pool.acquire().await.unwrap();
+ let bl = backlog::create(&mut conn, "Test").await.unwrap();
let task = create(
- &pool,
+ &mut conn,
CreateTask {
title: "Delete me",
backlog_id: bl.id,
@@ -881,22 +908,23 @@ mod tests {
.await
.unwrap();
- delete(&pool, task.id).await.unwrap();
+ delete(&mut conn, task.id).await.unwrap();
- let result = get_by_key_prefix(&pool, &task.key).await;
+ let result = get_by_key_prefix(&mut conn, &task.key).await;
assert!(result.is_err());
// backlog_tasks should be cleaned up by cascade
- let tasks = list(&pool, bl.id, None).await.unwrap();
+ let tasks = list(&mut conn, bl.id, None).await.unwrap();
assert_eq!(tasks.len(), 0);
}
#[tokio::test]
async fn create_task_before() {
let pool = test_pool().await;
- let bl = backlog::create(&pool, "Test").await.unwrap();
+ let mut conn = pool.acquire().await.unwrap();
+ let bl = backlog::create(&mut conn, "Test").await.unwrap();
let t1 = create(
- &pool,
+ &mut conn,
CreateTask {
title: "First",
backlog_id: bl.id,
@@ -910,7 +938,7 @@ mod tests {
.await
.unwrap();
let t2 = create(
- &pool,
+ &mut conn,
CreateTask {
title: "Second",
backlog_id: bl.id,
@@ -926,7 +954,7 @@ mod tests {
// Create a task before t1 — should produce order: t3, t1, t2
let t3 = create(
- &pool,
+ &mut conn,
CreateTask {
title: "Before first",
backlog_id: bl.id,
@@ -940,7 +968,7 @@ mod tests {
.await
.unwrap();
- let tasks = list(&pool, bl.id, None).await.unwrap();
+ let tasks = list(&mut conn, bl.id, None).await.unwrap();
assert_eq!(tasks[0].id, t3.id, "t3 should be first");
assert_eq!(tasks[1].id, t1.id, "t1 should be second");
assert_eq!(tasks[2].id, t2.id, "t2 should be third");
@@ -949,9 +977,10 @@ mod tests {
#[tokio::test]
async fn create_task_after() {
let pool = test_pool().await;
- let bl = backlog::create(&pool, "Test").await.unwrap();
+ let mut conn = pool.acquire().await.unwrap();
+ let bl = backlog::create(&mut conn, "Test").await.unwrap();
let t1 = create(
- &pool,
+ &mut conn,
CreateTask {
title: "First",
backlog_id: bl.id,
@@ -965,7 +994,7 @@ mod tests {
.await
.unwrap();
let t2 = create(
- &pool,
+ &mut conn,
CreateTask {
title: "Second",
backlog_id: bl.id,
@@ -981,7 +1010,7 @@ mod tests {
// Create a task after t1 — should produce order: t1, t3, t2
let t3 = create(
- &pool,
+ &mut conn,
CreateTask {
title: "After first",
backlog_id: bl.id,
@@ -995,7 +1024,7 @@ mod tests {
.await
.unwrap();
- let tasks = list(&pool, bl.id, None).await.unwrap();
+ let tasks = list(&mut conn, bl.id, None).await.unwrap();
assert_eq!(tasks[0].id, t1.id, "t1 should be first");
assert_eq!(tasks[1].id, t3.id, "t3 should be second");
assert_eq!(tasks[2].id, t2.id, "t2 should be third");
@@ -1004,9 +1033,10 @@ mod tests {
#[tokio::test]
async fn create_task_between() {
let pool = test_pool().await;
- let bl = backlog::create(&pool, "Test").await.unwrap();
+ let mut conn = pool.acquire().await.unwrap();
+ let bl = backlog::create(&mut conn, "Test").await.unwrap();
let t1 = create(
- &pool,
+ &mut conn,
CreateTask {
title: "First",
backlog_id: bl.id,
@@ -1020,7 +1050,7 @@ mod tests {
.await
.unwrap();
let t2 = create(
- &pool,
+ &mut conn,
CreateTask {
title: "Second",
backlog_id: bl.id,
@@ -1036,7 +1066,7 @@ mod tests {
// Create a task after t1 and before t2 — should produce order: t1, t3, t2
let t3 = create(
- &pool,
+ &mut conn,
CreateTask {
title: "Between",
backlog_id: bl.id,
@@ -1050,7 +1080,7 @@ mod tests {
.await
.unwrap();
- let tasks = list(&pool, bl.id, None).await.unwrap();
+ let tasks = list(&mut conn, bl.id, None).await.unwrap();
assert_eq!(tasks[0].id, t1.id, "t1 should be first");
assert_eq!(tasks[1].id, t3.id, "t3 should be second");
assert_eq!(tasks[2].id, t2.id, "t2 should be third");