To customize mappings within a table, pass a
as an extra argument to the table's constructor. All the various
serial_table constructors allow
this extra argument at the end. Thus:
serial_table<animal> animals(db, "animals", &animal::id, my_customization());
Now all the
animals will be represented in signed
integer columns of 16 and 32 bits respectively, as specified in
For any other polymorphically mapped type
the choice of mapper class falls back to the database: it will apply
its own custom mapper for
T, if it has one,
or else fall back to the defaults from the backend library.
Table-level customizations are fine as long as you are storing values like this:
animals .where(animals->id == jumbo_id) .update(animals->n_legs, uint16_t(4));
and retrieving them like this:
const optional<uint16_t> n_legs = animals .where(animals->id == jumbo_id) .select(animals->n_legs) .get();
but any use of table-level customized data in server-side expressions
is fraught with hazards. E.g. in the expression
the left operand is mapped according to the table's customized mapping,
2u (in that context)
does not belong to the table, so it is mapped according to the database's
mapping (which may or may not have its own customizations). And the expression
as a whole does not belong to the table, so if it's value goes back to
the client, it will be converted to C++ data by the database's mapping,
not the table's.
My advice is: use table-level customization sparingly. It is for situations where you have a large amount of data that needs to be stored compactly, but then you need to keep that data away from server-side expressions.
All uses of
have their problems, as we know, but if the deployments stay at the database
level, then at least you can be sure that a consistent set of mappings
will apply across any given query.