mod entities;
mod helpers;
use entities::task::*;
use es_entity::*;
use sqlx::PgPool;
#[derive(EsRepo, Debug)]
#[es_repo(
entity = "Task",
columns(
workspace_id(ty = "Option<WorkspaceId>", list_for),
status(ty = "String", list_for(by(created_at)))
)
)]
pub struct Tasks {
pool: PgPool,
}
impl Tasks {
pub fn new(pool: PgPool) -> Self {
Self { pool }
}
}
#[tokio::test]
async fn list_for_filters_none_skips_filter() -> anyhow::Result<()> {
let pool = helpers::init_pool().await?;
let tasks = Tasks::new(pool);
let ws_id = WorkspaceId::new();
let unique_status = format!("active_{}", TaskId::new());
let task_with_ws = tasks
.create(
NewTask::builder()
.id(TaskId::new())
.workspace_id(ws_id)
.status(&unique_status)
.build()
.unwrap(),
)
.await?;
let task_null_ws = tasks
.create(
NewTask::builder()
.id(TaskId::new())
.status(&unique_status)
.build()
.unwrap(),
)
.await?;
let result = tasks
.list_for_filters(
TaskFilters {
workspace_id: None,
status: Some(unique_status),
},
Sort {
by: TaskSortBy::Id,
direction: ListDirection::Ascending,
},
PaginatedQueryArgs {
first: 100,
after: None,
},
)
.await?;
assert_eq!(
result.entities.len(),
2,
"Expected both tasks (None means skip filter), got {}",
result.entities.len()
);
let ids: Vec<_> = result.entities.iter().map(|t| t.id).collect();
assert!(ids.contains(&task_with_ws.id));
assert!(ids.contains(&task_null_ws.id));
Ok(())
}
#[tokio::test]
async fn list_for_filters_some_value_filters_correctly() -> anyhow::Result<()> {
let pool = helpers::init_pool().await?;
let tasks = Tasks::new(pool);
let ws_id = WorkspaceId::new();
let unique_status = format!("pending_{}", TaskId::new());
let task_with_ws = tasks
.create(
NewTask::builder()
.id(TaskId::new())
.workspace_id(ws_id)
.status(&unique_status)
.build()
.unwrap(),
)
.await?;
let task_null_ws = tasks
.create(
NewTask::builder()
.id(TaskId::new())
.status(&unique_status)
.build()
.unwrap(),
)
.await?;
let result = tasks
.list_for_filters(
TaskFilters {
workspace_id: Some(Some(ws_id)),
status: Some(unique_status),
},
Sort {
by: TaskSortBy::Id,
direction: ListDirection::Ascending,
},
PaginatedQueryArgs {
first: 100,
after: None,
},
)
.await?;
assert_eq!(result.entities.len(), 1);
assert_eq!(result.entities[0].id, task_with_ws.id);
assert!(result.entities.iter().all(|t| t.id != task_null_ws.id));
Ok(())
}
#[tokio::test]
async fn list_for_column_none_matches_only_null_rows() -> anyhow::Result<()> {
let pool = helpers::init_pool().await?;
let tasks = Tasks::new(pool);
let ws_id = WorkspaceId::new();
let task_with_ws = tasks
.create(
NewTask::builder()
.id(TaskId::new())
.workspace_id(ws_id)
.status("any")
.build()
.unwrap(),
)
.await?;
let task_null_ws = tasks
.create(
NewTask::builder()
.id(TaskId::new())
.status("any")
.build()
.unwrap(),
)
.await?;
let result = tasks
.list_for_workspace_id_by_id(
None::<WorkspaceId>,
PaginatedQueryArgs {
first: 100,
after: None,
},
ListDirection::Ascending,
)
.await?;
assert!(
result.entities.iter().any(|t| t.id == task_null_ws.id),
"Task with NULL workspace_id should match a None filter"
);
assert!(
result.entities.iter().all(|t| t.id != task_with_ws.id),
"Task with non-NULL workspace_id should NOT match a None filter"
);
Ok(())
}
#[tokio::test]
async fn list_for_column_some_excludes_null_rows() -> anyhow::Result<()> {
let pool = helpers::init_pool().await?;
let tasks = Tasks::new(pool);
let ws_id = WorkspaceId::new();
let task_with_ws = tasks
.create(
NewTask::builder()
.id(TaskId::new())
.workspace_id(ws_id)
.status("any")
.build()
.unwrap(),
)
.await?;
let task_null_ws = tasks
.create(
NewTask::builder()
.id(TaskId::new())
.status("any")
.build()
.unwrap(),
)
.await?;
let result = tasks
.list_for_workspace_id_by_id(
Some(ws_id),
PaginatedQueryArgs {
first: 100,
after: None,
},
ListDirection::Ascending,
)
.await?;
assert_eq!(result.entities.len(), 1);
assert_eq!(result.entities[0].id, task_with_ws.id);
assert!(result.entities.iter().all(|t| t.id != task_null_ws.id));
Ok(())
}
#[tokio::test]
async fn list_for_filters_some_none_matches_only_null_rows() -> anyhow::Result<()> {
let pool = helpers::init_pool().await?;
let tasks = Tasks::new(pool);
let ws_id = WorkspaceId::new();
let unique_status = format!("null_filter_{}", TaskId::new());
let _task_with_ws = tasks
.create(
NewTask::builder()
.id(TaskId::new())
.workspace_id(ws_id)
.status(&unique_status)
.build()
.unwrap(),
)
.await?;
let task_null_ws = tasks
.create(
NewTask::builder()
.id(TaskId::new())
.status(&unique_status)
.build()
.unwrap(),
)
.await?;
let result = tasks
.list_for_filters(
TaskFilters {
workspace_id: Some(None),
status: Some(unique_status),
},
Sort {
by: TaskSortBy::Id,
direction: ListDirection::Ascending,
},
PaginatedQueryArgs {
first: 100,
after: None,
},
)
.await?;
assert_eq!(
result.entities.len(),
1,
"Expected only the NULL-workspace task, got {}",
result.entities.len()
);
assert_eq!(result.entities[0].id, task_null_ws.id);
assert!(
result.entities.iter().all(|t| t.id != _task_with_ws.id),
"Task with non-NULL workspace_id should NOT match a Some(None) filter"
);
Ok(())
}