From fe69d94f3d2dcb37d69ac2d7a0f88ad5fce2ad5c Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 1 Mar 2011 11:56:33 +0200 Subject: Add support for embedded database schemas New options: --schema-format, --default-schema. New example: schema/embedded. --- odb/mysql/schema.hxx | 314 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 311 insertions(+), 3 deletions(-) (limited to 'odb/mysql/schema.hxx') diff --git a/odb/mysql/schema.hxx b/odb/mysql/schema.hxx index e221c92..1defad7 100644 --- a/odb/mysql/schema.hxx +++ b/odb/mysql/schema.hxx @@ -6,12 +6,320 @@ #ifndef ODB_MYSQL_SCHEMA_HXX #define ODB_MYSQL_SCHEMA_HXX -#include +#include + +#include +#include namespace mysql { - void - generate_schema (context&); + struct schema_context: context + { + typedef std::set tables; + + schema_context (context& c, std::ostream& os, emitter& e) + : context (c, os), e_ (e) + { + } + + schema_context (schema_context& c) : context (c), e_ (c.e_) {} + + emitter& e_; + }; + + // + // Drop. + // + + struct member_drop: object_members_base, schema_context + { + member_drop (schema_context& c, tables& t) + : object_members_base (c, false, true), + schema_context (c), + tables_ (t) + { + } + + virtual void + container (semantics::data_member& m) + { + // Ignore inverse containers of object pointers. + // + if (inverse (m, "value")) + return; + + string const& name (table_name (m, table_prefix_)); + + if (tables_.count (name)) + return; + + e_.pre (); + os << "DROP TABLE IF EXISTS `" << name << "`" << endl; + e_.post (); + + tables_.insert (name); + } + + private: + tables& tables_; + }; + + struct class_drop: traversal::class_, schema_context + { + class_drop (context& c, emitter& e) + : schema_context (c, os, e), os (e), + member_drop_ (*this, tables_) + { + } + + virtual void + traverse (type& c) + { + if (c.file () != unit.file ()) + return; + + if (!c.count ("object")) + return; + + string const& name (table_name (c)); + + if (tables_.count (name)) + return; + + e_.pre (); + os << "DROP TABLE IF EXISTS `" << name << "`" << endl; + e_.post (); + + tables_.insert (name); + + // Drop tables for members. + // + member_drop_.traverse (c); + } + + private: + tables tables_; + emitter_ostream os; + member_drop member_drop_; + }; + + // + // Create. + // + + struct object_columns: object_columns_base, schema_context + { + object_columns (schema_context& c, string const& prefix = string ()) + : object_columns_base (c), schema_context (c), prefix_ (prefix) + { + } + + virtual bool + column (semantics::data_member& m, string const& name, bool first) + { + // Ignore inverse object pointers. + // + if (inverse (m)) + return false; + + if (!first) + os << "," << endl; + + os << " `" << name << "` " << column_type (m, prefix_); + + if (m.count ("id")) + os << " PRIMARY KEY"; + + using semantics::class_; + if (class_* c = object_pointer (member_type (m, prefix_))) + { + os << " REFERENCES `" << table_name (*c) << "` (`" << + column_name (id_member (*c)) << "`)"; + } + + return true; + } + + private: + string prefix_; + }; + + struct member_create: object_members_base, schema_context + { + member_create (schema_context& c, semantics::class_& object, tables& t) + : object_members_base (c, false, true), + schema_context (c), + id_member_ (id_member (object)), + tables_ (t) + { + } + + virtual void + container (semantics::data_member& m) + { + using semantics::type; + using semantics::data_member; + + // Ignore inverse containers of object pointers. + // + if (inverse (m, "value")) + return; + + type& t (m.type ()); + container_kind_type ck (container_kind (t)); + type& vt (container_vt (t)); + + string const& name (table_name (m, table_prefix_)); + + if (tables_.count (name)) + return; + + e_.pre (); + os << "CREATE TABLE `" << name << "` (" << endl; + + // object_id (simple value) + // + string id_name (column_name (m, "id", "object_id")); + os << " `" << id_name << "` " << column_type (id_member_, "ref"); + + // index (simple value) + // + string index_name; + bool ordered (ck == ck_ordered && !unordered (m)); + if (ordered) + { + index_name = column_name (m, "index", "index"); + + os << "," << endl + << " `" << index_name << "` " << column_type (m, "index"); + } + + // key (simple or composite value) + // + if (ck == ck_map || ck == ck_multimap) + { + type& kt (container_kt (t)); + + os << "," << endl; + + if (semantics::class_* ckt = comp_value (kt)) + { + object_columns oc (*this); + oc.traverse_composite (m, *ckt, "key", "key"); + } + else + { + object_columns oc (*this, "key"); + string const& name (column_name (m, "key", "key")); + oc.column (m, name, true); + } + } + + // value (simple or composite value) + // + { + os << "," << endl; + + if (semantics::class_* cvt = comp_value (vt)) + { + object_columns oc (*this); + oc.traverse_composite (m, *cvt, "value", "value"); + } + else + { + object_columns oc (*this, "value"); + string const& name (column_name (m, "value", "value")); + oc.column (m, name, true); + } + } + + // object_id index + // + os << "," << endl + << " INDEX (`" << id_name << "`)"; + + // index index + // + if (ordered) + os << "," << endl + << " INDEX (`" << index_name << "`)"; + + os << ")"; + + string const& engine (options.mysql_engine ()); + + if (engine != "default") + os << endl + << " ENGINE=" << engine; + + os << endl; + e_.post (); + + tables_.insert (name); + } + + private: + semantics::data_member& id_member_; + tables& tables_; + }; + + struct class_create: traversal::class_, schema_context + { + class_create (context& c, emitter& e) + : schema_context (c, os, e), os (e) + { + } + + virtual void + traverse (type& c) + { + if (c.file () != unit.file ()) + return; + + if (!c.count ("object")) + return; + + string const& name (table_name (c)); + + // If the table with this name was already created, assume the + // user knows what they are doing and skip it. + // + if (tables_.count (name)) + return; + + e_.pre (); + os << "CREATE TABLE `" << name << "` (" << endl; + + { + object_columns oc (*this); + oc.traverse (c); + } + + os << ")"; + + string const& engine (options.mysql_engine ()); + + if (engine != "default") + os << endl + << " ENGINE=" << engine; + + os << endl; + e_.post (); + + tables_.insert (name); + + // Create tables for members. + // + { + member_create mc (*this, c, tables_); + mc.traverse (c); + } + } + + private: + tables tables_; + emitter_ostream os; + }; } #endif // ODB_MYSQL_SCHEMA_HXX -- cgit v1.1