[odb-users] Query with conditional parts

Aarón Bueno Villares abv150ci at gmail.com
Tue Oct 4 10:05:30 EDT 2016


Suppose I have to construct a query depending on some external conditions,
in such a way I need to construct a query in different steps or parts, like:

     using q_vw_t = my_view;
     using q_t = odb::query<q_vw_t>;

     auto query = q_t::field_1.is_not_null();

      if (some_condition)
            query = query and q_t::field_2 == 5;
      else
             query = query and q_t::field_2.is_null();

There's no comments or examples in the ODB's documentation telling if that
can be done or what is the type of `q_t::field_1` or `q_t::field_1 == 5`.

I know, reading the ODB source code, that every operation over a column
(`.is_null()`, `and`, or whichever it is), returns a `query_base` oject
(which isn't parametric). So, I know every operation returns and object of
a same type, and thus, I can reuse the same variable and the type is
constant through any composition chain.

But because I'm not allow to know any implementation detail of how query
works (for example, if the implementation changes), I've created a
"functional" method to compose simple queries trying to avoid any asumption
about types.

My method is: I receive a callable object, and a list of pair of values,
and I pass each pair to the callable object, composing the returned objects
of each call with `and`s (no 100% generic of course, but enough for my
specific case; I would just need a `comb` callable object to specify what
to do with results instead of `and`).

Each pair is suppossed to be a column and a value to be compared with the
column, but in fact, can be anything accepted by the `cond`ition.

Case-base:

    template<class cond_t, class col_t, class mo_t>
    auto conditional_query(cond_t const& cond, col_t const& col, mo_t
const& mo)
        -> decltype(cond(col, mo))
    { return cond(col, mo); }


General-case:

    template<class cond_t, class col_t, class mo_t, class... more_t>
    auto conditional_query(cond_t const& cond, col_t const& col, mo_t
const& mo,
                           more_t&&... more)
        -> typename std::enable_if<
            (sizeof...(more) > 1),
                decltype(cond(col, mo) and conditional_query
                         (cond, std::forward<more_t>(more)...))>::type
    {
        return cond(col, mo) and
            conditional_query(cond, std::forward<more_t>(more)...);
    }

So, my conditional query is safe in the sense that its type is just the
result of the composition. There' s any asumption about common types
between operations or something. That function is correct without
considering if I've read the source code or not.

However, the "hole" lives in the "condition":

    // mo_t is just a wrapper of mine of a shared_ptr containing a instance
of a
    // persistent class. `valid` is true if the `shared_ptr` owns an
object, and `.id()`
    // returns the primary key as integer of the object otherwise.
    struct q_branch
    {
        template<class col_t, class mo_t>
        auto operator()(col_t const& col, mo_t const& mo) const
            -> decltype(col.is_null())
        {
            return mo.valid() ? col == mo.id() : col.is_null();
        }

    };

I assume here that the types of `col == mo.id()` and `col.is_null()` are
the same (which in fact they are, but it's a thing I know because I've read
the source code).

My question is: can ODB officially say that queries can be composed in
steps? Because, if the answer is yes, I could simply do:

     using q_vw_t = my_view;
     using q_t = odb::query<q_vw_t>;

     auto query = q_t::field_1.is_not_null();

      if (some_condition)
            query = query and q_t::field_2 == 5;
      else
             query = query and q_t::field_2.is_null();

My above method `conditional_query` is just to "carry" my
"discoveries/assumptions" to a focused place (the condition object) in case
of problems.

Is there other way of doing what I'm doing? Apart from creating new views,
of course, because there could be a lot of them.


More information about the odb-users mailing list