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 /include/boost/sqlite/json.hpp | |
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 'include/boost/sqlite/json.hpp')
-rw-r--r-- | include/boost/sqlite/json.hpp | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/include/boost/sqlite/json.hpp b/include/boost/sqlite/json.hpp new file mode 100644 index 0000000..3409e56 --- /dev/null +++ b/include/boost/sqlite/json.hpp @@ -0,0 +1,140 @@ +// +// 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) +// + +#ifndef BOOST_SQLITE_JSON_HPP +#define BOOST_SQLITE_JSON_HPP + +#include <boost/sqlite/detail/config.hpp> +#include <boost/sqlite/field.hpp> +#include <boost/sqlite/resultset.hpp> +#include <boost/sqlite/value.hpp> +#include <boost/json/parse.hpp> +#include <boost/json/serializer.hpp> +#include <boost/json/storage_ptr.hpp> +#include <boost/json/value_from.hpp> + +BOOST_SQLITE_BEGIN_NAMESPACE + +struct resultset; +struct field; +struct value; + +/// @brief The subtype value used by the sqlite json extension. See the [sqlite reference](https://www.sqlite.org/json1.html) +constexpr int json_subtype = static_cast<int>('J'); + +inline void tag_invoke(const struct set_result_tag &, sqlite3_context * ctx, const json::value & value) +{ + json::serializer ser; + ser.reset(&value); + + sqlite3_int64 len = 4096; + unique_ptr<char> c{static_cast<char*>(sqlite3_malloc64(len))}; + + len = sqlite3_msize(c.get()); + auto v = ser.read(c.get(), len); + + while (!ser.done()) + { + auto l = v.size(); + len *= 2; + c.reset(static_cast<char*>(sqlite3_realloc(c.release(), len))); + v = ser.read(c.get() + l, len); + } + + sqlite3_result_text(ctx, c.release(), v.size(), sqlite3_free); + sqlite3_result_subtype(ctx, json_subtype); +} + +///@{ +/// @brief Check if the value or field is a json. @ingroup reference +inline bool is_json(const value & v) { return v.type() == value_type::text && v.subtype() == json_subtype; } +inline bool is_json(const field & f) { return f.type() == value_type::text && f.get_value().subtype() == json_subtype; } +///@} + +///@{ +/// @brief Convert the value or field to a json. @ingroup reference +inline json::value as_json(const value & v, json::storage_ptr ptr = {}) +{ + return json::parse(v.get_text(), ptr); +} +inline json::value as_json(const field & f, json::storage_ptr ptr = {}) +{ + return json::parse(f.get_text(), ptr); +} +///@} + + +inline void tag_invoke( const json::value_from_tag &, json::value& val, const value & f) +{ + switch (f.type()) + { + case value_type::integer: + val.emplace_int64() = f.get_int(); + break; + case value_type::floating: + val.emplace_double() = f.get_double(); + break; + case value_type::text: + { + auto txt = f.get_text(); + if (f.subtype() == json_subtype) + val = json::parse(txt, val.storage()); + else + val.emplace_string() = txt; + } + break; + case value_type::blob: + throw_exception(std::invalid_argument("cannot convert blob to json")); + case value_type::null: + default: + val.emplace_null(); + } +} + +inline void tag_invoke( const json::value_from_tag &, json::value& val, const field & f) +{ + switch (f.type()) + { + case value_type::integer: + val.emplace_int64() = f.get_int(); + break; + case value_type::floating: + val.emplace_double() = f.get_double(); + break; + case value_type::text: + { + auto txt = f.get_text(); + if (f.get_value().subtype() == json_subtype) + val = json::parse(txt, val.storage()); + else + val.emplace_string() = txt; + } + break; + case value_type::blob: + throw_exception(std::invalid_argument("cannot convert blob to json")); + case value_type::null: + default: + val.emplace_null(); + } +} + +inline void tag_invoke( const json::value_from_tag &, json::value& val, resultset && rs) +{ + auto & obj = val.emplace_array(); + + for (auto r : rs) + { + auto & row = obj.emplace_back(json::object(obj.storage())).get_object(); + for (auto c : r) + row[c.column_name()] = json::value_from(c, row.storage()); + } +} + +BOOST_SQLITE_END_NAMESPACE + + +#endif //BOOST_SQLITE_JSON_HPP |