crud.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  1. /*
  2. * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License, version 2.0, as
  6. * published by the Free Software Foundation.
  7. *
  8. * This program is also distributed with certain software (including
  9. * but not limited to OpenSSL) that is licensed under separate terms,
  10. * as designated in a particular file or component or in included license
  11. * documentation. The authors of MySQL hereby grant you an
  12. * additional permission to link the program and your derivative works
  13. * with the separately licensed software that they have included with
  14. * MySQL.
  15. *
  16. * Without limiting anything contained in the foregoing, this file,
  17. * which is part of MySQL Connector/C++, is also subject to the
  18. * Universal FOSS Exception, version 1.0, a copy of which can be found at
  19. * http://oss.oracle.com/licenses/universal-foss-exception.
  20. *
  21. * This program is distributed in the hope that it will be useful, but
  22. * WITHOUT ANY WARRANTY; without even the implied warranty of
  23. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  24. * See the GNU General Public License, version 2.0, for more details.
  25. *
  26. * You should have received a copy of the GNU General Public License
  27. * along with this program; if not, write to the Free Software Foundation, Inc.,
  28. * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  29. */
  30. #ifndef MYSQLX_CRUD_H
  31. #define MYSQLX_CRUD_H
  32. /**
  33. @file
  34. Common templates used to define CRUD operation classes.
  35. */
  36. #include "common.h"
  37. #include "detail/crud.h"
  38. namespace mysqlx {
  39. class Collection;
  40. class Table;
  41. namespace internal {
  42. /*
  43. Factory for constructing concrete implementations of various CRUD
  44. operations. All these implementations implement the base Executable_if
  45. interface.
  46. Note: The caller of mk_xxx() method takes ownership of the returned
  47. implementation object.
  48. */
  49. struct PUBLIC_API Crud_factory
  50. {
  51. using Impl = common::Executable_if;
  52. static Impl* mk_add(Collection &coll);
  53. static Impl* mk_remove(Collection &coll, const string &expr);
  54. static Impl* mk_find(Collection &coll);
  55. static Impl* mk_find(Collection &coll, const string &expr);
  56. static Impl* mk_modify(Collection &coll, const string &expr);
  57. static Impl* mk_insert(Table &tbl);
  58. static Impl* mk_select(Table &tbl);
  59. static Impl* mk_update(Table &tbl);
  60. static Impl* mk_remove(Table &tbl);
  61. static Impl* mk_sql(Session &sess, const string &sql);
  62. };
  63. } // internal
  64. } // mysqlx
  65. /*
  66. Different CRUD operation classes derive from `Executable` which defines
  67. the `execute()` method that executes given operation. Derived classes
  68. define additional methods that can modify the operation before it gets
  69. executed.
  70. The hierarchy of classes reflects the grammar that defines the order in which
  71. fluent API calls can be done. It is built using templates, such as Offset<>
  72. below, which add one API call on top of base class which defines remaining
  73. API calls that can be called later. For example, type
  74. Limit< Offset< Executable<...> > >
  75. represents an operation for which first .limit() can be called, followed by
  76. .offset() and then finally .execute(). See classes like
  77. Collection_find_base in collection_crud.h for more examples.
  78. Each template assumes that its base class defines method 'get_impl()' which
  79. returns a pointer to the internal implementation object. It also assumes that
  80. this implementation is of appropriate type and can be casted to
  81. the appropriate interface type. For example Limit<> template assumes
  82. that the implementation type can be casted to Limit_if type.
  83. */
  84. namespace mysqlx {
  85. /**
  86. @brief The LockContention enum defines constants for defining the row locking contention for `Set_lock::lockExclusive()` and `Set_lock::lockShared()` methods.
  87. @see https://dev.mysql.com/doc/refman/8.0/en/innodb-locking-reads.html#innodb-locking-reads-nowait-skip-locked
  88. */
  89. enum_class LockContention
  90. {
  91. #define DEVAPI_LOCK_CONTENTION_ENUM(X,N) X = N,
  92. LOCK_CONTENTION_LIST(DEVAPI_LOCK_CONTENTION_ENUM)
  93. };
  94. namespace internal {
  95. /**
  96. Template for defining fluent api for CRUD operations.
  97. */
  98. template <class Base>
  99. class Offset
  100. : public Base
  101. {
  102. using Operation = Base;
  103. public:
  104. /**
  105. Skip the given number of items (rows or documents) before starting
  106. to perform the operation.
  107. */
  108. Operation& offset(unsigned rows)
  109. {
  110. try {
  111. get_impl()->set_offset(rows);
  112. return *this;
  113. }
  114. CATCH_AND_WRAP
  115. }
  116. protected:
  117. using Impl = common::Limit_if;
  118. Impl* get_impl()
  119. {
  120. return static_cast<Impl*>(Base::get_impl());
  121. }
  122. };
  123. /// @copydoc Offset
  124. template <class Base>
  125. class Limit
  126. : public Base
  127. {
  128. using Operation = Base;
  129. public:
  130. /**
  131. %Limit the operation to the given number of items (rows or documents).
  132. */
  133. Operation& limit(unsigned items)
  134. {
  135. try {
  136. get_impl()->set_limit(items);
  137. return *this;
  138. }
  139. CATCH_AND_WRAP
  140. }
  141. protected:
  142. using Impl = common::Limit_if;
  143. Impl* get_impl()
  144. {
  145. return static_cast<Impl*>(Base::get_impl());
  146. }
  147. };
  148. /// @copydoc Offset
  149. template <class Base>
  150. class Sort
  151. : public Base
  152. , Sort_detail
  153. {
  154. using Operation = Base;
  155. public:
  156. /**
  157. Specify ordering of documents in a query results.
  158. Arguments are one or more strings of the form `"<expr> <dir>"` where
  159. `<expr>` gives the value to sort on and `<dir>` is a sorting direction
  160. `ASC` or `DESC`.
  161. */
  162. template <typename...Type>
  163. Operation& sort(Type... spec)
  164. {
  165. try {
  166. add_sort(get_impl(), spec...);
  167. return *this;
  168. }
  169. CATCH_AND_WRAP
  170. }
  171. protected:
  172. using Impl = common::Sort_if;
  173. Impl* get_impl()
  174. {
  175. return static_cast<Impl*>(Base::get_impl());
  176. }
  177. };
  178. /// @copydoc Offset
  179. template <class Base>
  180. class Order_by
  181. : public Base
  182. , Sort_detail
  183. {
  184. using Operation = Base;
  185. public:
  186. /**
  187. Specify ordering of rows in a query results.
  188. Arguments are one or more strings of the form `"<expr> <dir>"` where
  189. `<expr>` gives the value to sort on and `<dir>` is a sorting direction
  190. `ASC` or `DESC`.
  191. */
  192. template <typename...Type>
  193. Operation& orderBy(Type... spec)
  194. {
  195. try {
  196. add_sort(get_impl(), spec...);
  197. return *this;
  198. }
  199. CATCH_AND_WRAP
  200. }
  201. protected:
  202. using Impl = common::Sort_if;
  203. Impl* get_impl()
  204. {
  205. return static_cast<Impl*>(Base::get_impl());
  206. }
  207. };
  208. /// @copydoc Offset
  209. template <class Base>
  210. class Having
  211. : public Base
  212. {
  213. using Operation = Base;
  214. public:
  215. /**
  216. Specify filter over grouped results of a query.
  217. The argument is a Boolean expression which can use aggregation functions.
  218. */
  219. Operation& having(const string& having_spec)
  220. {
  221. try {
  222. get_impl()->set_having(having_spec);
  223. return *this;
  224. }
  225. CATCH_AND_WRAP
  226. }
  227. protected:
  228. using Impl = common::Having_if;
  229. Impl* get_impl()
  230. {
  231. return static_cast<Impl*>(Base::get_impl());
  232. }
  233. };
  234. /// @copydoc Offset
  235. template <class Base>
  236. class Group_by
  237. : public Base
  238. , Group_by_detail
  239. {
  240. using Operation = Base;
  241. public:
  242. /**
  243. Specify grouping of items in a query result.
  244. Arguments are a one or more expressions. Documents/rows for which
  245. expressions evaluate to the same value are grouped together.
  246. */
  247. template <typename... Expr>
  248. Operation& groupBy(Expr... group_by_spec)
  249. {
  250. try {
  251. do_group_by(get_impl(), group_by_spec...);
  252. return *this;
  253. }
  254. CATCH_AND_WRAP
  255. }
  256. protected:
  257. using Impl = common::Group_by_if;
  258. Impl* get_impl()
  259. {
  260. return static_cast<Impl*>(Base::get_impl());
  261. }
  262. };
  263. /// @copydoc Offset
  264. template <class Base>
  265. class Bind_placeholders
  266. : public Base
  267. , Bind_detail
  268. {
  269. using BindOperation = Bind_placeholders;
  270. public:
  271. /**
  272. Specify values for '?' placeholders in a query.
  273. One or more values can be specified in a single call to bind(). A query
  274. can be executed only if values for all placeholders have been specified.
  275. */
  276. template <typename... Types>
  277. BindOperation& bind(Types&&... vals)
  278. {
  279. try {
  280. add_params(get_impl(), std::forward<Types>(vals)...);
  281. return *this;
  282. }
  283. CATCH_AND_WRAP
  284. }
  285. protected:
  286. using Impl = common::Bind_if;
  287. Impl* get_impl()
  288. {
  289. return static_cast<Impl*>(Base::get_impl());
  290. }
  291. };
  292. /// @copydoc Offset
  293. template <class Base>
  294. class Bind_parameters
  295. : public Base
  296. {
  297. using BindOperation = Bind_parameters;
  298. using Operation = Base;
  299. public:
  300. /**
  301. Bind parameter with given name to the given value.
  302. A statement or query can be executed only if all named parameters used by
  303. it are bound to values.
  304. */
  305. BindOperation& bind(const string &parameter, const Value &val)
  306. {
  307. if (Value::DOCUMENT == val.getType())
  308. throw_error("Can not bind a parameter to a document");
  309. if (Value::ARRAY == val.getType())
  310. throw_error("Can not bind a parameter to an array");
  311. try {
  312. get_impl()->add_param(parameter, (const common::Value&)val);
  313. return *this;
  314. }
  315. CATCH_AND_WRAP
  316. }
  317. /**
  318. Bind parameters to values given by a map from parameter
  319. names to their values.
  320. */
  321. template <class Map>
  322. Operation& bind(const Map &args)
  323. {
  324. for (const auto &keyval : args)
  325. {
  326. bind(keyval.first, keyval.second);
  327. }
  328. return *this;
  329. }
  330. protected:
  331. using Impl = common::Bind_if;
  332. Impl* get_impl()
  333. {
  334. return static_cast<Impl*>(Base::get_impl());
  335. }
  336. };
  337. /// @copydoc Offset
  338. template <class Base, class IMPL>
  339. class Set_lock
  340. : public Base
  341. {
  342. using Operation = Base;
  343. public:
  344. /**
  345. Set a shared mode lock on any rows/documents that are read.
  346. Other sessions can read, but not modify locked rows/documents.
  347. */
  348. Operation&
  349. lockShared(LockContention contention= LockContention::DEFAULT)
  350. {
  351. get_impl()->set_lock_mode(common::Lock_mode::SHARED,
  352. common::Lock_contention((unsigned)contention));
  353. return *this;
  354. }
  355. /**
  356. Set an exclusive mode lock on any rows/documents that are read.
  357. Other sessions are blocked from modifying, locking, or reading the data
  358. in certain transaction isolation levels. The lock is released
  359. when the transaction is committed or rolled back.
  360. */
  361. Operation&
  362. lockExclusive(LockContention contention = LockContention::DEFAULT)
  363. {
  364. get_impl()->set_lock_mode(common::Lock_mode::EXCLUSIVE,
  365. common::Lock_contention((unsigned)contention));
  366. return *this;
  367. }
  368. protected:
  369. using Impl = IMPL;
  370. Impl* get_impl()
  371. {
  372. return static_cast<Impl*>(Base::get_impl());
  373. }
  374. };
  375. }} // mysqlx::internal
  376. #endif