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