summaryrefslogtreecommitdiff
path: root/include/boost/sqlite/json.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'include/boost/sqlite/json.hpp')
-rw-r--r--include/boost/sqlite/json.hpp140
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