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