diff options
author | John Turner <jturner.usa@gmail.com> | 2025-09-14 00:16:10 -0400 |
---|---|---|
committer | John Turner <jturner.usa@gmail.com> | 2025-09-14 00:16:10 -0400 |
commit | efcea3a80da7c4479d5fe168435ecc9fd06bdc72 (patch) | |
tree | 5cb0177e17b1b00a177f2e830e809f606334571b /example/describe.cpp | |
download | sqlite-kv-bench-efcea3a80da7c4479d5fe168435ecc9fd06bdc72.tar.gz |
Squashed 'subprojects/boost-sqlite/' content from commit 3378e35
git-subtree-dir: subprojects/boost-sqlite
git-subtree-split: 3378e353705271e569cf4ba15c467b840a39798c
Diffstat (limited to 'example/describe.cpp')
-rw-r--r-- | example/describe.cpp | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/example/describe.cpp b/example/describe.cpp new file mode 100644 index 0000000..9b00f8b --- /dev/null +++ b/example/describe.cpp @@ -0,0 +1,202 @@ +// +// Copyright (c) 2022 Klemens Morgenstern (klemens.morgenstern@gmx.net) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include <boost/sqlite.hpp> +#include <boost/unordered_map.hpp> +#include <boost/describe.hpp> +#include <boost/variant2/variant.hpp> + +#include <iomanip> +#include <iostream> + +// This example shows how a virtual table can be created using boost.describe + +using namespace boost; + +// add more conversions here if you need more types in the described struct +void assign_value(std::int64_t & res, sqlite::value val) { res = val.get_int();} +void assign_value(std::string & res, sqlite::value val) { res = val.get_text();} + +template<typename T> +struct describe_cursor final : sqlite::vtab::cursor<> +{ + describe_cursor( + typename boost::unordered_map<sqlite3_int64, T>::const_iterator itr, + typename boost::unordered_map<sqlite3_int64, T>::const_iterator end + ) : itr(itr), end(end) + { + } + + typename boost::unordered_map<sqlite3_int64, T>::const_iterator itr, end; + constexpr static std::size_t column_count = mp11::mp_size<describe::describe_members<T, describe::mod_any_access>>::value; + + sqlite::result<void> next() {itr++; return {};} + sqlite::result<sqlite3_int64> row_id() {return itr->first;} + + void column(sqlite::context<> ctx, int i, bool /* no_change */) + { + mp11::mp_with_index<column_count>( + i, [&](auto Idx) + { + using type = mp11::mp_at_c<describe::describe_members<T, describe::mod_public>, Idx>; + ctx.set_result(itr->second.*type::pointer); + }); + } + + bool eof() noexcept {return itr == end;} +}; + +template<typename T> +struct describe_table final : + sqlite::vtab::table<describe_cursor<T>>, + sqlite::vtab::modifiable +{ + boost::unordered_map<sqlite3_int64, T> &data; + describe_table(boost::unordered_map<sqlite3_int64, T> &data) : data(data) {} + + std::string decl; + const char * declaration() + { + if (!decl.empty()) + return decl.c_str(); + mp11::mp_for_each<describe::describe_members<T, describe::mod_public>>( + [&](auto elem) + { + if (decl.empty()) + decl += "create table x("; + else + decl += ", "; + + decl += elem.name; + }); + decl += ");"; + return decl.c_str(); + } + + + sqlite3_int64 last_index = 0; + + sqlite::result<describe_cursor<T>> open() + { + return describe_cursor<T>{data.begin(), data.end()}; + } + + sqlite::result<void> delete_(sqlite::value key) + { + data.erase(key.get_int()); + return {}; + } + sqlite::result<sqlite_int64> insert(sqlite::value key, span<sqlite::value> values, int /*on_conflict*/) + { + T res; + sqlite_int64 id = key.is_null() ? last_index++ : key.get_int(); + auto vtr = values.begin(); + mp11::mp_for_each<describe::describe_members<T, describe::mod_public>>( + [&](auto elem) + { + assign_value(res.*elem.pointer , *vtr); + vtr++; + }); + + auto itr = data.emplace(id, std::move(res)).first; + return itr->first; + + } + sqlite::result<sqlite_int64> update(sqlite::value old_key, sqlite::value new_key, + span<sqlite::value> values, int /*on_conflict*/) + { + if (new_key.get_int() != old_key.get_int()) + data.erase(old_key.get_int()); + auto & res = data[new_key.get_int()]; + + auto vtr = values.begin(); + mp11::mp_for_each<describe::describe_members<T, describe::mod_public>>( + [&](auto elem) + { + assign_value(res.*elem.pointer , *vtr); + vtr++; + }); + return 0u; + } +}; + +template<typename T> +struct describe_module final : sqlite::vtab::eponymous_module<describe_table<T>> +{ + boost::unordered_map<sqlite3_int64, T> data; + constexpr static std::size_t column_count = mp11::mp_size<describe::describe_members<T, describe::mod_any_access>>::value; + sqlite::result<describe_table<T>> connect(sqlite::connection , + int, const char * const []) + { + return describe_table<T>{data}; + } +}; + + +void print_table(std::ostream & str, sqlite::resultset res) +{ + for (auto i = 0u; i < res.column_count(); i ++) + str << "| " << std::setfill(' ') << std::setw(15) << res.column_name(i) << " "; + + str << "|\n"; + + for (auto i = 0u; i < res.column_count(); i ++) + str << "|-----------------"; + str << "|\n"; + + for (auto && r : res) + { + for (auto i = 0u; i < res.column_count(); i ++) + str << "| " << std::setfill(' ') << std::setw(15) << r.at(i).get_text() << " "; + + str << "|\n" ; + } + str << std::endl; +} + + +struct boost_library +{ + std::string name; + std::int64_t first_released; + std::int64_t standard; +}; + +BOOST_DESCRIBE_STRUCT(boost_library, (), (name, first_released, standard)); + + +int main (int /*argc*/, char * /*argv*/[]) +{ + sqlite::connection conn{":memory:"}; + auto & md = sqlite::create_module(conn, "boost_libraries", describe_module<boost_library>()); + + { + auto p = conn.prepare("insert into boost_libraries (name, first_released, standard) values ($name, $version, $std);"); + p.execute({{"name", "process"}, {"version", 64}, {"std", 11}}); + p.execute({{"name", "asio"}, {"version", 35}, {"std", 98}}); + p.execute({{"name", "bimap"}, {"version", 35}, {"std", 98}}); + p.execute({{"name", "circular_buffer"}, {"version", 35}, {"std", 98}}); + p.execute({{"name", "mpi"}, {"version", 35}, {"std", 98}}); + p.execute({{"name", "beast"}, {"version", 66}, {"std", 11}}); + p.execute({{"name", "describe"}, {"version", 77}, {"std", 14}}); + } + + + print_table(std::cout, conn.query("select * from boost_libraries;")); + + // same as conn.execute("update boost_libraries set standard = 11 where standard = 98;"); + for (auto & p : md.data) + if (p.second.standard == 98) + p.second.standard = 11; + + print_table(std::cout, conn.query("select * from boost_libraries;")); + + conn.prepare("delete from boost_libraries where name = ?").execute({"mpi"}); + print_table(std::cout, conn.query("select * from boost_libraries;")); + + return 0; +} |