Repository navigation
Description
So I'm not the biggest fan of generating the table structs from SQL but I also didn't like the macro based solution sqlpp11 had.
Instead I like to have my types as simple structs, that I can easily read and which allow me to use designated initializers.
Which is why I've had templated classes to create those table structs for sqlpp11 already and now I've also tried to do something similar, quick and dirty for sqlpp23.
So, at the moment this allows me to define my tables like this:
namespace identifier{
SQLPP_MAKE_IDENTIFIER(user);
SQLPP_MAKE_IDENTIFIER(id);
SQLPP_MAKE_IDENTIFIER(name);
SQLPP_MAKE_IDENTIFIER(display_name);
}
struct user{
std::uint64_t id;
std::string name;
std::optional<std::string> display_name;
using table = sqlpp::table_t<sqlpp::tablegen::table<
user, identifier::user_t, "user", sqlpp::tablegen::fields<
sqlpp::tablegen::field<&user::id, identifier::id_t, "id", sqlpp::tablegen::field_options::required>,
sqlpp::tablegen::field<&user::name, identifier::name_t, "name">,
sqlpp::tablegen::field<&user::display_name, identifier::display_name_t, "display_name">
>
>>;
};
inline constexpr user::table user{};
int main(){
// ...
db(sqlpp::insert_into(user).set(user.id = 3, user.name = "abc", user.display_name = std::nullopt));
}having the identifiers separate is also a benefit for me, as you're often using the same identifiers multiple times (e.g. id for multiple types) or want to use them for aliases (though I haven't looked into those for sqlpp23 yet).
You could also go even further with this and maybe create mappings between those types and the query result fields (like a query_result.merge_into(my_obj) to update a "cached" object) or return this aggregate type in case of a SELECT * FROM .... But this might be a bit intrusive.
I haven't really tested this yet, it's basically "it compiles" at the moment, as it was just trying it out and I plan to change it up still.
Downsides would probably be, the error messages being worse than with "hard-coded" structures and also more to maintain of course (so far the code is quite managable I think).
So my question now is, if this would be something desirable for sqlpp23 itself, or if I should keep it in my own fork/repo, which is totally fine with me as well.
-Jonas
Activity
rbock commentedon Apr 17, 2025
Thanks for sharing, @vaijns !
I have a couple of questions / comments:
identifiersnamespace multiple times?sqlpp::detail::make_type_set_ifmight replace yourconditional_type_set._required_insert_columnsintosqlpp::table_t.inplace_stringvs.constexpr string_view?std::bool_constant:-)Looking forward to the next iteration!
Cheers,
Roland
vaijns commentedon Apr 17, 2025
Let me begin by saying: tbf, practically I don't have much of a use case, that couldn't be solved by the ddl2cpp generated code at the moment.
My intentions are mostly based on the idealistic desire to have my C++ code as my single source of truth for the table structure (well... Besides the actual database that can be out of sync) instead of the create scripts.
So in an ideal world, all I'd have to write would be:
Basically all data that I need in the simplest form possible.
But unfortunately reflection will take some time to arrive as a standardized feature in our compilers and annotations might take longer. :D
And I really wanna keep macro use to a minimum.
So the next best thing for me is, writing the "reflections" myself and that's pretty much what that is for me.
So, to your questions:
select(user.id, group.id.as(identifier::group{})).from(...)or something like that)make_type_set_ifseems like what I needinplace_stringis structural, so it's allowed as non-tyle template argument! So I can domy_type_taking_inplace_string<"Hello world!">{}but for the static constexpr field I could make it astring_view, doesn't matter much therebool_constantby surprise while doing this! :Duser obj{ .id = 3, .name = "abc", .display_name = std::nullopt }with my types. Tbf I could change ddl2cpp to generate those tooAll of this is very subjective and just what I myself prefer, which is why I'm also not sure if the "core" of sqlpp would even be the right place for this or if I should keep it outside of it in its own repo.
-Jonas
rbock commentedon Apr 17, 2025
Thanks for the explanations! I can imagine situations in which having those aggregates might be useful. And yes, I wish we had reflection already!
I think you should be able to drop the string parameter, e.g. "id" as the identifier already contains the string?
That said, I don't think this should be added to the library, at least for now. But is certainly is good food for thought!
vaijns commentedon Apr 17, 2025
In this case the string wouldn't really be necessary, yes. But this would be the name of the actual SQL column, which I thought would still be good to have in case it differs.
Alright, I will work on it separately then, once I've even got proper time for it, thanks for the feedback!
And great work on the library update, has some very good improvements from what I've seen!
rbock commentedon Apr 17, 2025
Good luck and thanks for the flowers!