Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. # cpphibernate
  2. A C++17 library to serialize and deserialize C++ objects to a MYSQL/MARIADB database.
  3. ## Getting Started
  4. ### Prerequisites
  5. Before you can use cpphibernate you need to download and install [the official mariadb C connector](https://downloads.mariadb.org/connector-c/)) and [the boost/hana library](https://github.com/boostorg/hana). And if you want to run the tests you additionally need [the google testing framework](https://github.com/google/googletest).
  6. [The cpputils libary](https://git.bergmann89.de/cpp/cpputils) and [the cppmariadb library](https://github.com/Bergmann89/cppmariadb) will be automatically downladed during the build.
  7. ### Simple Usage Example
  8. In this simple example we use a single and simple object, that is stored in the database. The create, update, read and destroy methods and the corresponding SQL queries are shown in the code below.
  9. ```cpp
  10. #include <memory>
  11. #include <iostream>
  12. #include <exception>
  13. #include <cpphibernate.h>
  14. #include <cpphibernate/driver/mariadb.h>
  15. /* define the class to hibernate */
  16. struct test_data
  17. {
  18. size_t id; //!< ID of the class instance (this field is mandatory for the hibernate engine)
  19. std::string str_data; //!< Add string data field
  20. ::cpphibernate::string<64> str64_data; //!< Add a special string data field with a mex length of 64
  21. uint32_t u32; //!< Add a normal integer data field
  22. std::unique_ptr<uint32_t> u32_ptr_u; //!< Add a nullable integer data field
  23. };
  24. /* create the database schema */
  25. constexpr decltype(auto) test_schema = cpphibernate_make_schema(
  26. test_schema, // this is the schema name
  27. cpphibernate_make_table_name(
  28. tbl_test_data, // this is the table name
  29. test_data, // this is the referenced class
  30. 1, // a unique id for the table
  31. cpphibernate_make_id (&test_data::id), // pointer to the ID member
  32. cpphibernate_make_field (test_data, str_data), // define a normal member field
  33. cpphibernate_make_field (test_data, str64_data), // [...]
  34. cpphibernate_make_field (test_data, u32), // [...]
  35. cpphibernate_make_field (test_data, u32_ptr_u), // [...]
  36. )
  37. );
  38. int main(int argc, char** argv)
  39. {
  40. try
  41. {
  42. using namespace ::cppmariadb;
  43. using namespace ::cpphibernate;
  44. /* establish connection to database */
  45. connection c = database::connect("localhost", 3306, "testuser", "password", "", client_flags::empty());
  46. /* create a hibernation context */
  47. auto context = make_context_ptr<mariadb_driver>(test_schema, c);
  48. /* initialize the database schema */
  49. context.init(); /* CREATE SCHEMA IF NOT EXISTS `test_schema` DEFAULT CHARACTER SET utf8;
  50. USE `test_schema`;
  51. CREATE TABLE IF NOT EXISTS `tbl_test_data`
  52. (
  53. `tbl_test_data_id` INT UNSIGNED NOT NULL,
  54. `str_data` VARCHAR(100) NOT NULL,
  55. `str64_data` VARCHAR(64) NOT NULL,
  56. `u32` INT UNSIGNED NOT NULL,
  57. `u32_ptr_u` INT UNSIGNED NULL DEFAULT NULL,
  58. PRIMARY KEY ( `tbl_test_data_id` ),
  59. UNIQUE INDEX `index_tbl_test_data_id` ( `tbl_test_data_id` ASC )
  60. )
  61. ENGINE = InnoDB
  62. DEFAULT CHARACTER SET = utf8; */
  63. /* create some test data */
  64. test_data data;
  65. data.str_data = "this is a simple string";
  66. data.str64_data = "this is a string with max 64 characters";
  67. data.u32 = 123;
  68. /* create a new dataset in the database:
  69. * the new IDs of the object are stored in the corresponding members */
  70. context.create(data); /* INSERT INTO
  71. `tbl_test_data`
  72. SET
  73. `str_data`='this is a simple string',
  74. `str64_data`='this is a string with max 64 characters',
  75. `u32`=123,
  76. `u32_ptr_u`=NULL; */
  77. /* change some data and update the database */
  78. t1.u32_ptr_u.reset(new uint32_t(456));
  79. context.update(data); /* UPDATE
  80. `tbl_test_data`
  81. SET
  82. `str_data`='this is a simple string',
  83. `str64_data`='this is a string with max 64 characters',
  84. `u32`=123,
  85. `u32_ptr_u`=456
  86. WHERE
  87. `tbl_test_data_id`=1; */
  88. /* read back the created object:
  89. * if no selector is passed here, the ID member of the object is used */
  90. context.read(data); /* SELECT "
  91. `tbl_test_data`.`tbl_test_data_id`),
  92. `tbl_test_data`.`str_data`,
  93. `tbl_test_data`.`str64_data`,
  94. `tbl_test_data`.`u32`,
  95. `tbl_test_data`.`u32_ptr_u`
  96. FROM
  97. `tbl_test_data`
  98. WHERE
  99. `tbl_test_data`.`tbl_test_data_id`=1; */
  100. /* delete the object from the database */
  101. context.destroy(data); /* DELETE
  102. `tbl_test_data`
  103. FROM
  104. `tbl_test_data`
  105. WHERE
  106. `tbl_test_data`.`tbl_test_data_id`=1; */
  107. return 0;
  108. }
  109. catch(const std::exception& ex)
  110. {
  111. std::cout << ex.what() << std::endl;
  112. }
  113. return 1
  114. }
  115. ```
  116. ### More Advanced Usage Example
  117. The more advanced example uses a more complex database schema, containing custom defined enum types, one to one and one to many correleation of different tables, a polymorphic class hierarchy with inheritance and some of the std containers like std::unique_ptr or std::vector.
  118. ```cpp
  119. #include <memory>
  120. #include <iostream>
  121. #include <exception>
  122. #include <cpphibernate.h>
  123. #include <cpphibernate/driver/mariadb.h>
  124. #include <cpputils/misc/enum.h>
  125. #include <cpputils/container/nullable.h>
  126. /* define a test enum */
  127. enum class test_enum
  128. {
  129. test0,
  130. test1,
  131. test2,
  132. test3,
  133. first = test0,
  134. last = test3,
  135. };
  136. /* define the enum to string mapping for the test enum */
  137. DEFINE_ENUM_TO_STRING_MAP(
  138. test_enum,
  139. { test_enum::test0, "test0" },
  140. { test_enum::test1, "test1" },
  141. { test_enum::test2, "test2" },
  142. { test_enum::test3, "test3" }
  143. );
  144. DEFINE_STRING_TO_ENUM_MAP(
  145. test_enum,
  146. invariant_string_less,
  147. { "test0", test_enum::test0 },
  148. { "test1", test_enum::test1 },
  149. { "test2", test_enum::test2 },
  150. { "test3", test_enum::test3 }
  151. );
  152. /* define some normal C++ structs/classes */
  153. struct test1
  154. {
  155. size_t id;
  156. std::string str_data;
  157. ::cpphibernate::string<64> str64_data;
  158. utl::nullable<uint32_t> u32_nullable;
  159. std::unique_ptr<uint32_t> u32_ptr_u;
  160. std::shared_ptr<uint32_t> u32_ptr_s;
  161. };
  162. struct test2
  163. {
  164. size_t id;
  165. uint8_t u8_data;
  166. int8_t i8_data;
  167. uint16_t u16_data;
  168. int16_t i16_data;
  169. };
  170. struct test3
  171. {
  172. size_t id;
  173. uint32_t u32_data;
  174. int32_t i32_data;
  175. uint64_t u64_data;
  176. int64_t i64_data;
  177. };
  178. struct base
  179. {
  180. ::cpphibernate::uuid id;
  181. std::string name;
  182. virtual ~base() = default;
  183. };
  184. struct derived1
  185. : public base
  186. {
  187. ::cpphibernate::uuid derived1_id;
  188. test1 test1_data;
  189. test_enum enum_data;
  190. };
  191. struct derived2
  192. : public base
  193. {
  194. ::cpphibernate::uuid derived2_id;
  195. utl::nullable<test2> test2_nullable;
  196. std::unique_ptr<test2> test2_ptr_u;
  197. std::shared_ptr<test2> test2_ptr_s;
  198. };
  199. struct derived3
  200. : public derived2
  201. {
  202. ::cpphibernate::uuid derived3_id;
  203. std::list<test3> test3_list;
  204. std::vector<test3> test3_vector;
  205. };
  206. /* create the database schema */
  207. constexpr decltype(auto) test_schema = cpphibernate_make_schema(
  208. test, // this is the schema name
  209. cpphibernate_make_table_name(
  210. tbl_test1, // this is the table name
  211. test1, // this is the referenced class
  212. 1, // a unique id for the table
  213. cpphibernate_make_id (&test1::id), // pointer to the ID member
  214. cpphibernate_make_field (test1, str_data), // define a normal member field
  215. cpphibernate_make_field (test1, str64_data), // [...]
  216. cpphibernate_make_field (test1, u32_nullable), // [...]
  217. cpphibernate_make_field (test1, u32_ptr_u), // [...]
  218. cpphibernate_make_field (test1, u32_ptr_s) // [...]
  219. ),
  220. cpphibernate_make_table_name(
  221. tbl_test2,
  222. test2,
  223. 2,
  224. cpphibernate_make_id (&test2::id),
  225. cpphibernate_make_field (test2, u8_data),
  226. cpphibernate_make_field (test2, i8_data),
  227. cpphibernate_make_field (test2, u16_data),
  228. cpphibernate_make_field (test2, i16_data)
  229. ),
  230. cpphibernate_make_table_name(
  231. tbl_test3,
  232. test3,
  233. 3,
  234. cpphibernate_make_id (&test3::id),
  235. cpphibernate_make_field (test3, u32_data),
  236. cpphibernate_make_field (test3, i32_data),
  237. cpphibernate_make_field (test3, u64_data),
  238. cpphibernate_make_field (test3, i64_data)
  239. ),
  240. cpphibernate_make_table_name(
  241. tbl_base,
  242. base,
  243. 10,
  244. cpphibernate_make_id (&base::id),
  245. cpphibernate_make_field (base, name)
  246. ),
  247. cpphibernate_make_table_name(
  248. tbl_derived1,
  249. derived1,
  250. 11,
  251. cpphibernate_make_id (&derived1::derived1_id),
  252. cpphibernate_make_field (derived1, test1_data),
  253. cpphibernate_make_field (derived1, enum_data)
  254. ),
  255. cpphibernate_make_table_name(
  256. tbl_derived2,
  257. derived2,
  258. 12,
  259. cpphibernate_make_id (&derived2::derived2_id),
  260. cpphibernate_make_field (derived2, test2_nullable),
  261. cpphibernate_make_field (derived2, test2_ptr_u),
  262. cpphibernate_make_field (derived2, test2_ptr_s)
  263. ),
  264. cpphibernate_make_table_name(
  265. tbl_derived3,
  266. derived3,
  267. 13,
  268. cpphibernate_make_id (&derived3::derived3_id),
  269. cpphibernate_make_field (derived3, test3_list),
  270. cpphibernate_make_field (derived3, test3_vector)
  271. )
  272. );
  273. int main(int argc, char** argv)
  274. {
  275. try
  276. {
  277. using namespace ::cppmariadb;
  278. using namespace ::cpphibernate;
  279. /* establish connection to database */
  280. connection c = database::connect("localhost", 3306, "testuser", "password", "", client_flags::empty());
  281. /* create a hibernation context */
  282. auto context = make_context_ptr<mariadb_driver>(test_schema, c);
  283. /* initialize the database schema */
  284. context.init();
  285. /* create some test data */
  286. derived3 d3;
  287. d3.name = "derived3";
  288. d3.test3_list.emplace_back();
  289. d3.test3_list.back().u32_data = 100;
  290. d3.test3_list.back().i32_data = 101;
  291. d3.test3_list.back().u64_data = 102;
  292. d3.test3_list.back().i64_data = 103;
  293. d3.test3_list.emplace_back();
  294. d3.test3_list.back().u32_data = 110;
  295. d3.test3_list.back().i32_data = 111;
  296. d3.test3_list.back().u64_data = 112;
  297. d3.test3_list.back().i64_data = 113;
  298. d3.test3_vector.emplace_back();
  299. d3.test3_vector.back().u32_data = 200;
  300. d3.test3_vector.back().i32_data = 201;
  301. d3.test3_vector.back().u64_data = 202;
  302. d3.test3_vector.back().i64_data = 203;
  303. d3.test3_vector.emplace_back();
  304. d3.test3_vector.back().u32_data = 210;
  305. d3.test3_vector.back().i32_data = 211;
  306. d3.test3_vector.back().u64_data = 212;
  307. d3.test3_vector.back().i64_data = 213;
  308. d3.test3_vector.emplace_back();
  309. d3.test3_vector.back().u32_data = 220;
  310. d3.test3_vector.back().i32_data = 221;
  311. d3.test3_vector.back().u64_data = 222;
  312. d3.test3_vector.back().i64_data = 223;
  313. /* create a new dataset in the database:
  314. * the new IDs of the object are stored in the corresponding members */
  315. context.create(d3);
  316. /* read back the created object:
  317. * if no selector is passed here, the ID member of the object is used */
  318. context.read(d3);
  319. /* if we pass a pointer to the read method, the suitable object is created automatically */
  320. using namespace ::boost::hana::literals;
  321. using namespace ::cpphibernate::modifier;
  322. using base_ptr_u = std::unique_ptr<base>;
  323. base_ptr_u b;
  324. constexpr decltype(auto) base_key_field = test_schema.tables[3_c].fields[0_c];
  325. context.read(b, where(equal(base_key_field, d3.id)));
  326. auto * d3_ptr = dynamic_cast<derived3*>(b.get());
  327. if (d3_ptr)
  328. {
  329. /* do something with the data */
  330. }
  331. /* this also works for containers of pointers */
  332. using base_vector = std::vector<base_ptr_u>;
  333. base_vector vec;
  334. context.read(vec);
  335. for (auto& ptr : vec)
  336. {
  337. /* do something with the data */
  338. }
  339. return 0;
  340. }
  341. catch(const std::exception& ex)
  342. {
  343. std::cout << ex.what() << std::endl;
  344. }
  345. return 1
  346. }
  347. ```
  348. ## License
  349. This project is licensed under the MIT License - see the [LICENSE.txt](LICENSE.txt) file for details