Predicate handlers

It's also possible to write an own predicate handler. Let's write a handler that concatenates all argument passed to the predicate and puts those arguments into the SQL predicate.


# #![allow(unused_variables)]
#fn main() {
use toql::prelude::{Toql,PredicateHandler, SqlExpr, SqlArg,
        ParameterMap, SqlBuilderError, Resolver};
use std::collections::HashMap;

#[derive(Toql)]
#[toql(predicate(name="names", 
                 sql="EXISTS (Select 1 FROM User u JOIN Todo t ON (u.id = t.user_id) \
                AND u.name IN <args>)", handler="my_handler"))]
struct Todo {

    #[toql(key)]
    id: u64,

    what: String,
}




pub(crate) struct MyPredicateHandler;
impl PredicateHandler for MyPredicateHandler {
    fn build_predicate(
        &self,
        predicate: SqlExpr, 		// SQL from predicate
        predicate_args: &[SqlArg],	// Arguments from the query
        aux_params: &ParameterMap,	// Aux params
    ) -> Result<Option<SqlExpr>, SqlBuilderError>  // Return None if no filtering should take place
    {
        if predicate_args.is_empty() {
            return Err(SqlBuilderError::FilterInvalid(
                "at least 1 argument expected".to_string(),
            ));
        }
        let mut args_expr = SqlExpr::new();
        predicate_args.iter().for_each(|a| { 
            args_expr.push_arg(a.to_owned());
            args_expr.push_literal(", ");
        });
        args_expr.pop(); // remove trailing ', '

        let mut replace = HashMap::new();
        replace.insert("args".to_string(), args_expr);
        let predicate = Resolver::replace_aux_params(predicate, &replace); // Replace  aux params with SQL expressions
        
        Ok(Some(predicate))
    }
}

// Getter function
pub fn my_handler() -> impl PredicateHandler {
    MyPredicateHandler {}
}

#}

Use it in a Toql query with @names 'Peter' 'Sandy' 'Bob'