// // 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 #include #include #include #include #include // 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 struct describe_cursor final : sqlite::vtab::cursor<> { describe_cursor( typename boost::unordered_map::const_iterator itr, typename boost::unordered_map::const_iterator end ) : itr(itr), end(end) { } typename boost::unordered_map::const_iterator itr, end; constexpr static std::size_t column_count = mp11::mp_size>::value; sqlite::result next() {itr++; return {};} sqlite::result row_id() {return itr->first;} void column(sqlite::context<> ctx, int i, bool /* no_change */) { mp11::mp_with_index( i, [&](auto Idx) { using type = mp11::mp_at_c, Idx>; ctx.set_result(itr->second.*type::pointer); }); } bool eof() noexcept {return itr == end;} }; template struct describe_table final : sqlite::vtab::table>, sqlite::vtab::modifiable { boost::unordered_map &data; describe_table(boost::unordered_map &data) : data(data) {} std::string decl; const char * declaration() { if (!decl.empty()) return decl.c_str(); mp11::mp_for_each>( [&](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> open() { return describe_cursor{data.begin(), data.end()}; } sqlite::result delete_(sqlite::value key) { data.erase(key.get_int()); return {}; } sqlite::result insert(sqlite::value key, span 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>( [&](auto elem) { assign_value(res.*elem.pointer , *vtr); vtr++; }); auto itr = data.emplace(id, std::move(res)).first; return itr->first; } sqlite::result update(sqlite::value old_key, sqlite::value new_key, span 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>( [&](auto elem) { assign_value(res.*elem.pointer , *vtr); vtr++; }); return 0u; } }; template struct describe_module final : sqlite::vtab::eponymous_module> { boost::unordered_map data; constexpr static std::size_t column_count = mp11::mp_size>::value; sqlite::result> connect(sqlite::connection , int, const char * const []) { return describe_table{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()); { 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; }