You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

365 lines
14 KiB

  1. #pragma once
  2. #include "read_context.h"
  3. #include "data_context.inl"
  4. #include "../helper/nullable_helper.inl"
  5. #include "../helper/container_helper.inl"
  6. namespace cpphibernate {
  7. namespace mariadb {
  8. read_context::read_context(
  9. const schema_t& p_schema,
  10. ::cppmariadb::connection& p_connection,
  11. const filter_t& p_filter,
  12. size_t p_real_dataset_id)
  13. : data_context (p_schema, p_connection)
  14. , filter (p_filter)
  15. , real_dataset_id (p_real_dataset_id)
  16. , is_dynamic (false)
  17. { }
  18. template<typename T_dataset>
  19. T_dataset& read_context::emplace(const table_t * table) const
  20. {
  21. using dataset_type = mp::decay_t<T_dataset>;
  22. /* check table */
  23. auto dataset_id = get_type_id(hana::type_c<dataset_type>);
  24. if (!table)
  25. table = &schema.table(dataset_id);
  26. else if (table->dataset_id != dataset_id)
  27. throw exception("wrong table passed!");
  28. /* check base */
  29. auto tbl = table;
  30. while (tbl && tbl->dataset_id != real_dataset_id)
  31. tbl = tbl->base_table;
  32. if (!tbl)
  33. {
  34. throw exception(cppcore::type_helper<dataset_type>::name() +
  35. " is not a derived type of dataset with id " + std::to_string(real_dataset_id));
  36. }
  37. /* create dataset */
  38. auto ptr = std::make_unique<dataset_type>();
  39. auto data = emplace_intern(ptr.get(), dataset_id);
  40. if (!data)
  41. throw exception("unable to store created dataset in context!");
  42. ptr.release();
  43. return *static_cast<dataset_type*>(data);
  44. }
  45. void read_context::emplace() const
  46. { emplace_intern(nullptr, 0); }
  47. void read_context::finish() const
  48. { finish_intern(); }
  49. namespace __impl
  50. {
  51. /* read_context_builder */
  52. template<typename X, typename>
  53. struct read_context_builder
  54. {
  55. template<typename... T_args>
  56. static constexpr decltype(auto) apply(T_args&&... args)
  57. { static_assert(sizeof...(args) == -1, "Invalid parameters for make_read_context(...)!"); }
  58. };
  59. /* read_context_builder - fake */
  60. template<
  61. typename T_schema,
  62. typename T_connection,
  63. typename T_dataset,
  64. typename T_filter>
  65. struct read_context_builder<
  66. mp::list<T_schema, T_connection, T_dataset, T_filter>,
  67. mp::enable_if_t<
  68. mp::is_same_v<hana::type_tag, hana::tag_of_t<mp::decay_t<T_dataset>>>
  69. >>
  70. {
  71. using dataset_type = typename mp::decay_t<T_dataset>::type;
  72. struct context_impl
  73. : public read_context
  74. {
  75. public:
  76. inline context_impl(
  77. const schema_t& p_schema,
  78. ::cppmariadb::connection& p_connection,
  79. T_dataset& p_dataset,
  80. const filter_t& p_filter)
  81. : read_context (p_schema, p_connection, p_filter,
  82. get_type_id(hana::type_c<real_dataset_t<mp::decay_t<dataset_type>>>))
  83. { }
  84. private:
  85. void * emplace_intern(void* data, size_t dataset_id) const override
  86. { return nullptr; }
  87. void finish_intern() const override
  88. { clear(); }
  89. };
  90. template<typename... X_args>
  91. static constexpr decltype(auto) apply(X_args&&... args)
  92. { return context_impl(std::forward<X_args>(args)...); }
  93. };
  94. /* read_context_builder - normal types */
  95. template<
  96. typename T_schema,
  97. typename T_connection,
  98. typename T_dataset,
  99. typename T_filter>
  100. struct read_context_builder<
  101. mp::list<T_schema, T_connection, T_dataset, T_filter>,
  102. mp::enable_if_t<
  103. !is_container_v<mp::decay_t<T_dataset>>
  104. && !is_nullable_v<mp::decay_t<T_dataset>>
  105. && !mp::is_same_v<hana::type_tag, hana::tag_of_t<mp::decay_t<T_dataset>>>
  106. >>
  107. {
  108. using dataset_type = mp::decay_t<T_dataset>;
  109. struct context_impl
  110. : public read_context
  111. {
  112. private:
  113. mutable size_t _count;
  114. dataset_type& _dataset;
  115. public:
  116. inline context_impl(
  117. const schema_t& p_schema,
  118. ::cppmariadb::connection& p_connection,
  119. T_dataset& p_dataset,
  120. const filter_t& p_filter)
  121. : read_context (p_schema, p_connection, p_filter,
  122. get_type_id(hana::type_c<real_dataset_t<mp::decay_t<T_dataset>>>))
  123. , _count (0)
  124. , _dataset (p_dataset)
  125. { }
  126. private:
  127. void * emplace_intern(void* data, size_t dataset_id) const override
  128. {
  129. if (data || dataset_id != 0)
  130. throw exception("Static datasets can not be assigned!");
  131. ++_count;
  132. if (_count > 1)
  133. throw exception("Expected exactly one dataset, but received more!");
  134. return set(_dataset);
  135. }
  136. void finish_intern() const override
  137. {
  138. if (_count < 1)
  139. throw exception("Expected exactly one dataset, but received none!");
  140. clear();
  141. }
  142. };
  143. template<typename... X_args>
  144. static constexpr decltype(auto) apply(X_args&&... args)
  145. { return context_impl(std::forward<X_args>(args)...); }
  146. };
  147. /* read_context_builder - nullable */
  148. template<
  149. typename T_schema,
  150. typename T_connection,
  151. typename T_dataset,
  152. typename T_filter>
  153. struct read_context_builder<
  154. mp::list<T_schema, T_connection, T_dataset, T_filter>,
  155. mp::enable_if_t<
  156. !is_container_v<mp::decay_t<T_dataset>>
  157. && is_nullable_v<mp::decay_t<T_dataset>>
  158. >>
  159. {
  160. using dataset_type = mp::decay_t<T_dataset>;
  161. using nullable_helper_type = nullable_helper<dataset_type>;
  162. using value_type = typename nullable_helper_type::value_type;
  163. struct context_impl
  164. : public read_context
  165. {
  166. private:
  167. dataset_type& _dataset;
  168. mutable size_t _count;
  169. public:
  170. inline context_impl(
  171. const schema_t& p_schema,
  172. ::cppmariadb::connection& p_connection,
  173. T_dataset& p_dataset,
  174. const filter_t& p_filter)
  175. : read_context (p_schema, p_connection, p_filter,
  176. get_type_id(hana::type_c<real_dataset_t<mp::decay_t<T_dataset>>>))
  177. , _count (0)
  178. , _dataset (p_dataset)
  179. {
  180. is_dynamic = is_pointer_v<dataset_type>;
  181. nullable_helper_type::clear(_dataset);
  182. }
  183. private:
  184. void * emplace_intern(void * data, size_t dataset_id) const override
  185. {
  186. if (data && !is_pointer_v<dataset_type>)
  187. throw exception("None pointer type can not be assigned!");
  188. ++_count;
  189. if (_count > 1)
  190. throw exception("Expected exactly one dataset, but received more!");
  191. if (data)
  192. {
  193. auto* cast = static_cast<value_type*>(data);
  194. auto& value = nullable_helper_type::set(_dataset, cast);
  195. if (cast != &value)
  196. throw exception("Nullable pointer value has changed!");
  197. return set(value, dataset_id);
  198. }
  199. else
  200. {
  201. auto& value = nullable_helper_type::set(_dataset, value_type { });
  202. return set(value);
  203. }
  204. }
  205. void finish_intern() const override
  206. { clear(); }
  207. };
  208. template<typename... X_args>
  209. static constexpr decltype(auto) apply(X_args&&... args)
  210. { return context_impl(std::forward<X_args>(args)...); }
  211. };
  212. /* container_emplace_helper */
  213. template<typename T_dataset, typename = void>
  214. struct container_emplace_helper;
  215. template<typename T_dataset>
  216. struct container_emplace_helper<
  217. T_dataset,
  218. mp::enable_if_t<
  219. mp::is_valid_v<typename container_helper<T_dataset>::value_type>
  220. && !is_pointer_v<typename container_helper<T_dataset>::value_type>
  221. >>
  222. {
  223. static inline decltype(auto) emplace(T_dataset& dataset, void * data, size_t& data_id)
  224. {
  225. using container_helper_type = container_helper<T_dataset>;
  226. using value_type = typename container_helper_type::value_type;
  227. if (data || data_id != 0)
  228. throw exception("Static datasets can not be assigned!");
  229. auto& value = container_helper_type::emplace(dataset);
  230. data_id = get_type_id(hana::type_c<value_type>);
  231. return value;
  232. }
  233. };
  234. template<typename T_dataset>
  235. struct container_emplace_helper<
  236. T_dataset,
  237. mp::enable_if_t<
  238. mp::is_valid_v<typename container_helper<T_dataset>::value_type>
  239. && is_pointer_v<typename container_helper<T_dataset>::value_type>
  240. >>
  241. {
  242. static inline decltype(auto) emplace(T_dataset& dataset, void * data, size_t& data_id)
  243. {
  244. using container_helper_type = container_helper<T_dataset>;
  245. using nullable_type = typename container_helper_type::value_type;
  246. using nullable_helper_type = nullable_helper<nullable_type>;
  247. using inner_value_type = typename nullable_helper_type::value_type;
  248. if (!data)
  249. throw exception("Expected dynamic data for pointer type!");
  250. if (data_id == 0)
  251. throw exception("Expected dataset id for pointer type!");
  252. if (!is_pointer_v<nullable_type>)
  253. throw exception("None pointer type can not be assigned!");
  254. auto& nullable = container_helper_type::emplace(dataset);
  255. auto* cast = static_cast<inner_value_type*>(data);
  256. auto& value = nullable_helper_type::set(nullable, cast);
  257. if (cast != &value)
  258. throw exception("Nullable pointer value has changed!");
  259. return value;
  260. }
  261. };
  262. /* read_context_builder - container */
  263. template<
  264. typename T_schema,
  265. typename T_connection,
  266. typename T_dataset,
  267. typename T_filter>
  268. struct read_context_builder<
  269. mp::list<T_schema, T_connection, T_dataset, T_filter>,
  270. mp::enable_if_t<
  271. is_container_v<mp::decay_t<T_dataset>>
  272. && !is_nullable_v<mp::decay_t<T_dataset>>
  273. >>
  274. {
  275. using dataset_type = mp::decay_t<T_dataset>;
  276. using real_dataset_type = real_dataset_t<dataset_type>;
  277. using container_helper_type = container_helper<dataset_type>;
  278. using value_type = typename container_helper_type::value_type;
  279. using emplace_helper_type = container_emplace_helper<dataset_type>;
  280. struct context_impl
  281. : public read_context
  282. {
  283. private:
  284. dataset_type& _dataset;
  285. public:
  286. inline context_impl(
  287. const schema_t& p_schema,
  288. ::cppmariadb::connection& p_connection,
  289. T_dataset& p_dataset,
  290. const filter_t& p_filter)
  291. : read_context (p_schema, p_connection, p_filter,
  292. get_type_id(hana::type_c<real_dataset_t<mp::decay_t<T_dataset>>>))
  293. , _dataset (p_dataset)
  294. {
  295. is_dynamic = is_pointer_v<value_type>;
  296. container_helper_type::clear(_dataset);
  297. }
  298. private:
  299. void * emplace_intern(void * data, size_t dataset_id) const override
  300. {
  301. auto& value = emplace_helper_type::emplace(_dataset, data, dataset_id);
  302. return set(value, dataset_id);
  303. }
  304. void finish_intern() const override
  305. { clear(); }
  306. };
  307. template<typename... X_args>
  308. static constexpr decltype(auto) apply(X_args&&... args)
  309. { return context_impl(std::forward<X_args>(args)...); }
  310. };
  311. }
  312. } }