From 5652354aa256426c5ab32c4a1c5687e5509af868 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 11 Jan 2023 14:40:02 +0200 Subject: Add support for custom table definition options --- NEWS | 4 ++ doc/manual.xhtml | 45 ++++++++++++++++++++++ odb/context.cxx | 84 ++++++++++++++++++++++++++++++++++++++++++ odb/context.hxx | 8 ++++ odb/relational/model.hxx | 8 ++-- odb/relational/mysql/model.cxx | 34 +++++++++++++++-- 6 files changed, 175 insertions(+), 8 deletions(-) diff --git a/NEWS b/NEWS index d6b2844..1bd577e 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,10 @@ Version 2.5.0 @@ Ref to the manual. + * Support for custom table definition options in addition to column + definition options. For details, refer to Section 14.1.16, "options" in + the ODB manual. + * Support for nested object ids. Now the 'id' pragma specifier can optionally include the data member path to the id inside a composite value. For example: diff --git a/doc/manual.xhtml b/doc/manual.xhtml index 0b6dc08..fde0a54 100644 --- a/doc/manual.xhtml +++ b/doc/manual.xhtml @@ -538,6 +538,7 @@ for consistency. 14.1.13sectionable 14.1.14deleted 14.1.15bulk + 14.1.16options @@ -14360,6 +14361,12 @@ class person 14.1.15 + + options + database options for a persistent class + 14.1.16 + +

14.1.1 table

@@ -15002,6 +15009,39 @@ class employer is the batch size. For more information on this functionality, refer to Section 15.3, "Bulk Database Operations".

+

14.1.16 options

+ +

The options specifier specifies additional table + definition options that should be used for the persistent class. For + example:

+ +
+#pragma db object options("PARTITION BY RANGE (age)")
+class person
+{
+  ...
+
+  unsigned short age_;
+};
+  
+ +

Table definition options for a container table can be specified with + the options data member specifier + (Section 14.4.8, "options"). For + example:

+ +
+#pragma db object
+class person
+{
+  ...
+
+  #pragma db options("PARTITION BY RANGE (index)")
+  std::vector<std::string> aliases_;
+};
+  
+ +

14.2 View Type Pragmas

A pragma with the view qualifier declares a C++ class @@ -16578,6 +16618,11 @@ class person }; +

Note that if specified for the container member, then instead of the + column definition options it specifies the table definition options for + the container table (Section 14.1.16, + "options").

+

Options can also be specified on the per-type basis (Section 14.3.5, "options"). By default, options are accumulating. That is, the ODB compiler diff --git a/odb/context.cxx b/odb/context.cxx index e220d0e..dd4019a 100644 --- a/odb/context.cxx +++ b/odb/context.cxx @@ -2130,6 +2130,90 @@ table_name (semantics::data_member& m, table_prefix const& p) const return r; } +string context:: +table_options (semantics::class_& c) +{ + string r; + + // Accumulate options from class. + // + // @@ Should we also get them from bases? + // + // @@ Note for some databases (like SQLite), options are seperated with + // comma, not space. Likely the same issue in the column_options(). + // + if (c.count ("options")) + { + strings const& o (c.get ("options")); + + for (strings::const_iterator i (o.begin ()); i != o.end (); ++i) + { + if (i->empty ()) + r.clear (); + else + { + if (!r.empty ()) + r += ' '; + + r += *i; + } + } + } + + return r; +} + +string context:: +table_options (semantics::data_member& m, semantics::type& c) +{ + string r; + + // Accumulate options from container and member. + // + // @@ Currently there is no way to assign options to the container type. If + // we use the value specifier, then it ends up being treated as a value + // type. To support this we will probably need to invent the container + // specifier. + // + if (c.count ("options")) + { + strings const& o (c.get ("options")); + + for (strings::const_iterator i (o.begin ()); i != o.end (); ++i) + { + if (i->empty ()) + r.clear (); + else + { + if (!r.empty ()) + r += ' '; + + r += *i; + } + } + } + + if (m.count ("options")) + { + strings const& o (m.get ("options")); + + for (strings::const_iterator i (o.begin ()); i != o.end (); ++i) + { + if (i->empty ()) + r.clear (); + else + { + if (!r.empty ()) + r += ' '; + + r += *i; + } + } + } + + return r; +} + // context::column_prefix // context::column_prefix:: diff --git a/odb/context.hxx b/odb/context.hxx index d10d555..ec4505b 100644 --- a/odb/context.hxx +++ b/odb/context.hxx @@ -1342,6 +1342,14 @@ public: qname table_name (semantics::data_member&, table_prefix const&) const; + string + table_options (semantics::class_&); + + // Table options for the container member. + // + string + table_options (semantics::data_member&, semantics::type& ct); + // // struct column_prefix diff --git a/odb/relational/model.hxx b/odb/relational/model.hxx index b7a07ea..fdfa8fd 100644 --- a/odb/relational/model.hxx +++ b/odb/relational/model.hxx @@ -555,9 +555,9 @@ namespace relational } virtual string - table_options (semantics::data_member&, semantics::type&) + table_options (semantics::data_member& m, semantics::type& ct) { - return ""; + return context::table_options (m, ct); } virtual void @@ -784,9 +784,9 @@ namespace relational class_ (sema_rel::model& model): model_ (model) {} virtual string - table_options (type&) + table_options (type& c) { - return ""; + return context::table_options (c); } virtual void diff --git a/odb/relational/mysql/model.cxx b/odb/relational/mysql/model.cxx index 2ec9d8b..17ed4c0 100644 --- a/odb/relational/mysql/model.cxx +++ b/odb/relational/mysql/model.cxx @@ -110,10 +110,23 @@ namespace relational member_create (base const& x): base (x) {} virtual string - table_options (semantics::data_member&, semantics::type&) + table_options (semantics::data_member& m, semantics::type& c) { + string r (relational::member_create::table_options (m, c)); + string const& engine (options.mysql_engine ()); - return engine != "default" ? "ENGINE=" + engine : ""; + if (engine != "default") + { + // Note: MySQL table options can be separated with spaces. + // + if (!r.empty ()) + r += ' '; + + r += "ENGINE="; + r += engine; + } + + return r; } }; entry member_create_; @@ -123,10 +136,23 @@ namespace relational class_ (base const& x): base (x) {} virtual string - table_options (type&) + table_options (type& c) { + string r (relational::class_::table_options (c)); + string const& engine (options.mysql_engine ()); - return engine != "default" ? "ENGINE=" + engine : ""; + if (engine != "default") + { + // Note: MySQL table options can be separated with spaces. + // + if (!r.empty ()) + r += ' '; + + r += "ENGINE="; + r += engine; + } + + return r; } }; entry class__; -- cgit v1.1