HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_ORMModelMeta.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_ORMModelMeta.h
7  *
8  * COMMENTS:
9  *
10  * The UT_ORMModelMeta class describes the C++ object (model) and how this
11  * object relates to the database through tables, fields, foreign relationships
12  * etc.
13  *
14  * See UT_SQLORM on how to create a meta object that descibes a model.
15  */
16 
17 #ifndef __UT_ORMMODELMETA_H__
18 #define __UT_ORMMODELMETA_H__
19 
20 #include "UT_API.h"
21 
22 #include "UT_ORMField.h"
23 #include "UT_StringHolder.h"
24 #include "UT_ORMError.h"
25 #include "UT_ORMQuerySet.h"
26 #include "UT_SharedPtr.h"
27 
28 class UT_SqlOrm;
30 class UT_ORMBaseModel;
31 class UT_ORMMigration;
32 
33 namespace UT::detail
34 {
35 template <typename T>
37 {
38  void operator()(T*) {}
39 };
40 } // namespace UT::detail
41 
42 template <typename Owner, typename OtherModel>
44 
46 {
47 public:
49  : myORM(orm)
50  {
51  setModelName(name);
52  setTableName(name);
53  }
55  virtual ~UT_ORMModelMeta() = default;
57 
59  {
60  myTableName = name;
61  }
63  {
64  myModelName = name;
65  if (!myTableName)
66  myTableName = name;
67  if (!myVerboseName)
68  myVerboseName = name;
69  if (!myPluralVerboseName)
70  myPluralVerboseName = name;
71  }
73  {
74  myVerboseName = name;
75  }
77  {
78  myPluralVerboseName = name;
79  }
80 
81  /// Call to build out all of your meta information.
82  void build(UT_SqlOrm& orm);
83  /// Called after all models concrete information has been connected
84  void connectLinks();
85  // Collect all migrations for this model.
86  virtual void collectMigrations(
87  UT_ORMMigrationBuilder& builder) const
88  = 0;
89  /// Called right before connecting the links on each model
90  virtual void preConnectLinks() {}
91  void postMigrate();
92 
93  template <typename Cls, typename FieldT>
95  const UT_StringHolder& name,
96  FieldT Cls::*field,
97  unsigned props = UT_ORMColumn::Empty)
98  {
99  myColumns.emplace_back(
101  name, field, props | UT_ORMColumn::AutoIncrement));
102  }
103  template <typename Cls, typename FieldT>
104  void addField(
105  const UT_StringHolder& name,
106  FieldT Cls::*field,
107  unsigned props = UT_ORMColumn::Empty)
108  {
109  myColumns.emplace_back(
111  name, field, props));
112  }
113  template <typename Cls, typename ForeignModel>
114  void addField(
115  const UT_StringHolder& name,
117  unsigned props = UT_ORMColumn::Empty,
118  UT_ORMColumn::OnDelete ondelete_type
119  = UT_ORMColumn::OnDelete::Cascade,
120  const UT_StringHolder& related_name
122  const UT_ORMModelMeta& foreign_meta = ForeignModel::metaInfo())
123  {
124  using adapter_t = UT_ORMForeignKeyFieldAdapter<
126  myColumns.emplace_back(adapter_t::createColumn(
127  foreign_meta, name, field, props, ondelete_type, related_name));
128  }
129  template <typename Owner, typename OtherModel>
130  void addField(
131  const UT_StringHolder& name,
133  const UT_StringHolder& related_name
135  {
136  UT_ASSERT(modelName() == Owner::metaInfo().modelName());
137  auto self = lookupMetaFromORM_(modelName());
138  auto other = lookupMetaFromORM_(OtherModel::metaInfo().modelName());
139  registerM2M_(self, other, name, related_name);
140  }
141 
142  const UT_StringHolder& tableName() const { return myTableName; }
143  const UT_StringHolder& modelName() const { return myModelName; }
144  const UT_StringHolder& verboseName() const { return myVerboseName; }
146  {
147  return myPluralVerboseName;
148  }
149  const UT_ORMFieldColumn* primaryKey() const { return myPrimaryKey; }
150  const UT_Array<UT_ORMFieldColumn>& columns() const { return myColumns; }
152  {
153  return myForeignKeys;
154  }
156  {
157  return myUniqueColumns;
158  }
159 
160  template <typename T>
161  bool save(
162  T& obj,
163  UT_ErrorCode& ec,
164  bool force_insert = false,
165  bool force_update = false) const;
166  template <typename T>
167  void remove(T& obj, UT_ErrorCode& ec) const;
168  template <typename T>
169  void remove(
170  const std::initializer_list<UT::orm::FilterArg>& args,
171  UT_ErrorCode& ec) const;
172  template <typename T, typename PK>
173  UT_Optional<T> fetch(const PK& pk, UT_ErrorCode& ec) const;
174  template <typename T>
175  UT_Array<T> fetch(
176  const std::initializer_list<UT::orm::FilterArg>& args,
177  UT_ErrorCode& ec) const;
178  template <typename T>
179  UT_Array<T> fetchAll(UT_ErrorCode& ec) const;
180  template <typename T>
182  const std::initializer_list<UT::orm::FilterArg>& args,
183  UT_ErrorCode& ec) const;
184  template <typename T>
185  std::pair<T, bool> getOrCreate(
186  const std::initializer_list<UT::orm::FilterArg>& args,
187  UT_ErrorCode& ec) const;
188  template <typename T>
189  UT_Optional<T> create(
190  const std::initializer_list<UT::orm::FilterArg>& args,
191  UT_ErrorCode& ec) const;
192  template <typename T, typename ArrayT>
193  UT_Array<T> bulkFetch(
194  const ArrayT& pks,
195  UT_ErrorCode& ec,
196  const UT_StringRef& col_name
198  template <typename T>
199  void bulkSave(const UT_Array<T>& items, UT_ErrorCode& ec) const;
200  template <typename T, typename... Args>
201  T fromDB(Args&&... args) const
202  {
203  T obj(std::forward<Args>(args)...);
204  obj.myOrmAdding = false;
205  return obj;
206  }
207  template <typename T>
208  bool exists(
209  const std::initializer_list<UT::orm::FilterArg>& args,
210  UT_ErrorCode& ec) const;
211 
212  UT_SqlOrm* orm() const { return SYSconst_cast(this)->myORM; }
213  UT_SqlStatement cursor() const;
214  UT_SqlDatabase& db();
215  UT_SqlDatabase& db() const;
216 
217  template <typename T>
218  bool loadObject(T& obj, UT_SqlStatement& stmt, UT_ErrorCode& ec) const
219  {
220  for (int i = 0; i < myColumns.size(); i++)
221  {
222  const UT_ORMFieldColumn& column = myColumns[i];
223  if (!column.isManyToMany())
224  {
225  if (UT_IORMFieldAdapter* adapter = column.adapter(); adapter)
226  {
227  adapter->load(&obj, stmt, i, ec);
228  if (ec)
229  return false;
230  }
231  else
232  {
233  ec = UTmakeErrorCode(
235  UT_ASSERT(!"Type not handled");
236  }
237  }
238  }
239 
240  // If the object is being loaded from the db then at some point it
241  // was saved.
242  obj.myOrmAdding = false;
243 
244  return true;
245  }
246  template <typename T>
248  {
249  UT_Array<T> items;
250  while (stmt.hasRow() && !stmt.getError())
251  {
252  T obj(*this);
253  if (loadObject(obj, stmt, ec))
254  items.emplace_back(obj);
255  else
256  break;
257  }
258  if (!ec)
259  ec = stmt.getError();
260  if (ec)
261  items.clear();
262  return items;
263  }
264 
266  {
267  myHasBuilt = false;
268  myHasPostBuilt = false;
269  myHasPostMigrate = false;
270  myIsThroughTable = false;
271  myColumns.clear();
272  myForeignKeys.clear();
273  myUniqueColumns.clear();
274  myRelated.clear();
275  myPrimaryKey = nullptr;
276  myORM = nullptr;
277  }
278 
279  bool hasField(const UT_StringView& name) const
280  {
281  for (auto&& col : myColumns)
282  {
283  if (UT_StringView(col.name()) == name)
284  return true;
285  }
286  return false;
287  }
288 
289  const UT_ORMFieldColumn* findField(const UT_StringView& name) const
290  {
291  for (auto&& col : myColumns)
292  {
293  if (UT_StringView(col.name()) == name)
294  return &col;
295  }
296  return nullptr;
297  }
298  /// Find a foreign concrete field based on the column name. The column name
299  /// passed in must be for a local field that is a foreign key
301  const UT_StringView& name) const
302  {
303  const UT_ORMFieldColumn* local_field = findField(name);
304  if (local_field != nullptr)
305  {
306  UT_SharedPtr<UT_ORMModelMeta> foreign_model
307  = local_field->foreignModel();
308  if (foreign_model != nullptr)
309  {
310  UT_StringHolder foreign_related_field_name
311  = local_field->foreignFieldName();
312  const UT_ORMFieldColumn* foreign_field
313  = foreign_model->findField(foreign_related_field_name);
314  return foreign_field;
315  }
316  }
317  return nullptr;
318  }
319 
320  bool registerRelated(
321  const UT_SharedPtr<UT_ORMModelMeta>& related,
322  const UT_StringHolder& related_name,
323  const UT_StringHolder& fk_field_name
325  UT_SharedPtr<UT_ORMModelMeta> findRelated(
326  const UT_StringView& name,
327  UT_StringHolder& fk_field_name) const;
328 
329  /// On a lookup table split the two columns up based on the provided model.
330  /// This is helpful for quickly determining which column on the lookup
331  /// table belongs to the provided concrete model and the other model.
332  void lookupTableColumns(
333  const UT_StringRef& model_name,
334  const UT_ORMFieldColumn*& fk_model,
335  const UT_ORMFieldColumn*& fk_other_model) const;
336 
337  bool isThroughTable() const { return myIsThroughTable; }
338 
340  {
341  return UT_ORMQuerySet(*this);
342  }
343 
344 protected:
345  struct Related
346  {
348  const UT_StringHolder& fk_name,
349  const UT_SharedPtr<UT_ORMModelMeta>& foreign_meta)
350  : myName(name)
351  , myForeignKeyName(fk_name)
352  , myForeignMeta(foreign_meta)
353  {
354  }
355  // Related name of the model. This is mainly used for searching
357  // If the relation is by reverse foreign key then this is the name of
358  // the foreign key field of the model. This is necessary for the join
359  // statement
361  // This is the related model. If its a M2M relationship this is the
362  // lookup table which the actual models can be found from. If its a
363  // related foreign key then this is the actual foreign model.
365  };
366 
367  virtual void doBuild() = 0;
368  virtual void doPostBuild() {}
369  virtual void doPostMigrate();
370 
371  /// Configure any cacheable information that is used often.
372  void configureConcrete_();
373 
374  void registerM2M_(
377  const UT_StringHolder& field_name,
378  const UT_StringHolder& related_name);
379 
380  UT_SharedPtr<UT_ORMModelMeta> lookupMetaFromORM_(
381  const UT_StringView& name) const;
382 
383  template <typename T>
384  bool doUpdate_(T& obj, UT_ErrorCode& ec) const;
385  template <typename T>
386  bool doInsert_(T& obj, UT_ErrorCode& ec) const;
387 
388  static void addDynamicColumn_(
389  UT_ORMModelMeta& meta,
390  UT_ORMFieldColumn&& field)
391  {
392  meta.myColumns.emplace_back(std::forward<UT_ORMFieldColumn>(field));
393  }
394 
395  bool myHasBuilt = false;
396  bool myHasPostBuilt = false;
397  bool myHasPostMigrate = false;
398  bool myIsThroughTable = false;
403  const UT_ORMFieldColumn* myPrimaryKey = nullptr;
408  UT_SqlOrm* myORM = nullptr;
409 };
410 
411 template <typename T>
412 bool
414  T& obj,
415  UT_ErrorCode& ec,
416  bool force_insert,
417  bool force_update) const
418 {
419  // If we arent forcing anything but also havent added the object then
420  // force an insert.
421  if (!force_insert && !force_update && obj.myOrmAdding)
422  force_insert = true;
423 
424  bool updated = false;
425  if (!force_insert)
426  {
427  updated = doUpdate_(obj, ec);
428 
429  if (force_update && !updated)
430  {
431  // TODO: error
432  return false;
433  }
434  }
435 
436  if (!updated)
437  {
438  updated = doInsert_(obj, ec);
439  }
440 
441  obj.myOrmAdding = false;
442 
443  return updated;
444 }
445 
446 template <typename T>
447 bool
449 {
451  for (auto&& col : myColumns)
452  {
453  if (!col.isPrimaryKey() && !col.isManyToMany())
454  {
455  values.emplace_back(UT::orm::FilterArg(col.name(), &col, &obj));
456  }
457  }
458 
459  UT_ORMQuerySet qset(*this);
461  = qset.filter({UT::orm::FilterArg(
462  primaryKey()->name(), primaryKey(), &obj)})
463  .update(values);
464 
465  ec = result.getError();
466  return result.stmt().changes() > 0 && !(bool)ec;
467 }
468 
469 template <typename T>
470 bool
472 {
473  UT_WorkBuffer sql_query("INSERT INTO ");
474 
477 
478  for (auto&& col : myColumns)
479  {
480  if (!col.isManyToMany())
481  {
482  if (col.isAutoIncrement())
483  outputs.emplace_back(&col);
484  else
485  // When the value is auto incremented we need to capture the
486  // value as the current value is likely not correct to the DB.
487  values.emplace_back(&col);
488  }
489  }
490 
491  sql_query.append(tableName());
492  sql_query.append(" (");
493  for (exint i = 0; i < values.size(); i++)
494  {
495  const UT_ORMFieldColumn* col = values[i];
496  if (!col->isAutoIncrement())
497  {
498  if (i != 0)
499  sql_query.append(',');
500  sql_query.append(col->name());
501  }
502  }
503  sql_query.append(')');
504 
505 
506  sql_query.append(" VALUES (");
507  for (exint i = 0; i < values.size(); i++)
508  {
509  const UT_ORMFieldColumn* col = values[i];
510  if (!col->isAutoIncrement())
511  {
512  if (i != 0)
513  sql_query.append(',');
514  sql_query.append('?');
515  }
516  }
517  sql_query.append(')');
518 
519  if (outputs.size() > 0)
520  {
521  sql_query.append(" RETURNING ");
522  // Add any outputs we might need to capture
523  for (exint i = 0, c = outputs.size(); i < c; i++)
524  {
525  if (i != 0)
526  sql_query.append(',');
527  sql_query.appendFormat("{}", outputs[i]->name());
528  }
529  }
530  sql_query.append(';');
531 
532  UT_ASSERT(myORM);
533  UT_SqlStatement stmt(cursor());
534 
535  if (stmt.getError())
536  {
537  ec = stmt.getError();
538  return false;
539  }
540 
541  if (!stmt.prepare(sql_query, ec))
542  {
543  return false;
544  }
545  for (int i = 0; i < values.size(); i++)
546  {
547  const UT_ORMFieldColumn* col = values[i];
548  if (!col->isAutoIncrement())
549  {
550  if (UT_IORMFieldAdapter* adapter = col->adapter(); adapter)
551  adapter->bind(&obj, stmt, i+1, ec);
552  else
553  {
555  }
556  if (ec)
557  return false;
558  }
559  }
560 
561  stmt.step();
562 
563  int changes = stmt.changes();
564 
565  // If the insert was a success load any outputs into the columns.
566  if (changes > 0 && outputs.size() > 0)
567  {
568  for (exint i = 0, c= outputs.size(); i < c; i++)
569  {
570  const UT_ORMFieldColumn* output = outputs[i];
571  if (UT_IORMFieldAdapter* adapter = output->adapter(); adapter)
572  {
573  adapter->load(&obj, stmt, i, ec);
574  }
575  }
576 
577  stmt.step();
578  }
579 
580  if (stmt.getError())
581  ec = stmt.getError();
582 
583  return changes > 0;
584 }
585 
586 template <typename T>
587 void
589 {
591 
592  UT_ORMQuerySet qset(*this);
594  = qset.filter({UT::orm::FilterArg(column->name(), column, &obj)})
595  .remove();
596 
597  if (result.getError())
598  {
599  ec = result.getError();
600  return;
601  }
602 
603  // Object has been removed from the db let the c++ object know in the
604  // event it has to do some extra work
605  for (auto&& meta_column : myColumns)
606  {
607  UT_IORMFieldAdapter* adapter = column->adapter();
608  adapter->onDelete(&obj, meta_column.onDelete(), ec);
609 
610  if (ec)
611  return;
612  }
613 }
614 
615 template <typename T>
616 void
618  const std::initializer_list<UT::orm::FilterArg>& args,
619  UT_ErrorCode& ec) const
620 {
621  UT_ORMQuerySet qset(*this);
622  UT_ORMQuerySetResult result = qset.filter(args).remove();
623  ec = result.getError();
624 }
625 
626 template <typename T>
629  const std::initializer_list<UT::orm::FilterArg>& args,
630  UT_ErrorCode& ec) const
631 {
632  UT_ORMQuerySet qset(*this);
633  UT_ORMQuerySetResult result = qset.filter(args).get();
634 
635  UT_Array<T> items;
636  for (auto&& record : result)
637  {
638  T item(*this);
639  if (loadObject(item, record.stmt(), ec))
640  items.emplace_back(std::move(item));
641  else
642  return UT_Array<T>{};
643  }
644 
645  if (result.getError())
646  ec = result.getError();
647 
648  return items;
649 }
650 
651 template <typename T, typename PK>
653 UT_ORMModelMeta::fetch(const PK& pk, UT_ErrorCode& ec) const
654 {
655  UT_ORMQuerySet qset(*this);
656  UT_ORMQuerySetResult result
657  = qset.filter({UT::orm::FilterArg(primaryKey()->name(), pk)}).get();
658 
659  if (!result.hasResults())
660  return std::nullopt;
661 
662  T item(*this);
663  if (loadObject(item, result.stmt(), ec))
664  {
665  return std::make_optional<T>(item);
666  }
667 
668  return std::nullopt;
669 }
670 
671 template <typename T>
674 {
675  UT_ORMQuerySet qset(*this);
676  UT_ORMQuerySetResult result = qset.get();
677 
678  UT_Array<T> items;
679  for (auto&& record : result)
680  {
681  T item(*this);
682  if (loadObject(item, record.stmt(), ec))
683  items.emplace_back(std::move(item));
684  else
685  return UT_Array<T>{};
686  }
687 
688  if (result.getError())
689  ec = result.getError();
690 
691  return items;
692 }
693 
694 template <typename T>
697  const std::initializer_list<UT::orm::FilterArg>& args,
698  UT_ErrorCode& ec) const
699 {
700  UT_ORMQuerySet qset(*this);
701  UT_ORMQuerySetResult result = qset.filter(args).limit(1).get();
702 
703  if (!result.hasResults())
704  return std::nullopt;
705 
706  T item(*this);
707  if (loadObject(item, result.stmt(), ec))
708  return item;
709 
710  return std::nullopt;
711 }
712 
713 template <typename T>
716  const std::initializer_list<UT::orm::FilterArg>& args,
717  UT_ErrorCode& ec) const
718 {
719  UT_ORMQuerySet qset(*this);
720  UT_ORMQuerySetResult result = qset.create(args);
721 
722  ec = result.getError();
723  if (ec)
724  return std::nullopt;
725 
726  if (result.hasResults())
727  {
728  T obj;
729  if (result.load(obj, ec))
730  return obj;
731  }
732 
733  return std::nullopt;
734 }
735 
736 template <typename T>
737 std::pair<T, bool>
739  const std::initializer_list<UT::orm::FilterArg>& args,
740  UT_ErrorCode& ec) const
741 {
742  if (auto&& found_obj = filter<T>(args, ec); found_obj)
743  {
744  return std::make_pair(std::move(found_obj.value()), false);
745  }
746 
747  if (ec)
748  return std::make_pair(T(), false);
749 
750  {
752  if (auto&& created_obj = create<T>(args, ec); created_obj)
753  {
754  trans.commit();
755  return std::make_pair(std::move(created_obj.value()), true);
756  }
757  }
758 
760  return std::make_pair(T(), false);
761 
762  if (auto&& found_obj = filter<T>(args, ec); found_obj)
763  {
764  return std::make_pair(std::move(found_obj.value()), false);
765  }
766 
767  // This should basically never happen but there is an outside chance so we
768  // need to make sure we communicate that we neither got or created an
769  // object so the operation failed.
770  if (!ec)
772 
773  return std::make_pair(T(), false);
774 }
775 
776 template <typename T, typename ArrayT>
779  const ArrayT& pks,
780  UT_ErrorCode& ec,
781  const UT_StringRef& col_name) const
782 {
783  UT_WorkBuffer wbuf;
784  wbuf.append("SELECT ");
785  for (int i = 0, count = 0; i < myColumns.size(); i++)
786  {
787  // M2M isnt an actual column on a model.
788  if (!myColumns[i].isManyToMany())
789  {
790  if (count != 0)
791  wbuf.append(',');
792  wbuf.append(myColumns[i].name());
793  count++;
794  }
795  }
796  wbuf.append(" FROM ");
797  wbuf.append(tableName());
798  wbuf.append(" WHERE ");
799  if (!col_name)
800  {
801  if (const UT_ORMFieldColumn* col = findField(col_name); col)
802  wbuf.append(col->name());
803  else
804  return UT_Array<T>();
805  }
806  else
807  {
808  wbuf.append(primaryKey()->name());
809  }
810  wbuf.append(" IN (");
811  for (int i = 0, c=pks.size(); i<c; i++)
812  {
813  if (i != 0)
814  wbuf.append(" , ");
815  wbuf.append("?");
816  }
817  wbuf.append(")");
818 
819  UT_SqlStatement stmt(cursor());
820 
821  if (!stmt.prepare(wbuf, ec))
822  return UT_Array<T>();
823 
824  int index = 1;
825  for (auto&& pk : pks)
826  {
827  stmt.bind(index, pk);
828  index++;
829  }
830 
831  UT_Array<T> items;
832  while (stmt.step() && !stmt.getError())
833  {
834  T item(*this);
835  if (loadObject(item, stmt, ec))
836  items.emplace_back(std::move(item));
837  else
838  return UT_Array<T>{};
839  }
840 
841  return items;
842 }
843 
844 template <typename T>
845 void
847 {
848  UT_SqlStatement stmt = cursor();
849 
850  UT_WorkBuffer wbuf;
851  wbuf.append("INSERT INTO ");
852  wbuf.append(tableName());
853  wbuf.append(" (");
854 
855  UT_WorkBuffer values_str;
856  values_str.append('(');
857  for (int i = 0, c = myColumns.size(), cl=0; i < c; i++)
858  {
859  if (!myColumns[i].isAutoIncrement())
860  {
861  if (cl != 0)
862  {
863  wbuf.append(',');
864  values_str.append(',');
865  }
866  values_str.append('?');
867  wbuf.append(myColumns[i].name());
868  cl++;
869  }
870  }
871  values_str.append(')');
872  wbuf.append(") VALUES ");
873  for (int i = 0, c = items.size(); i < c; i++)
874  {
875  if (i != 0)
876  wbuf.append(',');
877  wbuf.append(values_str);
878  }
879  wbuf.append(';');
880 
881  if (!stmt.prepare(wbuf, ec))
882  return;
883 
884  int bind_index = 1;
885  for (auto&& item : items)
886  {
887  for (auto&& col : myColumns)
888  {
889  if (!col.isAutoIncrement())
890  {
891  if (UT_IORMFieldAdapter* adapter = col.adapter(); adapter)
892  {
893  adapter->bind(SYSconst_cast(&item), stmt, bind_index, ec);
894  if (ec)
895  return;
896  }
897  else
898  {
899  ec = UTmakeErrorCode(
901  UT_ASSERT(!"Type not handled");
902  }
903  bind_index++;
904  }
905  }
906  }
907 
908  stmt.step();
909  if (stmt.getError())
910  ec = stmt.getError();
911 }
912 
913 template <typename T>
914 bool
916  const std::initializer_list<UT::orm::FilterArg>& args,
917  UT_ErrorCode& ec) const
918 {
919  UT_ORMQuerySet qset(*this);
920  return qset.filter(args).exists(ec);
921 }
922 
923 #endif // __UT_ORMMODELMETA_H__
UT_StringHolder myTableName
UT_StringHolder myVerboseName
const UT_StringHolder & name() const
Definition: UT_ORMColumn.h:76
void addAutoField(const UT_StringHolder &name, FieldT Cls::*field, unsigned props=UT_ORMColumn::Empty)
bool step()
Definition: UT_SQL.h:694
UT_SqlStatement & stmt()
const UT_ErrorCode & getError() const
Definition: UT_SQL.h:701
const UT_StringHolder & verboseName() const
UT_Optional< T > fetch(const PK &pk, UT_ErrorCode &ec) const
bool doInsert_(T &obj, UT_ErrorCode &ec) const
UT_StringHolder myModelName
void remove(T &obj, UT_ErrorCode &ec) const
GLint left
Definition: glcorearb.h:2005
virtual void doPostBuild()
void addField(const UT_StringHolder &name, UT_ORMForeignKeyField< ForeignModel > Cls::*field, unsigned props=UT_ORMColumn::Empty, UT_ORMColumn::OnDelete ondelete_type=UT_ORMColumn::OnDelete::Cascade, const UT_StringHolder &related_name=UT_StringHolder::theEmptyString, const UT_ORMModelMeta &foreign_meta=ForeignModel::metaInfo())
bool bind(int idx, null_tag_t)
Definition: UT_SQL.h:556
UT_ORMQuerySet querySet() const
UT_ORMModelMeta(const UT_StringHolder &name, UT_SqlOrm *orm=nullptr)
bool isManyToMany() const
Definition: UT_ORMColumn.h:134
SYS_FORCE_INLINE T * SYSconst_cast(const T *foo)
Definition: SYS_Types.h:136
UT_Array< T > fetchAll(UT_ErrorCode &ec) const
GLdouble right
Definition: glad.h:2817
const UT_ORMFieldColumn * primaryKey() const
int64 exint
Definition: SYS_Types.h:125
static void addDynamicColumn_(UT_ORMModelMeta &meta, UT_ORMFieldColumn &&field)
void addField(const UT_StringHolder &name, UT_ORMManyToManyField< Owner, OtherModel > Owner::*field, const UT_StringHolder &related_name=UT_StringHolder::theEmptyString)
virtual void onDelete(void *obj, UT_ORMColumn::OnDelete ondelete, UT_ErrorCode &ec)
Definition: UT_ORMField.h:66
UT_Optional< T > filter(const std::initializer_list< UT::orm::FilterArg > &args, UT_ErrorCode &ec) const
bool save(T &obj, UT_ErrorCode &ec, bool force_insert=false, bool force_update=false) const
#define UT_API
Definition: UT_API.h:14
UT_Array< T > bulkFetch(const ArrayT &pks, UT_ErrorCode &ec, const UT_StringRef &col_name=UT_StringHolder::theEmptyString) const
**But if you need a result
Definition: thread.h:622
UT_ORMQuerySet filter(const std::initializer_list< UT::orm::FilterArg > &args)
UT_Array< T > loadAllObjects(UT_SqlStatement &stmt, UT_ErrorCode &ec)
void setModelName(const UT_StringHolder &name)
const UT_Array< UT_ORMFieldColumn > & columns() const
exint size() const
Definition: UT_Array.h:653
UT_Array< const UT_ORMFieldColumn * > myUniqueColumns
T fromDB(Args &&...args) const
OutGridT const XformOp bool bool
std::optional< T > UT_Optional
Definition: UT_Optional.h:26
A utility class to do read-only operations on a subset of an existing string.
Definition: UT_StringView.h:40
size_t appendFormat(const char *fmt, const Args &...args)
const UT_StringHolder & pluralVerboseName() const
UT_IORMFieldAdapter * adapter()
Definition: UT_ORMField.h:134
exint emplace_back(S &&...s)
Definition: UT_ArrayImpl.h:769
bool hasRow()
Definition: UT_SQL.h:683
bool isAutoIncrement() const
Definition: UT_ORMColumn.h:115
UT_Optional< T > create(const std::initializer_list< UT::orm::FilterArg > &args, UT_ErrorCode &ec) const
std::shared_ptr< T > UT_SharedPtr
Wrapper around std::shared_ptr.
Definition: UT_SharedPtr.h:36
GA_API const UT_StringHolder trans
UT_SqlOrm * orm() const
static const UT_StringHolder theEmptyString
bool hasField(const UT_StringView &name) const
const UT_StringHolder & modelName() const
UT_SqlStatement cursor() const
#define UT_NON_COPYABLE(CLASS)
Define deleted copy constructor and assignment operator inside a class.
UT_SharedPtr< UT_ORMModelMeta > foreignModel() const
Definition: UT_ORMField.h:156
const UT_ErrorCode & getError() const
bool load(T &obj, UT_ErrorCode &ec)
bool exists(const std::initializer_list< UT::orm::FilterArg > &args, UT_ErrorCode &ec) const
OIIO_UTIL_API bool exists(string_view path) noexcept
virtual void preConnectLinks()
Called right before connecting the links on each model.
GLuint const GLchar * name
Definition: glcorearb.h:786
void commit(UT_ErrorCode *ec=nullptr)
void bulkSave(const UT_Array< T > &items, UT_ErrorCode &ec) const
UT_ORMQuerySetResult remove()
std::error_code UT_ErrorCode
Definition: UT_ErrorCode.h:20
auto UTmakeErrorCode(EnumT e) -> decltype(make_error_code(e))
Make a UT_ErrorCode based on the provided namespaced enum class.
Definition: UT_ErrorCode.h:29
const UT_StringHolder & foreignFieldName() const
Definition: UT_ORMColumn.h:174
UT_Array< UT_ORMFieldColumn > myColumns
const UT_Array< const UT_ORMFieldColumn * > & foreignKeys() const
bool isThroughTable() const
const UT_StringHolder & tableName() const
UT_ORMQuerySetResult get()
void setVerboseName(const UT_StringHolder &name)
GLenum GLsizei GLsizei GLint * values
Definition: glcorearb.h:1602
void setPluralVerboseName(const UT_StringHolder &name)
UT_ORMQuerySetResult create(const std::initializer_list< UT::orm::FilterArg > &args, bool ignore_conflicts=false, bool no_return=false)
const UT_ORMFieldColumn * findField(const UT_StringView &name) const
GLuint index
Definition: glcorearb.h:786
SYS_FORCE_INLINE void append(char character)
const UT_ORMFieldColumn * findForeignRelatedField(const UT_StringView &name) const
**If you just want to fire and args
Definition: thread.h:618
void setTableName(const UT_StringHolder &name)
UT_Array< Related > myRelated
bool hasResults() const
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:156
bool doUpdate_(T &obj, UT_ErrorCode &ec) const
bool loadObject(T &obj, UT_SqlStatement &stmt, UT_ErrorCode &ec) const
UT_ORMQuerySet limit(int limit)
void clear()
Resets list to an empty list.
Definition: UT_Array.h:736
std::pair< T, bool > getOrCreate(const std::initializer_list< UT::orm::FilterArg > &args, UT_ErrorCode &ec) const
UT_StringHolder myPluralVerboseName
GLenum GLenum GLsizei void GLsizei void * column
Definition: glad.h:5135
UT_Array< const UT_ORMFieldColumn * > myForeignKeys
UT_SqlOrm * myORM
void addField(const UT_StringHolder &name, FieldT Cls::*field, unsigned props=UT_ORMColumn::Empty)
std::weak_ptr< T > UT_WeakPtr
Definition: UT_SharedPtr.h:49
bool exists(UT_ErrorCode &ec)
UT_SqlDatabase & db()
const UT_Array< const UT_ORMFieldColumn * > & uniqueColumns() const
GLint GLsizei count
Definition: glcorearb.h:405
GLenum GLuint GLsizei const GLenum * props
Definition: glcorearb.h:2525
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition: glcorearb.h:1297
bool prepare(const UT_StringRef &sql, UT_ErrorCode &ec)
int changes() const
Definition: UT_SQL.h:883