collection_crud.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  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_COLLECTION_CRUD_H
  31. #define MYSQLX_COLLECTION_CRUD_H
  32. /**
  33. @file
  34. Declarations for CRUD operations on document collections.
  35. Classes declared here represent CRUD operations on a document
  36. collection. An Object of a class such as CollectionAdd represents
  37. a "yet-to-be-executed" operation and stores all the parameters of the
  38. operation. The operation is sent to server for execution only when
  39. `execute()` method is called.
  40. The following classes for collection CRUD operations are defined:
  41. - CollectionAdd
  42. - CollectionRemove
  43. - CollectionFind
  44. - CollectionModify
  45. CRUD operation objects can be created directly, or assigned from
  46. result of DevAPI methods that create such operations:
  47. ~~~~~~
  48. CollectionAdd add_op(coll);
  49. CollectionFind find_op = coll.find(...).sort(...);
  50. ~~~~~~
  51. CRUD operation objects have methods which can modify the operation
  52. before it gets executed. For example `CollectionAdd::add()`
  53. appends a document to the list of documents that should be added
  54. by the given CollectionAdd operation. These methods can be chained
  55. as allowed by the fluent API grammar.
  56. @internal
  57. The order of fluent API calls is expressed by base classes, such as
  58. Collection_find_base, which are composed from CRUD templates defined
  59. in crud.h. The order of templates determines the allowed order of fluent
  60. API calls.
  61. */
  62. #include "common.h"
  63. #include "result.h"
  64. #include "executable.h"
  65. #include "crud.h"
  66. namespace mysqlx {
  67. class Session;
  68. class Collection;
  69. class Table;
  70. // ----------------------------------------------------------------------
  71. /*
  72. Adding documents to a collection
  73. ================================
  74. */
  75. class CollectionAdd;
  76. namespace internal {
  77. /*
  78. Note: using empty class instead of alias/typedef to help Doxygen correctly
  79. expand templates.
  80. */
  81. struct Collection_add_base
  82. : public Executable<Result, CollectionAdd>
  83. {};
  84. }
  85. /**
  86. An operation which adds documents to a collection.
  87. Documents to be added by this operation are specified with various variants
  88. of `add()` method.
  89. Each document must have a unique identifier which is stored in `_id`
  90. field of the document. Document identifiers are character strings no longer
  91. than 32 characters. If added document does not have `_id` field, a unique
  92. identifier is generated for it. Document identifier generated by a given
  93. collection add operation can be examined using `Result::getDocumentIds()`
  94. method. Generated document identifiers are strings of 32 hexadecimal digits,
  95. like this one `0512020981044082E6119DFA0E4C0584`.
  96. @note Generated document identifiers are based on UUIDs but they are not
  97. valid UUIDs (fields are reversed).
  98. @ingroup devapi_op
  99. @internal
  100. The various `add()` methods are implemented in terms of `do_add()` method
  101. defined by Collection_add_detail class. This method passes documents to
  102. the internal implementation object.
  103. */
  104. class CollectionAdd
  105. : public internal::Collection_add_base
  106. , internal::Collection_add_detail
  107. {
  108. public:
  109. /**
  110. Create an empty add operation for the given collection.
  111. */
  112. CollectionAdd(Collection &coll)
  113. {
  114. try {
  115. reset(internal::Crud_factory::mk_add(coll));
  116. }
  117. CATCH_AND_WRAP
  118. }
  119. CollectionAdd(const internal::Collection_add_base &other)
  120. {
  121. internal::Collection_add_base::operator=(other);
  122. }
  123. CollectionAdd(internal::Collection_add_base &&other)
  124. {
  125. internal::Collection_add_base::operator=(std::move(other));
  126. }
  127. /**
  128. Add all documents from a range defined by two iterators.
  129. */
  130. template <typename It>
  131. CollectionAdd& add(const It &begin, const It &end)
  132. {
  133. try {
  134. do_add(get_impl(), begin, end);
  135. return *this;
  136. }
  137. CATCH_AND_WRAP
  138. }
  139. /**
  140. Add all documents within given container.
  141. Any container type for which `std::begin()`/`std::end()` are defined
  142. should work.
  143. */
  144. template <class Container>
  145. CollectionAdd& add(const Container &c)
  146. {
  147. try {
  148. do_add(get_impl(), c);
  149. return *this;
  150. }
  151. CATCH_AND_WRAP
  152. }
  153. /**
  154. Add document(s) to a collection.
  155. Documents can be described by JSON strings or DbDoc objects.
  156. */
  157. template <typename... Types>
  158. CollectionAdd& add(const Types&... docs)
  159. {
  160. try {
  161. do_add(get_impl(), docs...);
  162. return *this;
  163. }
  164. CATCH_AND_WRAP
  165. }
  166. protected:
  167. using Impl = common::Collection_add_if;
  168. Impl* get_impl()
  169. {
  170. return static_cast<Impl*>(internal::Collection_add_base::get_impl());
  171. }
  172. };
  173. // ----------------------------------------------------------------------
  174. /*
  175. Removing documents from a collection
  176. ====================================
  177. */
  178. class CollectionRemove;
  179. namespace internal {
  180. struct Collection_remove_cmd
  181. : public Executable<Result,CollectionRemove>
  182. {};
  183. struct Collection_remove_base
  184. : public Sort< Limit< Bind_parameters< Collection_remove_cmd > > >
  185. {};
  186. } // internal namespace
  187. /**
  188. An operation which removes documents from a collection.
  189. @ingroup devapi_op
  190. @internal
  191. Note: All methods that modify remove operation are defined by the base
  192. class.
  193. */
  194. class CollectionRemove
  195. : public internal::Collection_remove_base
  196. {
  197. public:
  198. /**
  199. Create an operation which removes selected documnets from the given
  200. collection.
  201. Documents to be removed are specified by the given Boolean expression.
  202. */
  203. CollectionRemove(Collection &coll, const string &expr)
  204. {
  205. try {
  206. reset(internal::Crud_factory::mk_remove(coll, expr));
  207. }
  208. CATCH_AND_WRAP
  209. }
  210. CollectionRemove(const internal::Collection_remove_cmd &other)
  211. {
  212. internal::Collection_remove_cmd::operator=(other);
  213. }
  214. CollectionRemove(internal::Collection_remove_cmd &&other)
  215. {
  216. internal::Collection_remove_cmd::operator=(std::move(other));
  217. }
  218. };
  219. // ----------------------------------------------------------------------
  220. /*
  221. Searching for documents in a collection
  222. =======================================
  223. */
  224. class CollectionFind;
  225. namespace internal {
  226. struct Collection_find_cmd
  227. : public Executable<DocResult, CollectionFind>
  228. {};
  229. struct Collection_find_base
  230. : public Group_by< Having< Sort< Limit< Offset< Bind_parameters<
  231. Set_lock< Collection_find_cmd, common::Collection_find_if >
  232. > > > > > >
  233. {};
  234. } // internal namespace
  235. /**
  236. An operation which returns all or selected documents from a collection.
  237. @ingroup devapi_op
  238. */
  239. class CollectionFind
  240. : public internal::Collection_find_base
  241. , internal::Collection_find_detail
  242. {
  243. using Operation = internal::Collection_find_base;
  244. public:
  245. /**
  246. Create an operation which returns all documents from the given collection.
  247. */
  248. CollectionFind(Collection &coll)
  249. {
  250. try {
  251. reset(internal::Crud_factory::mk_find(coll));
  252. }
  253. CATCH_AND_WRAP
  254. }
  255. /**
  256. Create an operation which returns selected documents from the given
  257. collection.
  258. Documents to be returned are specified by the given Boolean expression.
  259. */
  260. CollectionFind(Collection &coll, const string &expr)
  261. {
  262. try {
  263. reset(internal::Crud_factory::mk_find(coll, expr));
  264. }
  265. CATCH_AND_WRAP
  266. }
  267. CollectionFind(const internal::Collection_find_cmd &other)
  268. {
  269. internal::Collection_find_cmd::operator=(other);
  270. }
  271. CollectionFind(internal::Collection_find_cmd &&other)
  272. {
  273. internal::Collection_find_cmd::operator=(std::move(other));
  274. }
  275. public:
  276. /**
  277. Specify a projection for the documents returned by this operation.
  278. Projection is either a single document expression given by `expr(<string>)`
  279. or a list (or collection) of strings of the form
  280. `"<expression> AS <path>"`. In the latter case each `<expression>`
  281. is evaluated and `<path>` specifies where to put the value of
  282. the expression in the resulting document.
  283. */
  284. template <typename... Expr>
  285. Operation& fields(Expr... proj)
  286. {
  287. try {
  288. do_fields(get_impl(), proj...);
  289. return *this;
  290. }
  291. CATCH_AND_WRAP
  292. }
  293. protected:
  294. using Impl = common::Collection_find_if;
  295. Impl* get_impl()
  296. {
  297. return static_cast<Impl*>(internal::Collection_find_base::get_impl());
  298. }
  299. };
  300. // ----------------------------------------------------------------------
  301. /*
  302. Modifying documents in a collection
  303. ===================================
  304. */
  305. class CollectionModify;
  306. namespace internal {
  307. class CollectionReplace;
  308. struct Collection_modify_cmd
  309. : public Executable<Result, CollectionModify>
  310. {};
  311. struct Collection_modify_base
  312. : public Sort< Limit< Bind_parameters< Collection_modify_cmd > > >
  313. {};
  314. } // internal namespace
  315. /**
  316. An operation which modifies all or selected documents in a collection.
  317. @ingroup devapi_op
  318. */
  319. class CollectionModify
  320. : public internal::Collection_modify_base
  321. {
  322. public:
  323. /**
  324. Create an operation which modifies selected documents in the given
  325. collection.
  326. Documents to be modified are specified by the given Boolean expression.
  327. */
  328. CollectionModify(Collection &coll, const string &expr)
  329. {
  330. try {
  331. reset(internal::Crud_factory::mk_modify(coll, expr));
  332. }
  333. CATCH_AND_WRAP
  334. }
  335. CollectionModify(const internal::Collection_modify_cmd &other)
  336. {
  337. internal::Collection_modify_cmd::operator=(other);
  338. }
  339. CollectionModify(internal::Collection_modify_cmd &&other)
  340. {
  341. internal::Collection_modify_cmd::operator=(std::move(other));
  342. }
  343. /**
  344. Set the given field in a document to the given value.
  345. The field is given by a document path. The value can be either a direct
  346. literal or an expression given as `expr(<string>)`, to be evaluated on
  347. the server.
  348. */
  349. CollectionModify& set(const Field &field, const Value &val)
  350. {
  351. try {
  352. get_impl()->add_operation(
  353. Impl::SET, std::wstring(field), (const common::Value&)val
  354. );
  355. return *this;
  356. }
  357. CATCH_AND_WRAP
  358. }
  359. /**
  360. Remove the given field from a document.
  361. The field is given by a document path.
  362. */
  363. CollectionModify& unset(const Field &field)
  364. {
  365. try {
  366. get_impl()->add_operation(Impl::UNSET, std::wstring(field));
  367. return *this;
  368. }
  369. CATCH_AND_WRAP
  370. }
  371. /**
  372. Insert a value into an array field of a document.
  373. The `field` parameter should be a document path pointing at a location
  374. inside an array field. The given value is inserted at this position.
  375. */
  376. CollectionModify& arrayInsert(const Field &field, const Value &val)
  377. {
  378. try {
  379. get_impl()->add_operation(
  380. Impl::ARRAY_INSERT,
  381. std::wstring(field),
  382. (const common::Value&)val
  383. );
  384. return *this;
  385. }
  386. CATCH_AND_WRAP
  387. }
  388. /**
  389. Append a value to an array field of a document.
  390. The `field` parameter should be a document path pointing at an array
  391. field inside the document. The given value is appended at the end of the
  392. array.
  393. */
  394. CollectionModify& arrayAppend(const Field &field, const Value &val)
  395. {
  396. try {
  397. get_impl()->add_operation(
  398. Impl::ARRAY_APPEND,
  399. std::wstring(field),
  400. (const common::Value&)val
  401. );
  402. return *this;
  403. }
  404. CATCH_AND_WRAP
  405. }
  406. /**
  407. Apply JSON Patch to a target JSON document.
  408. The JSON Patch format is defined by
  409. <a href=https://tools.ietf.org/html/rfc7386>RFC7386</a>.
  410. A document patch is similar to a JSON object, with the key difference that
  411. document field values can be nested expressions in addition to literal
  412. values.
  413. The patch contains instructions of how the source document is to be modified
  414. producing a derived document. By default, all fields from the source
  415. document are copied to the resulting document. If patch sets a field to NULL,
  416. the field of that name in the source is skipped from the result, identifiers
  417. and function calls are evaluated against the original source document.
  418. */
  419. CollectionModify& patch(const string &val)
  420. {
  421. try {
  422. get_impl()->add_operation(
  423. Impl::MERGE_PATCH, L"$", (const common::Value&)expr(val)
  424. );
  425. return *this;
  426. }
  427. CATCH_AND_WRAP
  428. }
  429. protected:
  430. using Impl = common::Collection_modify_if;
  431. Impl* get_impl()
  432. {
  433. return static_cast<Impl*>(internal::Collection_modify_base::get_impl());
  434. }
  435. };
  436. } // mysqlx namespace
  437. #endif