HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_ORMQuerySet.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: UT_ORMQuerySet.h
7  *
8  * COMMENTS:
9  *
10  * The UT_ORMQuerySet is a powerful object that lets the developer create
11  * complex sql queries without having to worry about any of the underlying
12  * sql.
13  *
14  * The provided model meta object is the model the query set acts on.
15  * Joining two tables occurs when the query set notices a foreign
16  * relationship based on the provided filter(s). For example, if there
17  * was a User model with m2m relationships to a Group model and that
18  * Group model has a m2m relationship to a Permission model. If the
19  * filter was was Permission.filter({"group__in", user_groups}) then the
20  * query set would recognize there is a foreign relationship between
21  * groups and permissions and a inner join would be required.
22  *
23  * Generally speaking most queries can be performed through the object
24  * as this will aditionally update and flags and signals registered.
25  *
26  * See UT_SQLORM for an explanation on the ORM system.
27  *
28  * Example:
29  * * UT_ORMQuerySet(User).filter({"username"_f="myuser"}).get() will
30  * return a user with username "myuser".
31  * * UT_ORMQuerySet(Session).filter({"expiry__lt"_f=123}).get() will
32  * return any session with an expiry less than 123.
33  * * UT_ORMQuerySet(User).filter({UT::orm::FilterArg("email", School::metaInfo().primaryKey(), &school)}).get()
34  * returns any user with email equal to the schools pk (email in this example).
35  *
36  * Currently supported operators
37  * - `eq` (==)
38  * - `gt` (>)
39  * - `gte` (>=)
40  * - `lt` (<)
41  * - `lte` (<=)
42  * - `in` (IN): means the left must be in the provided list.
43  */
44 
45 #ifndef __UT_ORMQUERYSET_H__
46 #define __UT_ORMQUERYSET_H__
47 
48 #include "UT_API.h"
49 
50 #include "UT_ORMError.h"
51 #include "UT_SharedPtr.h"
52 #include "UT_StringSet.h"
53 #include "UT_ErrorCode.h"
54 #include "UT_SQL.h"
55 #include "UT_StringArray.h"
56 #include "UT_ORMField.h"
57 
58 class UT_ORMQuerySet;
59 class UT_SqlOrm;
60 class UT_ORMModelMeta;
61 
62 namespace UT::detail
63 {
64 template <typename T>
66 {
67  static bool const value = false;
68 };
69 template <typename T>
71 {
72  static bool const value = true;
73 };
74 template <>
76 {
77  static bool const value = true;
78 };
79 template <>
81 {
82  static bool const value = true;
83 };
84 };
85 
86 class ut_QueryOperationInfo;
87 
88 namespace UT::orm
89 {
90 template <typename... Ts>
91 struct overloads : Ts...
92 {
93  using Ts::operator()...;
94 };
95 template <typename... Ts>
96 overloads(Ts...) -> overloads<Ts...>;
97 
99 {
100  struct Column
101  {
102  Column(const UT_ORMFieldColumn* field, const void* obj) :
103  myField(field), myObject(obj)
104  {}
105 
106  const UT_ORMFieldColumn* myField;
107  const void* myObject = nullptr;
108  };
109  class ArgArray : public UT_IntrusiveRefCounter<
110  ArgArray,
111  std::default_delete<ArgArray>,
112  UT_IntrusiveNonThreadSafeCounterPolicy>
113  {
114  public:
115  virtual ~ArgArray() = default;
116  ArgArray(const ArgArray&) = default;
117  ArgArray& operator=(const ArgArray&) = default;
118  virtual void bind(UT_SqlStatement& stmt, int& bind_index) const = 0;
119  virtual exint size() const = 0;
120  protected:
121  ArgArray() = default;
122  };
123  template <typename T>
124  class ArgArrayHolder final : public ArgArray
125  {
126  public:
127  ArgArrayHolder(const T& objs) : myObjs(objs) {}
128  void bind(UT_SqlStatement& stmt, int& bind_index) const override
129  {
130  for (auto&& obj : myObjs)
131  {
132  stmt.bind(bind_index, obj);
133  bind_index++;
134  if (stmt.getError())
135  break;
136  }
137  }
138  exint size() const override { return myObjs.size(); }
139 
140  private:
141  T myObjs;
142  };
143  template <typename T>
144  class ArgArrayMemberHolder final : public ArgArray
145  {
146  public:
147  ArgArrayMemberHolder(
148  const T& objs,
149  const UT_ORMFieldColumn* field = nullptr)
150  : myObjs(objs), myField(field)
151  {
152  }
153  void bind(UT_SqlStatement& stmt, int& bind_index) const override
154  {
155  for (int i = 0; i < myObjs.size(); i++)
156  {
157  UT_ErrorCode ec;
158  myField->adapter()->bind(&myObjs[i], stmt, bind_index, ec);
159  bind_index++;
160 
161  if (stmt.getError())
162  break;
163  }
164  }
165  exint size() const override { return myObjs.size(); }
166 
167  private:
168  const UT_ORMFieldColumn* myField = nullptr;
169  T myObjs;
170  };
171 
172 public:
173  template <
174  typename T,
175  typename = typename std::enable_if_t<
177  FilterArg(const UT_StringHolder& name, T&& arg) : myName(name), myArg(arg)
178  {
179  }
180  FilterArg(const UT_StringHolder& name, const char* arg) :
181  myName(name), myArg(UT_StringHolder(arg))
182  {
183  }
185  const UT_StringHolder& name,
186  const UT_ORMFieldColumn* field,
187  const void* obj)
188  : myName(name), myArg(Column(field, obj))
189  {
190  }
191  template <
192  typename T,
193  typename = typename std::enable_if_t<
195  FilterArg(const UT_StringHolder& name, const T& objs)
196  : myName(name), myArg(UTmakeIntrusive<ArgArrayHolder<T>>(objs))
197  {
198  }
199  template <
200  typename T,
201  typename = typename std::enable_if_t<
204  const UT_StringHolder& name,
205  const UT_ORMFieldColumn* field,
206  const T& objs)
207  : myName(name)
208  , myArg(UTmakeIntrusive<ArgArrayMemberHolder<T>>(objs, field))
209  {
210  }
211 
212  const UT_StringHolder& name() const { return myName; }
213 
214  void bind(UT_SqlStatement& stmt, int& bind_index) const
215  {
216  const auto visitor = overloads{
217  [&](const Column& col)
218  {
219  UT_ErrorCode ec;
220  col.myField->adapter()->bind(
221  col.myObject, stmt, bind_index, ec);
222  bind_index++;
223  },
224  [&](const UT_IntrusivePtr<ArgArray>& arg)
225  {
226  arg->bind(stmt, bind_index);
227  },
228  [&](auto&& arg)
229  {
230  using T = std::decay_t<decltype(arg)>;
231  stmt.bind(bind_index, std::get<T>(myArg));
232  bind_index++;
233  }};
234  std::visit(visitor, myArg);
235  }
236 
237  void sqlParam(UT_WorkBuffer& wbuf) const
238  {
239  const auto visitor = overloads
240  {
241  [&](const UT_IntrusivePtr<ArgArray>& arg)
242  {
243  for (int i = 0; i < arg->size(); i++)
244  {
245  if (i != 0)
246  wbuf.append(',');
247  wbuf.append('?');
248  }
249  },
250  [&](auto&& arg)
251  {
252  wbuf.append('?');
253  }
254  };
255  std::visit(visitor, myArg);
256  }
257 
258 private:
259  UT_StringHolder myName;
260  std::variant<
261  int32,
262  int64,
263  bool,
265  Column,
267  myArg;
268 };
269 
271 {
272 public:
273  UdlArgValue(const UT_StringHolder& str) : myStr(str) {}
274 
275  template <typename T>
277  {
278  return FilterArg(myStr, std::forward<T>(value));
279  }
280 
281 private:
282  UT_StringHolder myStr;
283 };
284 }; // namespace UT::orm
285 
286 namespace UT
287 {
288 inline namespace Literal
289 {
291  const char* s,
292  const std::size_t len)
293 {
294  return UT::orm::UdlArgValue(UT_StringHolder(s, len));
295 }
296 } // namespace Literal
297 } // namespace UT
298 
299 
300 
302 {
303 public:
305  {
306  public:
308  using iterator_category = std::forward_iterator_tag;
310  using pointer = value_type*;
312 
314  {
315  if (myResult)
316  {
317  myResult->next();
318  if (isDone())
319  myResult = nullptr;
320  }
321  return *this;
322  }
323 
324  bool operator==(const iterator& rhs) const
325  {
326  if (myResult != nullptr && rhs.myResult != nullptr)
327  return myResult->myStmt.isImplEqual(rhs->myStmt);
328  else if (myResult == nullptr && rhs.myResult == nullptr)
329  return true;
330  return false;
331  }
332  bool operator!=(const iterator& rhs) const
333  {
334  return !(*this == rhs);
335  }
337  return *myResult;
338  }
340  {
341  return *myResult;
342  }
344  {
345  return myResult;
346  }
348  {
349  return myResult;
350  }
351  bool isDone() const
352  {
353  return myResult == nullptr || !myResult->hasResults()
354  || myResult->getError();
355  }
356 
357  private:
358  friend class UT_ORMQuerySetResult;
359 
360  iterator(UT_ORMQuerySetResult* result = nullptr) :
361  myResult(result)
362  {}
363 
364  UT_ORMQuerySetResult* myResult = nullptr;
365  };
366 
368  {
369  if (hasResults())
370  return iterator(this);
371  return end();
372  }
374  {
375  return iterator();
376  }
377  const iterator begin() const
378  {
379  if (hasResults())
380  return iterator(SYSconst_cast(this));
381  return end();
382  }
383  const iterator end() const
384  {
385  return iterator();
386  }
387  const iterator cbegin() const
388  {
389  return begin();
390  }
391  const iterator cend() const
392  {
393  return end();
394  }
395 
396  const UT_ErrorCode& getError() const;
397  void next();
398  bool hasResults() const;
399 
400  template <typename... Args>
401  std::tuple<Args...> fetchOne(UT_ErrorCode* ec = nullptr)
402  {
403  return myStmt.fetchOne<Args...>(ec);
404  }
405  template <typename... Args>
406  UT_Array<std::tuple<Args...>> fetchAll(UT_ErrorCode* ec = nullptr)
407  {
408  return myStmt.fetchAll<Args...>(ec);
409  }
410  template <typename T>
412  {
413  return myStmt.fetchAllFlat<T>(ec);
414  }
415  template <typename... Args>
416  std::tuple<Args...> as(UT_ErrorCode* ec = nullptr)
417  {
418  return myStmt.as<Args...>(ec);
419  }
420  template <typename T>
421  bool load(T& obj, UT_ErrorCode& ec)
422  {
423  return obj.meta().loadObject(obj, myStmt, ec);
424  }
425 
426  UT_SqlStatement& stmt() { return myStmt; }
427 protected:
428  friend class UT_ORMQuerySet;
429 
432  const UT_ErrorCode& ec)
433  : myStmt(impl), myError(ec)
434  {
435  }
436 
439 };
440 
442 {
443 public:
444  UT_ORMQuerySet(const UT_ORMModelMeta& meta);
445  ~UT_ORMQuerySet() = default;
446 
447  UT_ORMQuerySet(const UT_ORMQuerySet&) = default;
448  UT_ORMQuerySet& operator=(const UT_ORMQuerySet&) = default;
449 
452  const std::initializer_list<UT::orm::FilterArg>& args);
454  UT_ORMQuerySetResult get();
455  UT_ORMQuerySetResult get(const UT_ORMFieldColumn& field, void* obj);
456  UT_ORMQuerySetResult remove();
457  UT_ORMQuerySetResult update(
458  const std::initializer_list<UT::orm::FilterArg>& args);
460  bool exists(UT_ErrorCode& ec);
461 
462  UT_ORMQuerySetResult create(
463  const std::initializer_list<UT::orm::FilterArg>& args,
464  bool ignore_conflicts = false,
465  bool no_return = false);
466 
468  const std::initializer_list<UT_StringHolder>& col_names)
469  {
470  myReturningValues.clear();
471  for (auto&& name : col_names)
472  {
473  myReturningValues.emplace_back(name);
474  }
475  return UT_ORMQuerySet(*this);
476  }
477 
478  UT_ORMQuerySet limit(int limit);
479 
481 
483 
485 
486  UT_ORMQuerySet orderBy(const UT_StringHolder& order_by);
487 
488  int count(UT_ErrorCode* ec);
489 private:
490 
491  enum class SqlOp
492  {
493  SQL_SELECT,
494  SQL_DELETE,
495  SQL_INSERT,
496  SQL_INSERT_IGNORE,
497  SQL_UPDATE
498  };
499 
500  void filterOnModel_(
501  UT_WorkBuffer& wbuf,
502  const UT_ORMModelMeta& meta,
503  const UT::orm::FilterArg& filter_arg,
504  const UT_StringView& full_arg);
505  void filterOnM2M_(
506  UT_WorkBuffer& wbuf,
507  const UT_ORMModelMeta& through,
508  const UT_ORMModelMeta& curr_meta,
509  const UT::orm::FilterArg& filter_arg,
510  const UT_StringView& argname,
511  const UT_StringView& full_arg,
512  UT_StringSet& executed_joins);
513  UT_StringHolder build_(SqlOp op_type);
514  void addOperationToFilter_(
515  UT_WorkBuffer& wbuf,
516  const UT_StringView& op,
517  const UT::orm::FilterArg& filter_arg);
518  bool isOperation_(const UT_StringView& op) const;
519  UT_ORMQuerySetResult update_();
520 
521  static ut_QueryOperationInfo* getAvailableOperations_();
522 
523  UT_StringArray myReturningValues;
524  UT_StringHolder myFilter;
525  UT_StringArray myJoins;
526  int myLimit = -1;
527  int myOffset = -1;
530  UT_StringHolder myOrderBy;
531 
532  std::reference_wrapper<const UT_ORMModelMeta> myModelMeta;
533 
534  UT_ErrorCode myError;
535 };
536 
537 #endif // __UT_ORMQUERYSET_H__
538 
GLint first
Definition: glcorearb.h:405
const UT_ORMQuerySetResult * operator->() const
typename std::enable_if< B, T >::type enable_if_t
Define Imath::enable_if_t to be std for C++14, equivalent for C++11.
int int32
Definition: SYS_Types.h:39
UT_SqlStatement & stmt()
const UT_ErrorCode & getError() const
Definition: UT_SQL.h:701
overloads(Ts...) -> overloads< Ts...>
const iterator end() const
bool operator!=(const iterator &rhs) const
std::tuple< Args...> as(UT_ErrorCode *ec=nullptr)
std::optional< std::tuple< std::tuple< Args...> > > as(UT_ErrorCode *ec=nullptr)
Definition: UT_SQL.h:857
UT_IntrusivePtr< T > UTmakeIntrusive(ArgsT &&...args)
Constructs an object of type T wrapped in a UT_IntrusivePtr.
GLsizei const GLfloat * value
Definition: glcorearb.h:824
UT_ORMQuerySetResult(const UT_SharedPtr< UT_SqlStatementImpl > &impl, const UT_ErrorCode &ec)
bool bind(int idx, null_tag_t)
Definition: UT_SQL.h:556
UT_Array< T > fetchAllFlat(UT_ErrorCode *ec=nullptr)
Definition: UT_SQL.h:824
SYS_FORCE_INLINE T * SYSconst_cast(const T *foo)
Definition: SYS_Types.h:136
UdlArgValue(const UT_StringHolder &str)
int64 exint
Definition: SYS_Types.h:125
UT_Array< T > fetchAllFlat(UT_ErrorCode *ec=nullptr)
GLdouble s
Definition: glad.h:3009
#define UT_API
Definition: UT_API.h:14
FilterArg operator=(T &&value)
**But if you need a result
Definition: thread.h:622
A reference counter base class for use with UT_IntrusivePtr.
auto arg(const Char *name, const T &arg) -> detail::named_arg< Char, T >
Definition: core.h:1859
OutGridT const XformOp bool bool
SIM_API const UT_StringHolder all
< returns > If no error
Definition: snippets.dox:2
FilterArg(const UT_StringHolder &name, const UT_ORMFieldColumn *field, const void *obj)
UT_SqlStatement myStmt
std::forward_iterator_tag iterator_category
A utility class to do read-only operations on a subset of an existing string.
Definition: UT_StringView.h:40
UT_ORMQuerySetResult & operator*()
GLintptr offset
Definition: glcorearb.h:665
std::shared_ptr< T > UT_SharedPtr
Wrapper around std::shared_ptr.
Definition: UT_SharedPtr.h:36
void bind(UT_SqlStatement &stmt, int &bind_index) const
FilterArg(const UT_StringHolder &name, const UT_ORMFieldColumn *field, const T &objs)
GLuint GLuint end
Definition: glcorearb.h:475
#define SYS_FORCE_INLINE
Definition: SYS_Inline.h:45
Wrapper around hboost::intrusive_ptr.
long long int64
Definition: SYS_Types.h:116
UT_Array< std::tuple< Args...> > fetchAll(UT_ErrorCode *ec=nullptr)
Definition: UT_SQL.h:789
const iterator begin() const
const iterator cbegin() const
bool load(T &obj, UT_ErrorCode &ec)
OIIO_UTIL_API bool exists(string_view path) noexcept
GLuint const GLchar * name
Definition: glcorearb.h:786
FilterArg(const UT_StringHolder &name, T &&arg)
bool operator==(const iterator &rhs) const
FilterArg(const UT_StringHolder &name, const char *arg)
std::error_code UT_ErrorCode
Definition: UT_ErrorCode.h:20
Error getError()
Definition: oidn.hpp:823
UT_ORMQuerySetResult * operator->()
GLsizeiptr size
Definition: glcorearb.h:664
void sqlParam(UT_WorkBuffer &wbuf) const
FilterArg(const UT_StringHolder &name, const T &objs)
LeafData & operator=(const LeafData &)=delete
SYS_FORCE_INLINE void append(char character)
const iterator cend() const
**If you just want to fire and args
Definition: thread.h:618
bool hasResults() const
const UT_StringHolder & name() const
UT_ORMQuerySet values(const std::initializer_list< UT_StringHolder > &col_names)
const UT_ORMQuerySetResult & operator*() const
std::optional< std::tuple< Args...> > fetchOne(UT_ErrorCode *ec=nullptr)
Definition: UT_SQL.h:755
std::tuple< Args...> fetchOne(UT_ErrorCode *ec=nullptr)
UT_Array< std::tuple< Args...> > fetchAll(UT_ErrorCode *ec=nullptr)
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition: glcorearb.h:1297
PcpNodeRef_ChildrenIterator begin(const PcpNodeRef::child_const_range &r)
Support for range-based for loops for PcpNodeRef children ranges.
Definition: node.h:566