1use crate::filters::FilterValue;
47use crate::{
48 Aggregate, Database, FilterOperator, Operator, PaginatedResult, Pagination, Result, Sort, Value,
49};
50use std::collections::HashMap;
51
52pub struct QueryResult<T> {
65 pub data: Vec<T>,
66 pub total: Option<u64>,
67}
68
69impl<T> QueryResult<T> {
70 pub fn new(data: Vec<T>) -> Self {
71 Self { data, total: None }
72 }
73
74 pub fn with_total(data: Vec<T>, total: u64) -> Self {
75 Self {
76 data,
77 total: Some(total),
78 }
79 }
80}
81
82pub struct QueryBuilder {
120 table: String,
121 select_columns: Vec<String>,
122 joins: Vec<JoinClause>,
123 where_clauses: Vec<FilterOperator>,
124 group_by: Vec<String>,
125 having: Vec<FilterOperator>,
126 order_by: Vec<Sort>,
127 limit: Option<u32>,
128 offset: Option<u32>,
129 distinct: bool,
130 aggregate: Option<AggregateClause>,
131}
132
133struct JoinClause {
135 join_type: crate::JoinType,
136 table: String,
137 alias: Option<String>,
138 condition: String,
139}
140
141struct AggregateClause {
143 function: Aggregate,
144 column: String,
145 alias: Option<String>,
146}
147
148impl QueryBuilder {
149 pub fn new(table: impl Into<String>) -> Self {
151 Self {
152 table: table.into(),
153 select_columns: vec!["*".to_string()],
154 joins: Vec::new(),
155 where_clauses: Vec::new(),
156 group_by: Vec::new(),
157 having: Vec::new(),
158 order_by: Vec::new(),
159 limit: None,
160 offset: None,
161 distinct: false,
162 aggregate: None,
163 }
164 }
165
166 pub fn select(mut self, columns: Vec<impl Into<String>>) -> Self {
168 self.select_columns = columns.into_iter().map(|c| c.into()).collect();
169 self
170 }
171
172 pub fn join(
174 mut self,
175 join_type: crate::JoinType,
176 table: impl Into<String>,
177 condition: impl Into<String>,
178 ) -> Self {
179 self.joins.push(JoinClause {
180 join_type,
181 table: table.into(),
182 alias: None,
183 condition: condition.into(),
184 });
185 self
186 }
187
188 pub fn join_as(
190 mut self,
191 join_type: crate::JoinType,
192 table: impl Into<String>,
193 alias: impl Into<String>,
194 condition: impl Into<String>,
195 ) -> Self {
196 self.joins.push(JoinClause {
197 join_type,
198 table: table.into(),
199 alias: Some(alias.into()),
200 condition: condition.into(),
201 });
202 self
203 }
204
205 pub fn r#where(mut self, filter: FilterOperator) -> Self {
207 self.where_clauses.push(filter);
208 self
209 }
210
211 pub fn group_by(mut self, columns: Vec<impl Into<String>>) -> Self {
213 self.group_by = columns.into_iter().map(|c| c.into()).collect();
214 self
215 }
216
217 pub fn having(mut self, filter: FilterOperator) -> Self {
219 self.having.push(filter);
220 self
221 }
222
223 pub fn order_by(mut self, sort: Sort) -> Self {
225 self.order_by.push(sort);
226 self
227 }
228
229 pub fn order_by_multiple(mut self, sorts: Vec<Sort>) -> Self {
231 self.order_by.extend(sorts);
232 self
233 }
234
235 pub fn limit(mut self, limit: u32) -> Self {
237 self.limit = Some(limit);
238 self
239 }
240
241 pub fn offset(mut self, offset: u32) -> Self {
243 self.offset = Some(offset);
244 self
245 }
246
247 pub fn distinct(mut self, distinct: bool) -> Self {
249 self.distinct = distinct;
250 self
251 }
252
253 pub fn aggregate(
255 mut self,
256 function: Aggregate,
257 column: impl Into<String>,
258 alias: Option<impl Into<String>>,
259 ) -> Self {
260 self.aggregate = Some(AggregateClause {
261 function,
262 column: column.into(),
263 alias: alias.map(|a| a.into()),
264 });
265 self
266 }
267
268 pub fn select_all(mut self) -> Self {
270 self.select_columns = vec!["*".to_string()];
271 self
272 }
273
274 pub fn select_columns(mut self, columns: &[&str]) -> Self {
276 self.select_columns = columns.iter().map(|&c| c.to_string()).collect();
277 self
278 }
279
280 pub fn select_column(mut self, column: &str) -> Self {
282 self.select_columns = vec![column.to_string()];
283 self
284 }
285
286 pub fn select_count(mut self) -> Self {
288 self.select_columns = vec!["COUNT(*)".to_string()];
289 self
290 }
291
292 pub fn select_aggregate(mut self, aggregate: &str) -> Self {
294 self.select_columns = vec![aggregate.to_string()];
295 self
296 }
297
298 pub fn select_distinct(mut self, column: &str) -> Self {
300 self.select_columns = vec![column.to_string()];
301 self.distinct = true;
302 self
303 }
304
305 pub fn where_condition(
307 mut self,
308 condition: &str,
309 _params: impl Into<Vec<crate::compat::LibsqlValue>>,
310 ) -> Self {
311 self.where_clauses
313 .push(FilterOperator::Custom(condition.to_string()));
314 self
315 }
316
317 pub fn search(mut self, field: &str, query: &str) -> Self {
319 let condition = format!("{field} LIKE '%{query}%'");
320 self.where_clauses.push(FilterOperator::Custom(condition));
321 self
322 }
323
324 pub fn with_filter(mut self, filter: crate::Filter) -> Self {
326 self.where_clauses.push(FilterOperator::Single(filter));
328 self
329 }
330
331 pub fn with_filters(mut self, filters: Vec<crate::Filter>) -> Self {
333 for filter in filters {
334 self = self.with_filter(filter);
335 }
336 self
337 }
338
339 pub fn with_sorts(mut self, sorts: Vec<crate::Sort>) -> Self {
341 for sort in sorts {
342 self = self.order_by(sort);
343 }
344 self
345 }
346
347 pub fn having_condition(
349 mut self,
350 condition: &str,
351 _params: impl Into<Vec<crate::compat::LibsqlValue>>,
352 ) -> Self {
353 self.having
355 .push(FilterOperator::Custom(condition.to_string()));
356 self
357 }
358
359 pub fn where_in(mut self, field: &str, subquery: QueryBuilder) -> Self {
361 let (subquery_sql, _) = subquery.build().unwrap_or_default();
362 let condition = format!("{field} IN ({subquery_sql})");
363 self.where_clauses.push(FilterOperator::Custom(condition));
364 self
365 }
366
367 pub async fn execute_count(&self, db: &Database) -> Result<u64> {
369 let (sql, params) = self.build_count()?;
370 let mut rows = db.query(&sql, params).await?;
371
372 if let Some(row) = rows.next().await? {
373 row.get_value(0)
374 .ok()
375 .and_then(|v| match v {
376 crate::compat::LibsqlValue::Integer(i) => Some(i as u64),
377 _ => None,
378 })
379 .ok_or_else(|| crate::Error::Query("Failed to get count".to_string()))
380 } else {
381 Err(crate::Error::Query("No count result".to_string()))
382 }
383 }
384
385 pub async fn execute_aggregate(&self, db: &Database) -> Result<Vec<crate::compat::LibsqlRow>> {
387 let (sql, params) = self.build()?;
388 let mut rows = db.query(&sql, params).await?;
389 let mut results = Vec::new();
390 while let Some(row) = rows.next().await? {
391 results.push(row);
392 }
393 Ok(results)
394 }
395
396 pub fn build(&self) -> Result<(String, Vec<crate::compat::LibsqlValue>)> {
398 let mut sql = String::new();
399 let mut params = Vec::new();
400
401 sql.push_str("SELECT ");
403 if self.distinct {
404 sql.push_str("DISTINCT ");
405 }
406
407 if let Some(agg) = &self.aggregate {
408 sql.push_str(&format!("{}({})", agg.function, agg.column));
409 if let Some(alias) = &agg.alias {
410 sql.push_str(&format!(" AS {alias}"));
411 }
412 } else {
413 sql.push_str(&self.select_columns.join(", "));
414 }
415
416 sql.push_str(&format!(" FROM {}", self.table));
418
419 for join in &self.joins {
421 sql.push_str(&format!(" {} {}", join.join_type, join.table));
422 if let Some(alias) = &join.alias {
423 sql.push_str(&format!(" AS {alias}"));
424 }
425 sql.push_str(&format!(" ON {}", join.condition));
426 }
427
428 if !self.where_clauses.is_empty() {
430 sql.push_str(" WHERE ");
431 let (where_sql, where_params) = self.build_where_clause(&self.where_clauses)?;
432 sql.push_str(&where_sql);
433 params.extend(where_params);
434 }
435
436 if !self.group_by.is_empty() {
438 sql.push_str(&format!(" GROUP BY {}", self.group_by.join(", ")));
439 }
440
441 if !self.having.is_empty() {
443 sql.push_str(" HAVING ");
444 let (having_sql, having_params) = self.build_where_clause(&self.having)?;
445 sql.push_str(&having_sql);
446 params.extend(having_params);
447 }
448
449 if !self.order_by.is_empty() {
451 sql.push_str(" ORDER BY ");
452 let order_clauses: Vec<String> = self
453 .order_by
454 .iter()
455 .map(|sort| format!("{} {}", sort.column, sort.order))
456 .collect();
457 sql.push_str(&order_clauses.join(", "));
458 }
459
460 if let Some(limit) = self.limit {
462 sql.push_str(&format!(" LIMIT {limit}"));
463 }
464 if let Some(offset) = self.offset {
465 sql.push_str(&format!(" OFFSET {offset}"));
466 }
467
468 Ok((sql, params))
469 }
470
471 pub fn build_count(&self) -> Result<(String, Vec<crate::compat::LibsqlValue>)> {
473 let mut sql = String::new();
474 let mut params = Vec::new();
475
476 sql.push_str("SELECT COUNT(*)");
477
478 sql.push_str(&format!(" FROM {}", self.table));
480
481 for join in &self.joins {
483 sql.push_str(&format!(" {} {}", join.join_type, join.table));
484 if let Some(alias) = &join.alias {
485 sql.push_str(&format!(" AS {alias}"));
486 }
487 sql.push_str(&format!(" ON {}", join.condition));
488 }
489
490 if !self.where_clauses.is_empty() {
492 sql.push_str(" WHERE ");
493 let (where_sql, where_params) = self.build_where_clause(&self.where_clauses)?;
494 sql.push_str(&where_sql);
495 params.extend(where_params);
496 }
497
498 if !self.group_by.is_empty() {
500 sql.push_str(&format!(" GROUP BY {}", self.group_by.join(", ")));
501 }
502
503 if !self.having.is_empty() {
505 sql.push_str(" HAVING ");
506 let (having_sql, having_params) = self.build_where_clause(&self.having)?;
507 sql.push_str(&having_sql);
508 params.extend(having_params);
509 }
510
511 Ok((sql, params))
512 }
513
514 fn build_where_clause(
516 &self,
517 filters: &[FilterOperator],
518 ) -> Result<(String, Vec<crate::compat::LibsqlValue>)> {
519 let mut sql = String::new();
520 let mut params = Vec::new();
521
522 for (i, filter) in filters.iter().enumerate() {
523 if i > 0 {
524 sql.push_str(" AND ");
525 }
526 let (filter_sql, filter_params) = self.build_filter_operator(filter)?;
527 sql.push_str(&filter_sql);
528 params.extend(filter_params);
529 }
530
531 Ok((sql, params))
532 }
533
534 fn build_filter_operator(
536 &self,
537 filter: &FilterOperator,
538 ) -> Result<(String, Vec<crate::compat::LibsqlValue>)> {
539 match filter {
540 FilterOperator::Single(filter) => self.build_filter(filter),
541 FilterOperator::And(filters) => {
542 let mut sql = String::new();
543 let mut params = Vec::new();
544 sql.push('(');
545 for (i, filter) in filters.iter().enumerate() {
546 if i > 0 {
547 sql.push_str(" AND ");
548 }
549 let (filter_sql, filter_params) = self.build_filter_operator(filter)?;
550 sql.push_str(&filter_sql);
551 params.extend(filter_params);
552 }
553 sql.push(')');
554 Ok((sql, params))
555 }
556 FilterOperator::Or(filters) => {
557 let mut sql = String::new();
558 let mut params = Vec::new();
559 sql.push('(');
560 for (i, filter) in filters.iter().enumerate() {
561 if i > 0 {
562 sql.push_str(" OR ");
563 }
564 let (filter_sql, filter_params) = self.build_filter_operator(filter)?;
565 sql.push_str(&filter_sql);
566 params.extend(filter_params);
567 }
568 sql.push(')');
569 Ok((sql, params))
570 }
571 FilterOperator::Not(filter) => {
572 let (filter_sql, filter_params) = self.build_filter_operator(filter)?;
573 Ok((format!("NOT ({filter_sql})"), filter_params))
574 }
575 FilterOperator::Custom(condition) => Ok((condition.clone(), vec![])),
576 }
577 }
578
579 fn build_filter(
581 &self,
582 filter: &crate::Filter,
583 ) -> Result<(String, Vec<crate::compat::LibsqlValue>)> {
584 let mut sql = String::new();
585 let mut params = Vec::new();
586
587 match &filter.operator {
588 Operator::IsNull => {
589 sql.push_str(&format!("{} IS NULL", filter.column));
590 }
591 Operator::IsNotNull => {
592 sql.push_str(&format!("{} IS NOT NULL", filter.column));
593 }
594 _ => {
595 sql.push_str(&format!("{} {} ", filter.column, filter.operator));
596 match &filter.value {
597 FilterValue::Single(value) => {
598 sql.push('?');
599 params.push(self.value_to_libsql_value(value));
600 }
601 FilterValue::Multiple(values) => {
602 sql.push('(');
603 for (i, value) in values.iter().enumerate() {
604 if i > 0 {
605 sql.push_str(", ");
606 }
607 sql.push('?');
608 params.push(self.value_to_libsql_value(value));
609 }
610 sql.push(')');
611 }
612 FilterValue::Range(min, max) => {
613 sql.push_str("? AND ?");
614 params.push(self.value_to_libsql_value(min));
615 params.push(self.value_to_libsql_value(max));
616 }
617 }
618 }
619 }
620
621 Ok((sql, params))
622 }
623
624 fn value_to_libsql_value(&self, value: &Value) -> crate::compat::LibsqlValue {
626 match value {
627 Value::Null => crate::compat::LibsqlValue::Null,
628 Value::Integer(i) => crate::compat::LibsqlValue::Integer(*i),
629 Value::Real(f) => crate::compat::LibsqlValue::Real(*f),
630 Value::Text(s) => crate::compat::LibsqlValue::Text(s.clone()),
631 Value::Blob(b) => crate::compat::LibsqlValue::Blob(b.clone()),
632 Value::Boolean(b) => crate::compat::LibsqlValue::Integer(if *b { 1 } else { 0 }),
633 }
634 }
635
636 pub async fn execute<T>(&self, db: &Database) -> Result<Vec<T>>
638 where
639 T: serde::de::DeserializeOwned,
640 {
641 let (sql, params) = self.build()?;
642 let mut rows = db.query(&sql, params).await?;
643
644 let mut results = Vec::new();
645 while let Some(row) = rows.next().await? {
646 let mut map = HashMap::new();
647 for i in 0..row.column_count() {
648 if let Some(column_name) = row.column_name(i) {
649 let value = row.get_value(i).unwrap_or(crate::compat::LibsqlValue::Null);
650 map.insert(
651 column_name.to_string(),
652 self.libsql_value_to_json_value(&value),
653 );
654 }
655 }
656 let json_value = serde_json::to_value(map)?;
657 let result: T = serde_json::from_value(json_value)?;
658 results.push(result);
659 }
660
661 Ok(results)
662 }
663
664 pub async fn execute_paginated<T>(
666 &self,
667 db: &Database,
668 pagination: &Pagination,
669 ) -> Result<PaginatedResult<T>>
670 where
671 T: serde::de::DeserializeOwned,
672 {
673 let count_builder = QueryBuilder::new(&self.table).select(vec!["COUNT(*) as count"]);
675
676 let (count_sql, count_params) = count_builder.build_count()?;
677 let mut count_rows = db.query(&count_sql, count_params).await?;
678 let total: u64 = if let Some(row) = count_rows.next().await? {
679 row.get_value(0)
680 .ok()
681 .and_then(|v| match v {
682 crate::compat::LibsqlValue::Integer(i) => Some(i as u64),
683 _ => None,
684 })
685 .unwrap_or(0)
686 } else {
687 0
688 };
689
690 let data_builder = self
692 .clone()
693 .limit(pagination.limit())
694 .offset(pagination.offset());
695
696 let data = data_builder.execute::<T>(db).await?;
697
698 Ok(PaginatedResult::with_total(data, pagination.clone(), total))
699 }
700
701 fn libsql_value_to_json_value(&self, value: &crate::compat::LibsqlValue) -> serde_json::Value {
703 match value {
704 crate::compat::LibsqlValue::Null => serde_json::Value::Null,
705 crate::compat::LibsqlValue::Integer(i) => {
706 serde_json::Value::Number(serde_json::Number::from(*i))
707 }
708 crate::compat::LibsqlValue::Real(f) => {
709 if let Some(n) = serde_json::Number::from_f64(*f) {
710 serde_json::Value::Number(n)
711 } else {
712 serde_json::Value::Null
713 }
714 }
715 crate::compat::LibsqlValue::Text(s) => serde_json::Value::String(s.clone()),
716 crate::compat::LibsqlValue::Blob(b) => serde_json::Value::Array(
717 b.iter()
718 .map(|&byte| serde_json::Value::Number(serde_json::Number::from(byte)))
719 .collect(),
720 ),
721 }
722 }
723}
724
725impl Clone for QueryBuilder {
726 fn clone(&self) -> Self {
727 Self {
728 table: self.table.clone(),
729 select_columns: self.select_columns.clone(),
730 joins: self.joins.clone(),
731 where_clauses: self.where_clauses.clone(),
732 group_by: self.group_by.clone(),
733 having: self.having.clone(),
734 order_by: self.order_by.clone(),
735 limit: self.limit,
736 offset: self.offset,
737 distinct: self.distinct,
738 aggregate: self.aggregate.clone(),
739 }
740 }
741}
742
743impl Clone for JoinClause {
744 fn clone(&self) -> Self {
745 Self {
746 join_type: self.join_type,
747 table: self.table.clone(),
748 alias: self.alias.clone(),
749 condition: self.condition.clone(),
750 }
751 }
752}
753
754impl Clone for AggregateClause {
755 fn clone(&self) -> Self {
756 Self {
757 function: self.function,
758 column: self.column.clone(),
759 alias: self.alias.clone(),
760 }
761 }
762}