
Am 15.05.2022 um 18:25 schrieb Ruben Perez:
I'm not really getting the interface that your input/output transformers would expose, though. Let's take this one, for example:
template <> struct OutputTransformer<NullAsEmptyString> { using value_type = std::string;
static std::string get_value( int /*index_*/ ) { static std::string x = "hello"; return x; }; static void get_value( int index_, std::string& value_ ) { value_ = get_value( index_ ); }; };
I assume this is user-provided code. Where does the user get the string value from? What does index_ mean in this context?
sorry for beeing not clear (and sending a not directly fitting example)
that code should be library code - more a less a collection of base-mysql concepts that can be used - this sample transformer lets you act empty strings as null in mysql - the implementation is a dummy - only to get a feeling how the data-flow is
my adaption is used with SQLite and the index is the parameter index that would then map to SQLite bind functions or as in this case checks if the value is null and returns ""
plus serveral other "typical" helper for adaption problems
What kind of transformers do you propose? For instance, something to make a NULL string be treated as empty is a pattern I don't especially like. I guess string-to-json parsing is the obvious one. That would end up having the form of custom types that can be specified in the tuple/struct representing a row, so something like:
tuple<int, std::string, null_as_empty_string> row; resultset.read_one(row);
std:optional would be more correct clearly all Basic types TEXT NULL <-> std::optional<std::string> BasicType NULL <-> std::optional<BasicType>
to know as much as possible before-hand - allows maybe deeper optimization etc. for example the my_select instance can use prepared statements per default (and this is connection oriented with sqlite)
I'd say you know at compile-time as much in both cases.
// return value tuple const auto [ein_int2, ein_float2, ein_string2] = my_select( { 123 } );
I'd suggest something like
struct my_row { int ein_int2; float ein_float2; string ein_string2; }; BOOST_DESCRIBE_STRUCT(my_row); resultset.read_one(row);
i like it flexible to adapt to my structures, tuples etc. - but yours seems flexible enough so far im a big nearly/zero copy fan
Returning it by value works great for sync ops but can have bad implications in async ops.
thats true - but that counts for every value stuff using async
// multi row fetch using My_select = Prepared_fetch<std::tuple<int>, std::tuple<int, float, NullAsEmptyString>>; My_select my_select( db_connection, "select a, b from test where c == ?1" );
std::vector<Result2> result; my_select.fetch_copy( std::back_inserter( result ), 34 ); my_select.fetch_copy( result, 34 );
auto fetch_func = []( const int& /*ein_int_*/, const float& /*ein_float_*/, const std::string& /*ein_string_*/ ) {}; my_select.fetch_func( fetch_func, 34 ); auto fetch_func_cancel = []( const int& /*ein_int_*/, const float& /*ein_float_*/, const std::string& /*ein_string_*/ ) { return false; }; my_select.fetch_func_with_cancel( fetch_func_cancel, 34 );
I can see something like fetch_copy, as a generalization of resultset::read_many. Other users have also brought it up. https://github.com/anarthal/mysql/issues/58 tracks it. It can be extended to work with tuples or structs.
don't forget the ability to read cursor/stream based and allow breaking the read beforehand therefor im having this callable lambda that allows to end reading based on runtime decision
Boost does only provide low level stuff for real low level concepts (smart-pointer, maps etc.-) but most other libraries are always introducing very high level concepts
As Mateusz pointed out, I think there is room for everything - Beast has very low level stuff, too.
you right with that