1use crate::models::{TaskFilters, TaskStatus, TaskType};
4use chrono::NaiveDate;
5use uuid::Uuid;
6
7#[derive(Debug, Clone)]
9pub struct TaskQueryBuilder {
10 filters: TaskFilters,
11}
12
13impl TaskQueryBuilder {
14 #[must_use]
16 pub fn new() -> Self {
17 Self {
18 filters: TaskFilters::default(),
19 }
20 }
21
22 #[must_use]
24 pub const fn status(mut self, status: TaskStatus) -> Self {
25 self.filters.status = Some(status);
26 self
27 }
28
29 #[must_use]
31 pub const fn task_type(mut self, task_type: TaskType) -> Self {
32 self.filters.task_type = Some(task_type);
33 self
34 }
35
36 #[must_use]
38 pub const fn project_uuid(mut self, project_uuid: Uuid) -> Self {
39 self.filters.project_uuid = Some(project_uuid);
40 self
41 }
42
43 #[must_use]
45 pub const fn area_uuid(mut self, area_uuid: Uuid) -> Self {
46 self.filters.area_uuid = Some(area_uuid);
47 self
48 }
49
50 #[must_use]
52 pub fn tags(mut self, tags: Vec<String>) -> Self {
53 self.filters.tags = Some(tags);
54 self
55 }
56
57 #[must_use]
59 pub const fn start_date_range(
60 mut self,
61 from: Option<NaiveDate>,
62 to: Option<NaiveDate>,
63 ) -> Self {
64 self.filters.start_date_from = from;
65 self.filters.start_date_to = to;
66 self
67 }
68
69 #[must_use]
71 pub const fn deadline_range(mut self, from: Option<NaiveDate>, to: Option<NaiveDate>) -> Self {
72 self.filters.deadline_from = from;
73 self.filters.deadline_to = to;
74 self
75 }
76
77 #[must_use]
79 pub fn search(mut self, query: &str) -> Self {
80 self.filters.search_query = Some(query.to_string());
81 self
82 }
83
84 #[must_use]
86 pub const fn limit(mut self, limit: usize) -> Self {
87 self.filters.limit = Some(limit);
88 self
89 }
90
91 #[must_use]
93 pub const fn offset(mut self, offset: usize) -> Self {
94 self.filters.offset = Some(offset);
95 self
96 }
97
98 #[must_use]
100 pub fn build(self) -> TaskFilters {
101 self.filters
102 }
103}
104
105impl Default for TaskQueryBuilder {
106 fn default() -> Self {
107 Self::new()
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114 use chrono::NaiveDate;
115 use uuid::Uuid;
116
117 #[test]
118 fn test_task_query_builder_new() {
119 let builder = TaskQueryBuilder::new();
120 let filters = builder.build();
121
122 assert!(filters.status.is_none());
123 assert!(filters.task_type.is_none());
124 assert!(filters.project_uuid.is_none());
125 assert!(filters.area_uuid.is_none());
126 assert!(filters.tags.is_none());
127 assert!(filters.start_date_from.is_none());
128 assert!(filters.start_date_to.is_none());
129 assert!(filters.deadline_from.is_none());
130 assert!(filters.deadline_to.is_none());
131 assert!(filters.search_query.is_none());
132 assert!(filters.limit.is_none());
133 assert!(filters.offset.is_none());
134 }
135
136 #[test]
137 fn test_task_query_builder_default() {
138 let builder = TaskQueryBuilder::default();
139 let filters = builder.build();
140
141 assert!(filters.status.is_none());
142 assert!(filters.task_type.is_none());
143 }
144
145 #[test]
146 fn test_task_query_builder_status() {
147 let builder = TaskQueryBuilder::new().status(TaskStatus::Completed);
148 let filters = builder.build();
149
150 assert_eq!(filters.status, Some(TaskStatus::Completed));
151 }
152
153 #[test]
154 fn test_task_query_builder_task_type() {
155 let builder = TaskQueryBuilder::new().task_type(TaskType::Project);
156 let filters = builder.build();
157
158 assert_eq!(filters.task_type, Some(TaskType::Project));
159 }
160
161 #[test]
162 fn test_task_query_builder_project_uuid() {
163 let uuid = Uuid::new_v4();
164 let builder = TaskQueryBuilder::new().project_uuid(uuid);
165 let filters = builder.build();
166
167 assert_eq!(filters.project_uuid, Some(uuid));
168 }
169
170 #[test]
171 fn test_task_query_builder_area_uuid() {
172 let uuid = Uuid::new_v4();
173 let builder = TaskQueryBuilder::new().area_uuid(uuid);
174 let filters = builder.build();
175
176 assert_eq!(filters.area_uuid, Some(uuid));
177 }
178
179 #[test]
180 fn test_task_query_builder_tags() {
181 let tags = vec!["urgent".to_string(), "important".to_string()];
182 let builder = TaskQueryBuilder::new().tags(tags.clone());
183 let filters = builder.build();
184
185 assert_eq!(filters.tags, Some(tags));
186 }
187
188 #[test]
189 fn test_task_query_builder_start_date_range() {
190 let from = NaiveDate::from_ymd_opt(2024, 1, 1).unwrap();
191 let to = NaiveDate::from_ymd_opt(2024, 12, 31).unwrap();
192 let builder = TaskQueryBuilder::new().start_date_range(Some(from), Some(to));
193 let filters = builder.build();
194
195 assert_eq!(filters.start_date_from, Some(from));
196 assert_eq!(filters.start_date_to, Some(to));
197 }
198
199 #[test]
200 fn test_task_query_builder_deadline_range() {
201 let from = NaiveDate::from_ymd_opt(2024, 1, 1).unwrap();
202 let to = NaiveDate::from_ymd_opt(2024, 12, 31).unwrap();
203 let builder = TaskQueryBuilder::new().deadline_range(Some(from), Some(to));
204 let filters = builder.build();
205
206 assert_eq!(filters.deadline_from, Some(from));
207 assert_eq!(filters.deadline_to, Some(to));
208 }
209
210 #[test]
211 fn test_task_query_builder_search() {
212 let query = "test search";
213 let builder = TaskQueryBuilder::new().search(query);
214 let filters = builder.build();
215
216 assert_eq!(filters.search_query, Some(query.to_string()));
217 }
218
219 #[test]
220 fn test_task_query_builder_limit() {
221 let builder = TaskQueryBuilder::new().limit(50);
222 let filters = builder.build();
223
224 assert_eq!(filters.limit, Some(50));
225 }
226
227 #[test]
228 fn test_task_query_builder_offset() {
229 let builder = TaskQueryBuilder::new().offset(10);
230 let filters = builder.build();
231
232 assert_eq!(filters.offset, Some(10));
233 }
234
235 #[test]
236 fn test_task_query_builder_chaining() {
237 let uuid = Uuid::new_v4();
238 let tags = vec!["urgent".to_string()];
239 let from = NaiveDate::from_ymd_opt(2024, 1, 1).unwrap();
240 let to = NaiveDate::from_ymd_opt(2024, 12, 31).unwrap();
241
242 let builder = TaskQueryBuilder::new()
243 .status(TaskStatus::Incomplete)
244 .task_type(TaskType::Todo)
245 .project_uuid(uuid)
246 .tags(tags.clone())
247 .start_date_range(Some(from), Some(to))
248 .search("test")
249 .limit(25)
250 .offset(5);
251
252 let filters = builder.build();
253
254 assert_eq!(filters.status, Some(TaskStatus::Incomplete));
255 assert_eq!(filters.task_type, Some(TaskType::Todo));
256 assert_eq!(filters.project_uuid, Some(uuid));
257 assert_eq!(filters.tags, Some(tags));
258 assert_eq!(filters.start_date_from, Some(from));
259 assert_eq!(filters.start_date_to, Some(to));
260 assert_eq!(filters.search_query, Some("test".to_string()));
261 assert_eq!(filters.limit, Some(25));
262 assert_eq!(filters.offset, Some(5));
263 }
264}