Boost logo

Boost :

Subject: Re: [boost] sqlpp11, 3rd iteration
From: Adam Wulkiewicz (adam.wulkiewicz_at_[hidden])
Date: 2014-08-19 18:34:15


Roland Bock wrote:
> On 2014-08-19 18:56, Adam Wulkiewicz wrote:
>> Ok AFAIU a struct like _member_t should define some convenient member
>> variable for the user and must define operator() for the library.
>> But the rest could be automatically generated, couldn't it?
>> Why not just pass a list of templates of classes adapted to MemberType
>> concept (defined operator()) into the table/column/etc.?
>> I'm thinking about something like the code below. I don't know exactly
>> what's required so this is just an example of a technique rather than
>> a solution ready-to-use in sqlpp.
> The idea is good. For the columns, you will have to add a few more
> parameters, e.g. the value_type (mandatory), can_be_null,
> must_not_insert, must_not_update, null_is_trivial, trivial_is_null,
> maybe as per your suggestion a default value or a function for producing
> it. That default stuff might be tough in such a design.

The additional traits would be a list of variadic template parameters.
So if this list contained only one type, e.g. sqlpp::default_traits the
default traits could be generated e.g. by specializing sqlpp::make_traits<>.
Since it's impossible to define a default argument of a template
parameters pack (another missing language feature?) it could be
"simulated" with something like:

template <template <typename> class Name,
           typename Trait0 = default_traits,
           typename... Traits
>
struct column
{
     using traits = make_traits<Trait0, Traits...>;
};

Or all traits could be passed as one list type like MPL sequence or
someting like that as you wrote below.

> But thats manageable. And yes, the code would be shorter, although not
> that much, I suspect. The only problem I have with it is that now the
> column types are going to be about a hundred characters long. And users
> are going to operate on columns all the time. So error message have to
> be short.
Do you have in mind the code of the library or user's code?
I expect that the user's code, even not using defaults, would be a lot
shorter.
But the most important is that the definition of a table would probably
be more clear, in one place, etc.
Or am I wrong?

>
> I would thus add a struct which inherits from the column template
> instance for each column, e..g.
>
> struct alpha: public column<tab_member, alpha_member, sqlpp::integral,
> sqlpp::tag::must_not_insert, ...> {};
With variadic templates the construction of traits out of this would be
straightforward.
An alternative would be to take additional parameters/traits list as the
3rd parameter as you wrote below.

Btw, why a column must be aware about a Table?

Can a table also have some traits specified?
I'm asking because then there would be 2 lists that should be passed -
Members and Traits.

> I tried something similar a while back but failed, which is mainly due
> to lack of perseverance, I guess.
>
> Right now, I am happy with the current design because it is quite easy
> to change things, like introducing that default value or a function for
> handling attempts to read NULL.

Sure, I'm not saying that you should change the design. I'm just sharing
my thoughts.

> If you want to put everything into that one list of template parameters,
> it is much tougher, IMO. I mean how would you add a function for
> handling access to NULL value? You would need another class, I think.
> And you would have to group those tags into a tuple or type_set, because
> otherwise it would be ugly to add another optional parameter...

I'm guessing that the function or ... could be passed as yet another
trait like:

struct alpha: public column<tab_member, alpha_member, sqlpp::trivial_value<some_generator> >
  

If not passed, a default trivial value would be used.

The best would be to somehow pass a static value in compile-time but
only integral types could be handled this way. The reference to the
global external variable of non-integral type could also be passed as a
template parameter but still it would have to be defined somewhere so it
wouldn't be convenient.

So some_generator could be a type of default-constructible function
object or a pointer to function, etc.

Or do someone knows some trick that could be used here?

Regards,
Adam


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk