Как реализовать вложенные фильтры в дизельном топливе?

Я новичок в Rust and Diesel. Теперь я пытаюсь реализовать фильтрацию дизельного топлива для такого запроса:

-- @param1 is duration in years
-- @param2 is duration in months

SELECT columns FROM a
WHERE 
(...dynamic AND clauses)
AND (((a.min_unit = "Years") AND (a.min_duration <= @param1))
  OR ((a.min_unit = "Months") AND (a.min_duration <= @param2)))
(...dynamic AND clauses)

После нескольких поисков в документах и ​​в Интернете я все еще не мог найти, как это сделать. Мое самое близкое предположение:

let param1 = ...;
let param2 = ...;

let mut query = a::table.select(a::all_columns).into_boxed();
// dynamic clauses: query = query.filter(...) ...
query = query.filter(a::min_unit.eq(Some("Years")).and(a::min_duration.le(Some(param1))))
  .or_filter(a::min_unit.eq(Some("Months")).and(a::min_duration.le(Some(param2))));
// dynamic clauses: query = query.filter(...) ...

let results = a::table.load<A>(&*conn);

У кого-нибудь есть идея?

Спасибо!


person Chakrit W    schedule 13.05.2020    source источник


Ответы (2)


Ваш код действительно выглядит правильно (я его не запускал). В документации указано, как это делается: https://docs.diesel.rs/diesel/query_dsl/trait.QueryDsl.html#method.or_filter foo.filter(bar).or_filter(baz) is like foo.filter(bar.or(baz)), но второй является «вложенным». Итак, чтобы получить (id = 5 OR other = 6) AND foo=7, нужно сделать .filter(id.eq(5).or(other.eq(6))).filter(foo.eq(7)). Надеюсь, это поможет!

person Greg Edwards    schedule 14.05.2020

Что ж, вот моя последняя попытка:

let min_months_predicate = a::min_unit.eq(Some("Months"))
    .and(a::min_duration.le(Some(param1)));
let min_years_predicate = a::min_unit.eq(Some("Years"))
    .and(a::min_duration.le(Some(param1)));

query = query.filter(min_months_predicate.or(min_years_predicate))
    .filter(a::max_duration.ge(Some(param2)));

debug!("TEST QUERY: {:?}", debug_query(&query));

что дает этот запрос:

"SELECT \"a\".\"id\", \"a\".\"code\", .... WHERE (\"a\".\"min_unit\" = $1 AND \"a\".\"min_duration\" <= $2 OR \"a\".\"min_unit\" = $3 AND \"a\".\"min_duration\" <= $4) AND \"a\".\"max_duration\" >= $5"

И когда я использую sql EXPLAIN с этим запросом, я получаю следующее предложение:

  Filter: ((max_duration >= 60) AND (((min_unit = 'Months'::text) AND (min_duration <= 3)) OR ((min_unit = 'Years'::text) AND (min_duration <= 5))))

что кажется правильным.

person Chakrit W    schedule 05.06.2020