with_params.hpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. //
  2. // Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. #ifndef BOOST_MYSQL_WITH_PARAMS_HPP
  8. #define BOOST_MYSQL_WITH_PARAMS_HPP
  9. #include <boost/mysql/constant_string_view.hpp>
  10. #include <boost/mysql/detail/format_sql.hpp>
  11. #include <tuple>
  12. #include <utility>
  13. namespace boost {
  14. namespace mysql {
  15. /**
  16. * \brief Type trait that applies the transformation performed by `std::make_tuple` to a single element.
  17. * \details
  18. * For example: \n
  19. * - `make_tuple_element_t<int>` yields `int` \n
  20. * - `make_tuple_element_t<const int&>` yields `int` \n
  21. * - `make_tuple_element_t<std::reference_wrapper<int>>` yields `int&` \n
  22. * \n
  23. * Consult the <a href="https://en.cppreference.com/w/cpp/utility/tuple/make_tuple">`std::make_tuple`</a> docs
  24. * for more info.
  25. */
  26. template <class T>
  27. using make_tuple_element_t = typename std::tuple_element<0, decltype(std::make_tuple(std::declval<T&&>()))>::
  28. type;
  29. /**
  30. * \brief A query format string and format arguments that can be executed.
  31. * \details
  32. * Contains a query with placeholders (i.e. `{}`) and a set of parameters to
  33. * expand such placeholders. Satisfies `ExecutionRequest` and can thus be passed
  34. * to \ref any_connection::execute, \ref any_connection::start_execution and its
  35. * async counterparts.
  36. * \n
  37. * When executed, client-side SQL formatting is invoked
  38. * to expand the provided query with the supplied parameters. The resulting query is then sent to
  39. * the server for execution. Formally, given a `conn` variable of \ref any_connection type,
  40. * the query is generated as if the following was called:
  41. * ```
  42. * format_sql(
  43. * this->query,
  44. * conn.format_opts().value(),
  45. * std::get<i>(this->args)... // for i in [0, sizeof...(Formattable))
  46. * );
  47. * ```
  48. * \n
  49. * Objects of this type are usually created using \ref with_params, which
  50. * creates `args` by calling `std::make_tuple`.
  51. *
  52. * \par Object lifetimes
  53. * The format string `query` is stored as a view, as a compile-time string should be used in most cases.
  54. * When using \ref with_params, `args` will usually contain copies of the passed parameters
  55. * (as per <a href="https://en.cppreference.com/w/cpp/utility/tuple/make_tuple">`std::make_tuple`</a>),
  56. * which is safe even when using async functions with deferred completion tokens.
  57. * You may disable such copies using `std::ref`, as you would when using `std::make_tuple`.
  58. *
  59. * \par Errors
  60. * When passed to \ref any_connection::execute, \ref any_connection::start_execution or
  61. * its async counterparts, in addition to the usual network and server-generated errors,
  62. * `with_params_t` may generate the following errors: \n
  63. * - Any errors generated by \ref format_sql. This includes errors due to invalid format
  64. * strings and unformattable arguments (e.g. invalid UTF-8).
  65. * - \ref client_errc::unknown_character_set if the connection does not know the
  66. * character set it's using when the query is executed (i.e. \ref any_connection::current_character_set
  67. * would return an error.
  68. */
  69. template <BOOST_MYSQL_FORMATTABLE... Formattable>
  70. struct with_params_t
  71. {
  72. /// The query to be expanded and executed, which may contain `{}` placeholders.
  73. constant_string_view query;
  74. /// The arguments to use to expand the query.
  75. std::tuple<Formattable...> args;
  76. };
  77. /**
  78. * \brief Creates a query with parameters (client-side SQL formatting) that can be executed.
  79. * \details
  80. * Creates a \ref with_params_t object by packing the supplied arguments into a tuple,
  81. * calling <a href="https://en.cppreference.com/w/cpp/utility/tuple/make_tuple">`std::make_tuple`</a>.
  82. * As per `std::make_tuple`, parameters will be decay-copied into the resulting object.
  83. * This behavior can be disabled by passing `std::reference_wrapper` objects, which are
  84. * transformed into references.
  85. * \n
  86. * This function does not inspect the supplied query string and arguments.
  87. * Errors like missing format arguments are detected when the resulting object is executed.
  88. * This function does not involve communication with the server.
  89. * \n
  90. * The passed `args` must either satisfy `Formattable`, or be `std::reference_wrapper<T>`
  91. * with `T` satisfying `Formattable`.
  92. * \n
  93. * See \ref with_params_t for details on how the execution request works.
  94. * \n
  95. * \par Exception safety
  96. * Strong guarantee. Any exception thrown when copying `args` will be propagated.
  97. * \n
  98. */
  99. template <class... FormattableOrRefWrapper>
  100. auto with_params(constant_string_view query, FormattableOrRefWrapper&&... args)
  101. -> with_params_t<make_tuple_element_t<FormattableOrRefWrapper>...>
  102. {
  103. return {query, std::make_tuple(std::forward<FormattableOrRefWrapper>(args)...)};
  104. }
  105. } // namespace mysql
  106. } // namespace boost
  107. #include <boost/mysql/impl/with_params.hpp>
  108. #endif