sqlint/ast/function/search.rs
1use crate::prelude::*;
2use std::borrow::Cow;
3
4#[derive(Debug, Clone, PartialEq)]
5/// Holds the expressions on which to perform a full-text search
6pub struct TextSearch<'a> {
7 pub(crate) exprs: Vec<Expression<'a>>,
8}
9
10/// Performs a full-text search. Use it in combination with the `.matches()` comparable.
11///
12/// ```rust
13/// # use sqlint::{ast::*, visitor::{Visitor, Postgres}};
14/// # fn main() -> Result<(), sqlint::error::Error> {
15/// let search: Expression = text_search(&[Column::from("name"), Column::from("ingredients")]).into();
16/// let query = Select::from_table("recipes").so_that(search.matches("chicken"));
17/// let (sql, params) = Postgres::build(query)?;
18///
19/// assert_eq!(
20/// "SELECT \"recipes\".* FROM \"recipes\" \
21/// WHERE to_tsvector(concat_ws(' ', \"name\",\"ingredients\")) @@ to_tsquery($1)", sql
22/// );
23///
24/// assert_eq!(params, vec![Value::from("chicken")]);
25/// # Ok(())
26/// # }
27/// ```
28#[cfg(any(feature = "postgresql", feature = "mysql"))]
29pub fn text_search<'a, T: Clone>(exprs: &[T]) -> super::Function<'a>
30where
31 T: Into<Expression<'a>>,
32{
33 let exprs: Vec<Expression> = exprs.iter().map(|c| c.clone().into()).collect();
34 let fun = TextSearch { exprs };
35
36 fun.into()
37}
38
39#[derive(Debug, Clone, PartialEq)]
40/// Holds the expressions & query on which to perform a text-search ranking compute
41pub struct TextSearchRelevance<'a> {
42 pub(crate) exprs: Vec<Expression<'a>>,
43 pub(crate) query: Cow<'a, str>,
44}
45
46/// Computes the relevance score of a full-text search query against some expressions.
47///
48/// ```rust
49/// # use sqlint::{ast::*, visitor::{Visitor, Postgres}};
50/// # fn main() -> Result<(), sqlint::error::Error> {
51/// let relevance: Expression = text_search_relevance(&[Column::from("name"), Column::from("ingredients")], "chicken").into();
52/// let query = Select::from_table("recipes").so_that(relevance.greater_than(0.1));
53/// let (sql, params) = Postgres::build(query)?;
54///
55/// assert_eq!(
56/// "SELECT \"recipes\".* FROM \"recipes\" WHERE \
57/// ts_rank(to_tsvector(concat_ws(' ', \"name\",\"ingredients\")), to_tsquery($1)) > $2", sql
58/// );
59///
60/// assert_eq!(params, vec![Value::from("chicken"), Value::from(0.1)]);
61/// # Ok(())
62/// # }
63/// ```
64#[cfg(any(feature = "postgresql", feature = "mysql"))]
65pub fn text_search_relevance<'a, E: Clone, Q>(exprs: &[E], query: Q) -> super::Function<'a>
66where
67 E: Into<Expression<'a>>,
68 Q: Into<Cow<'a, str>>,
69{
70 let exprs: Vec<Expression> = exprs.iter().map(|c| c.clone().into()).collect();
71 let fun = TextSearchRelevance { exprs, query: query.into() };
72
73 fun.into()
74}