// // 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 #include #include namespace boost { namespace mysql { namespace detail { BOOST_MYSQL_DECL std::pair parse_range_specifiers(const char* spec_begin, const char* spec_end); // To use with arguments with a custom formatter template bool do_format_custom_formatter( const void* obj, const char* spec_begin, const char* spec_end, format_context_base& ctx ) { formatter fmt; const char* it = fmt.parse(spec_begin, spec_end); if (it != spec_end) { return false; } fmt.format(*static_cast(obj), ctx); return true; } // To use with ranges template 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(static_cast(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 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 is not formattable. Please use a formattable type or specialize formatter to make it " "formattable" ); return { formattable_ref_impl::type_t::fn_and_ptr, formattable_ref_impl::fn_and_ptr{&v, &do_format_custom_formatter} }; } // Make ranges formattable template 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::type>} }; } template formattable_ref_impl make_formattable_ref_range( const T& v, std::false_type // formattable range ) { return make_formattable_ref_custom(v, is_formattable_ref()); } // Used for types having is_writable_field template 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::value ? formattable_ref_impl::type_t::field_with_specs : formattable_ref_impl::type_t::field, to_field(v) }; } template formattable_ref_impl make_formattable_ref_writable( T&& v, std::false_type // is_writable_field ) { return make_formattable_ref_range(std::forward(v), is_formattable_range()); } } // namespace detail } // namespace mysql } // namespace boost template 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(v), is_writable_field_ref()); } template void boost::mysql::format_sql_to( format_context_base& ctx, constant_string_view format_str, Formattable&&... args ) { std::initializer_list args_il{ {string_view(), std::forward(args)} ... }; format_sql_to(ctx, format_str, args_il); } template std::string boost::mysql::format_sql( format_options opts, constant_string_view format_str, Formattable&&... args ) { std::initializer_list args_il{ {string_view(), std::forward(args)} ... }; return format_sql(opts, format_str, args_il); } #endif