123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- //
- // Copyright (c) 2019-2024 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
- //
- // 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_MYSQL_IMPL_FORMAT_SQL_HPP
- #define BOOST_MYSQL_IMPL_FORMAT_SQL_HPP
- #pragma once
- #include <boost/mysql/format_sql.hpp>
- #include <boost/mysql/detail/format_sql.hpp>
- #include <type_traits>
- namespace boost {
- namespace mysql {
- namespace detail {
- BOOST_MYSQL_DECL
- std::pair<bool, string_view> parse_range_specifiers(const char* spec_begin, const char* spec_end);
- // To use with arguments with a custom formatter
- template <class T>
- bool do_format_custom_formatter(
- const void* obj,
- const char* spec_begin,
- const char* spec_end,
- format_context_base& ctx
- )
- {
- formatter<T> fmt;
- const char* it = fmt.parse(spec_begin, spec_end);
- if (it != spec_end)
- {
- return false;
- }
- fmt.format(*static_cast<const T*>(obj), ctx);
- return true;
- }
- // To use with ranges
- template <class T>
- bool do_format_range(const void* obj, const char* spec_begin, const char* spec_end, format_context_base& ctx)
- {
- // Parse specifiers
- auto res = detail::parse_range_specifiers(spec_begin, spec_end);
- if (!res.first)
- return false;
- auto spec = runtime(res.second);
- // Retrieve the object. T here may be the actual type U or const U
- auto& value = *const_cast<T*>(static_cast<const T*>(obj));
- // Output the sequence
- bool is_first = true;
- for (auto it = std::begin(value); it != std::end(value); ++it)
- {
- if (!is_first)
- ctx.append_raw(", ");
- is_first = false;
- ctx.append_value(*it, spec);
- }
- return true;
- }
- // Make formattable_ref formattable
- inline formattable_ref_impl make_formattable_ref_custom(
- formattable_ref v,
- std::true_type // is format ref
- )
- {
- return access::get_impl(v);
- }
- // Make types with custom formatters formattable
- template <class T>
- formattable_ref_impl make_formattable_ref_custom(
- const T& v,
- std::false_type // is format ref
- )
- {
- // If you're getting an error here, it means that you're passing a type
- // that is not formattable to a SQL formatting function.
- static_assert(
- has_specialized_formatter<T>(),
- "T is not formattable. Please use a formattable type or specialize formatter<T> to make it "
- "formattable"
- );
- return {
- formattable_ref_impl::type_t::fn_and_ptr,
- formattable_ref_impl::fn_and_ptr{&v, &do_format_custom_formatter<T>}
- };
- }
- // Make ranges formattable
- template <class T>
- formattable_ref_impl make_formattable_ref_range(
- T&& v,
- std::true_type // formattable range
- )
- {
- // Although everything is passed as const void*, do_format_range
- // can bypass const-ness for non-const ranges (e.g. filter_view)
- return {
- formattable_ref_impl::type_t::fn_and_ptr,
- formattable_ref_impl::fn_and_ptr{&v, &do_format_range<typename std::remove_reference<T>::type>}
- };
- }
- template <class T>
- formattable_ref_impl make_formattable_ref_range(
- const T& v,
- std::false_type // formattable range
- )
- {
- return make_formattable_ref_custom(v, is_formattable_ref<T>());
- }
- // Used for types having is_writable_field<T>
- template <class T>
- formattable_ref_impl make_formattable_ref_writable(
- const T& v,
- std::true_type // is_writable_field
- )
- {
- // Only string types (and not field_views or optionals) support the string specifiers
- return {
- std::is_convertible<T, string_view>::value ? formattable_ref_impl::type_t::field_with_specs
- : formattable_ref_impl::type_t::field,
- to_field(v)
- };
- }
- template <class T>
- formattable_ref_impl make_formattable_ref_writable(
- T&& v,
- std::false_type // is_writable_field
- )
- {
- return make_formattable_ref_range(std::forward<T>(v), is_formattable_range<T>());
- }
- } // namespace detail
- } // namespace mysql
- } // namespace boost
- template <class T>
- boost::mysql::detail::formattable_ref_impl boost::mysql::detail::make_formattable_ref(T&& v)
- {
- // Hierarchy:
- // 1. writable field?
- // 2. formattable range?
- // 3. custom formatter or formattable_ref?
- return make_formattable_ref_writable(std::forward<T>(v), is_writable_field_ref<T>());
- }
- template <BOOST_MYSQL_FORMATTABLE... Formattable>
- void boost::mysql::format_sql_to(
- format_context_base& ctx,
- constant_string_view format_str,
- Formattable&&... args
- )
- {
- std::initializer_list<format_arg> args_il{
- {string_view(), std::forward<Formattable>(args)}
- ...
- };
- format_sql_to(ctx, format_str, args_il);
- }
- template <BOOST_MYSQL_FORMATTABLE... Formattable>
- std::string boost::mysql::format_sql(
- format_options opts,
- constant_string_view format_str,
- Formattable&&... args
- )
- {
- std::initializer_list<format_arg> args_il{
- {string_view(), std::forward<Formattable>(args)}
- ...
- };
- return format_sql(opts, format_str, args_il);
- }
- #endif
|