aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2012-11-02 12:18:43 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2012-11-21 13:13:50 +0200
commit1f777ed4b8cc816817e1ce6cb8d9af970ad9b423 (patch)
treefc6be8482dfa11fa26b387ca4763d9b282b27638
parent8a637f5697fdee3e7ae2d46f64a64d40cba5954b (diff)
Rework query alias tag system
Now each object pointer or view-associated object with alias gets its own unique tag.
-rw-r--r--odb/relational/common.cxx205
-rw-r--r--odb/relational/common.hxx27
-rw-r--r--odb/relational/header.cxx48
-rw-r--r--odb/relational/header.hxx87
-rw-r--r--odb/relational/source.cxx53
5 files changed, 283 insertions, 137 deletions
diff --git a/odb/relational/common.cxx b/odb/relational/common.cxx
index e9b3485..b8d2c60 100644
--- a/odb/relational/common.cxx
+++ b/odb/relational/common.cxx
@@ -17,6 +17,15 @@ namespace relational
// query_alias_traits
//
+ query_alias_traits::
+ query_alias_traits (semantics::class_& c, bool decl)
+ : decl_ (decl)
+ {
+ scope_ = "access::";
+ scope_ += (object (c) ? "object_traits_impl" : "view_traits_impl");
+ scope_ += "< " + class_fq_name (c) + ", id_" + db.string () + " >";
+ }
+
void query_alias_traits::
traverse_object (semantics::class_& c)
{
@@ -26,101 +35,110 @@ namespace relational
}
void query_alias_traits::
- traverse_pointer (semantics::data_member& m, semantics::class_& c)
+ traverse_composite (semantics::data_member* m, semantics::class_& c)
{
- // Ignore polymorphic id references.
- //
- if (m.count ("polymorphic-ref"))
- return;
-
- // Come up with a table alias. Generally, we want it to be based
- // on the column name. This is straightforward for single-column
- // references. In case of a composite id, we will need to use the
- // column prefix which is based on the data member name, unless
- // overridden by the user. In the latter case the prefix can be
- // empty, in which case we will just fall back on the member's
- // public name.
+ // Base type.
//
- string alias;
+ if (m == 0)
{
- string n;
-
- if (composite_wrapper (utype (*id_member (c))))
- {
- n = column_prefix (m, key_prefix_, default_name_);
+ object_columns_base::traverse_composite (m, c);
+ return;
+ }
- if (n.empty ())
- n = public_name_db (m);
- else
- n.resize (n.size () - 1); // Remove trailing underscore.
- }
- else
- n = column_name (m, key_prefix_, default_name_);
+ string old_scope (scope_);
+ scope_ += "::" + public_name (*m) + "_tag";
- alias = compose_name (column_prefix_, n);
- }
+ object_columns_base::traverse_composite (m, c);
- generate (alias, c);
+ scope_ = old_scope;
}
void query_alias_traits::
- generate (string const& alias, semantics::class_& c)
+ traverse_pointer (semantics::data_member& m, semantics::class_& c)
{
- string tag (escape (alias + "_alias_tag"));
+ // Ignore polymorphic id references.
+ //
+ if (m.count ("polymorphic-ref"))
+ return;
- if (tags_.find (tag) == tags_.end ())
+ if (decl_)
+ generate_decl (public_name (m), c);
+ else
{
- os << "class " << tag << ";"
- << endl;
+ // Come up with a table alias. Generally, we want it to be based
+ // on the column name. This is straightforward for single-column
+ // references. In case of a composite id, we will need to use the
+ // column prefix which is based on the data member name, unless
+ // overridden by the user. In the latter case the prefix can be
+ // empty, in which case we will just fall back on the member's
+ // public name.
+ //
+ string alias;
+ {
+ string n;
- tags_.insert (tag);
- }
+ if (composite_wrapper (utype (*id_member (c))))
+ {
+ n = column_prefix (m, key_prefix_, default_name_);
- // Generate the alias_traits specialization.
- //
- generate_specialization (alias, tag, c);
+ if (n.empty ())
+ n = public_name_db (m);
+ else
+ n.resize (n.size () - 1); // Remove trailing underscore.
+ }
+ else
+ n = column_name (m, key_prefix_, default_name_);
+
+ alias = compose_name (column_prefix_, n);
+ }
+
+ generate_def (public_name (m), c, alias);
+ }
}
void query_alias_traits::
- generate_specialization (string const& alias,
- string const& tag,
- semantics::class_& c)
+ generate_decl (string const& tag, semantics::class_& c)
{
- string const& fq_name (class_fq_name (c));
- string guard (
- make_guard ("ODB_" + string (db.string ()) + "_ALIAS_TRAITS_" +
- alias + "_FOR_" + flat_name (fq_name)));
-
- if (specs_.find (guard) != specs_.end ())
- return;
- else
- specs_.insert (guard);
-
semantics::class_* poly_root (polymorphic (c));
bool poly_derived (poly_root != 0 && poly_root != &c);
semantics::class_* poly_base (poly_derived ? &polymorphic_base (c) : 0);
if (poly_derived)
- generate_specialization (alias, tag, *poly_base);
-
- os << "#ifndef " << guard << endl
- << "#define " << guard << endl;
+ generate_decl (tag, *poly_base);
- os << "template <bool d>" << endl
- << "struct alias_traits< " << fq_name << ", id_" << db << ", " <<
- tag << ", d >"
+ os << "template <>" << endl
+ << "struct alias_traits<" << endl
+ << " " << class_fq_name (c) << "," << endl
+ << " id_" << db << "," << endl
+ << " " << scope_ << "::" << tag << "_tag>"
<< "{"
<< "static const char table_name[];";
if (poly_derived)
- os << "typedef alias_traits< " << class_fq_name (*poly_base) << ", " <<
- "id_" << db << ", " << tag << " > base_traits;";
+ os << endl
+ << "typedef alias_traits<" << endl
+ << " " << class_fq_name (*poly_base) << "," << endl
+ << " id_" << db << "," << endl
+ << " " << scope_ << "::" << tag << "_tag>" << endl
+ << "base_traits;";
os << "};";
+ }
+
+ void query_alias_traits::
+ generate_def (string const& tag, semantics::class_& c, string const& alias)
+ {
+ semantics::class_* poly_root (polymorphic (c));
+ bool poly_derived (poly_root != 0 && poly_root != &c);
+ semantics::class_* poly_base (poly_derived ? &polymorphic_base (c) : 0);
- os << "template <bool d>" << endl
- << "const char alias_traits< " << fq_name << ", id_" << db << ", " <<
- tag << ", d >::" << endl
+ if (poly_derived)
+ generate_def (tag, *poly_base, alias);
+
+ os << "const char alias_traits<"
+ << " " << class_fq_name (c) << "," << endl
+ << " id_" << db << "," << endl
+ << " " << scope_ << "::" << tag << "_tag>::" << endl
<< "table_name[] = ";
if (poly_root != 0)
@@ -129,25 +147,22 @@ namespace relational
os << strlit (quote_id (alias));
os << ";"
- << "#endif // " << guard << endl
<< endl;
}
-
// query_columns_base
//
query_columns_base::
- query_columns_base ()
- : decl_ (true)
+ query_columns_base (semantics::class_& c, bool decl)
+ : decl_ (decl)
{
- }
+ string const& n (class_fq_name (c));
- query_columns_base::
- query_columns_base (semantics::class_& c) //@@ context::{cur,top}_object
- : decl_ (false)
- {
- scope_ = "query_columns_base< " + class_fq_name (c) + ", id_" +
+ if (!decl)
+ scope_ = "query_columns_base< " + n + ", id_" + db.string () + " >";
+
+ tag_scope_ = "access::object_traits_impl< " + n + ", id_" +
db.string () + " >";
}
@@ -184,17 +199,25 @@ namespace relational
<< "struct " << name << "_base_"
<< "{";
+ string old_tag_scope (tag_scope_);
+ tag_scope_ += "::" + name + "_tag";
+
object_columns_base::traverse_composite (m, c);
+ tag_scope_ = old_tag_scope;
+
os << "};";
}
else
{
string old_scope (scope_);
+ string old_tag_scope (tag_scope_);
scope_ += "::" + name + "_base_";
+ tag_scope_ += "::" + name + "_tag";
object_columns_base::traverse_composite (m, c);
+ tag_scope_ = old_tag_scope;
scope_ = old_scope;
}
}
@@ -215,39 +238,13 @@ namespace relational
os << "// " << name << endl
<< "//" << endl;
- // Come up with a table alias. Generally, we want it to be based
- // on the column name. This is straightforward for single-column
- // references. In case of a composite id, we will need to use the
- // column prefix which is based on the data member name, unless
- // overridden by the user. In the latter case the prefix can be
- // empty, in which case we will just fall back on the member's
- // public name.
- //
- string alias;
- {
- string n;
-
- if (composite_wrapper (utype (*id_member (c))))
- {
- n = column_prefix (m, key_prefix_, default_name_);
-
- if (n.empty ())
- n = public_name_db (m);
- else
- n.resize (n.size () - 1); // Remove trailing underscore.
- }
- else
- n = column_name (m, key_prefix_, default_name_);
-
- alias = compose_name (column_prefix_, n);
- }
-
- string tag (escape (alias + "_alias_tag"));
string const& fq_name (class_fq_name (c));
os << "typedef" << endl
- << "odb::alias_traits< " << fq_name << ", id_" << db << ", " <<
- tag << " >" << endl
+ << "odb::alias_traits<" << endl
+ << " " << fq_name << "," << endl
+ << " id_" << db << "," << endl
+ << " " << tag_scope_ << "::" << name << "_tag>" << endl
<< name << "_alias_;"
<< endl;
diff --git a/odb/relational/common.hxx b/odb/relational/common.hxx
index b951d15..1e7143f 100644
--- a/odb/relational/common.hxx
+++ b/odb/relational/common.hxx
@@ -222,33 +222,32 @@ namespace relational
}
};
- // Generate alias tags and alias_traits specializations for pointers
- // in this objects.
+ // Generate alias_traits specializations for pointers in this objects.
//
struct query_alias_traits: object_columns_base, virtual context
{
typedef query_alias_traits base;
- query_alias_traits (std::set<string>& tags, std::set<string>& specs)
- : tags_ (tags), specs_ (specs) {}
+ query_alias_traits (semantics::class_&, bool decl);
virtual void
traverse_object (semantics::class_&);
virtual void
+ traverse_composite (semantics::data_member*, semantics::class_&);
+
+ virtual void
traverse_pointer (semantics::data_member&, semantics::class_&);
virtual void
- generate (string const& alias, semantics::class_&);
+ generate_decl (string const& tag, semantics::class_&);
- private:
- void
- generate_specialization (string const& alias,
- string const& tag,
- semantics::class_&);
+ virtual void
+ generate_def (string const& tag, semantics::class_&, string const& alias);
- std::set<string>& tags_;
- std::set<string>& specs_;
+ protected:
+ bool decl_;
+ string scope_;
};
//
@@ -257,8 +256,7 @@ namespace relational
{
typedef query_columns_base base;
- query_columns_base ();
- query_columns_base (semantics::class_&);
+ query_columns_base (semantics::class_&, bool decl);
virtual void
traverse_object (semantics::class_&);
@@ -272,6 +270,7 @@ namespace relational
protected:
bool decl_;
string scope_;
+ string tag_scope_;
};
//
diff --git a/odb/relational/header.cxx b/odb/relational/header.cxx
index 1295106..3c9cd5a 100644
--- a/odb/relational/header.cxx
+++ b/odb/relational/header.cxx
@@ -147,6 +147,22 @@ traverse_object (type& c)
}
//
+ // Query (abstract and concrete).
+ //
+
+ if (options.generate_query ())
+ {
+ // Generate object pointer tags.
+ //
+ if (has_a (c, test_pointer | exclude_base))
+ {
+ instance<query_tags> t;
+ t->traverse (c);
+ os << endl;
+ }
+ }
+
+ //
// Functions (abstract and concrete).
//
@@ -630,6 +646,7 @@ void relational::header::class1::
traverse_view (type& c)
{
string const& type (class_fq_name (c));
+ size_t obj_count (c.get<size_t> ("object-count"));
os << "// " << class_name (c) << endl
<< "//" << endl;
@@ -656,12 +673,41 @@ traverse_view (type& c)
// Query.
//
+ // Generate associated object tags.
+ //
+ if (obj_count != 0)
+ {
+ view_objects& objs (c.get<view_objects> ("objects"));
+
+ {
+ instance<query_tags> t;
+
+ bool gen (false);
+ for (view_objects::const_iterator i (objs.begin ());
+ i < objs.end ();
+ ++i)
+ {
+ if (i->kind != view_object::object)
+ continue; // Skip tables.
+
+ if (i->alias.empty ())
+ continue;
+
+ t->generate (i->alias);
+ gen = true;
+ }
+
+ if (gen)
+ os << endl;
+ }
+ }
+
// query_base_type and query_columns (definition generated by class2).
//
os << "typedef " << db << "::query_base query_base_type;"
<< "struct query_columns";
- if (c.get<size_t> ("object-count") == 0)
+ if (obj_count == 0)
os << "{"
<< "};";
else
diff --git a/odb/relational/header.hxx b/odb/relational/header.hxx
index c0e1e89..c2bf73e 100644
--- a/odb/relational/header.hxx
+++ b/odb/relational/header.hxx
@@ -142,6 +142,62 @@ namespace relational
};
//
+ // query_tags
+ //
+
+ struct query_tags: object_columns_base, virtual context
+ {
+ typedef query_tags base;
+
+ virtual void
+ traverse_object (semantics::class_& c)
+ {
+ names (c); // We don't want to traverse bases.
+ }
+
+ virtual void
+ traverse_composite (semantics::data_member* m, semantics::class_& c)
+ {
+ // Base type.
+ //
+ if (m == 0)
+ {
+ object_columns_base::traverse_composite (m, c);
+ return;
+ }
+
+ // Don't generate an empty struct if we don't have any pointers.
+ //
+ if (!has_a (c, test_pointer))
+ return;
+
+ os << "struct " << public_name (*m) << "_tag"
+ << "{";
+
+ object_columns_base::traverse_composite (m, c);
+
+ os << "};";
+ }
+
+ virtual void
+ traverse_pointer (semantics::data_member& m, semantics::class_&)
+ {
+ // Ignore polymorphic id references.
+ //
+ if (m.count ("polymorphic-ref"))
+ return;
+
+ generate (public_name (m));
+ }
+
+ virtual void
+ generate (string const& name)
+ {
+ os << "struct " << name << "_tag;";
+ }
+ };
+
+ //
// query_columns_type
//
@@ -305,7 +361,8 @@ namespace relational
db << " >"
<< "{";
- instance<query_columns_base> t;
+ bool true_ (true); //@@ (im)perfect forwarding.
+ instance<query_columns_base> t (c, true_);
t->traverse (c);
os << "};";
@@ -1072,7 +1129,8 @@ namespace relational
//
if (has_ptr)
{
- instance<query_alias_traits> t (alias_tags_, alias_specs_);
+ bool true_ (true); //@@ (im)perfect forwarding
+ instance<query_alias_traits> t (c, true_);
t->traverse (c);
query_columns_type_->traverse (c);
@@ -1098,10 +1156,11 @@ namespace relational
view_objects& objs (c.get<view_objects> ("objects"));
- // Generate the alias tags and alias_traits specializations.
+ // Generate alias_traits specializations.
//
{
- instance<query_alias_traits> at (alias_tags_, alias_specs_);
+ bool true_ (true); //@@ (im)perfect forwarding
+ instance<query_alias_traits> at (c, true_);
for (view_objects::const_iterator i (objs.begin ());
i < objs.end ();
@@ -1121,7 +1180,7 @@ namespace relational
// a prefix).
//
if (polymorphic (o) || t.qualified () || i->alias != t.uname ())
- at->generate (i->alias, o);
+ at->generate_decl (i->alias, o);
}
}
@@ -1156,9 +1215,10 @@ namespace relational
table.qualified () ||
i->alias != table.uname ()))
{
- string tag (escape (i->alias + "_alias_tag"));
- os << " odb::alias_traits< " << otype << ", id_" << db <<
- ", " << tag << " > >" << endl;
+ os << " odb::alias_traits< " << otype << "," << endl
+ << " id_" << db << "," << endl
+ << " access::view_traits_impl< " << type << ", id_" <<
+ db << " >::" << i->alias << "_tag> >" << endl;
}
else
os << " odb::access::object_traits_impl< " << otype <<
@@ -1198,9 +1258,11 @@ namespace relational
table.qualified () ||
vo->alias != table.uname ()))
{
- string tag (escape (vo->alias + "_alias_tag"));
- os << " odb::alias_traits< " << otype << ", id_" <<
- db << ", " << tag << " > >";
+ os << " odb::alias_traits<" << endl
+ << " " << otype << "," << endl
+ << " id_" << db << "," << endl
+ << " access::view_traits_impl< " << type << ", id_" <<
+ db << " >::" << vo->alias << "_tag> >";
}
else
os << " odb::access::object_traits_impl< " << otype <<
@@ -1221,9 +1283,6 @@ namespace relational
private:
instance<query_columns_type> query_columns_type_;
-
- std::set<string> alias_tags_;
- std::set<string> alias_specs_;
};
struct include: virtual context
diff --git a/odb/relational/source.cxx b/odb/relational/source.cxx
index 7fc3ce6..21c0f57 100644
--- a/odb/relational/source.cxx
+++ b/odb/relational/source.cxx
@@ -22,8 +22,6 @@ traverse_object (type& c)
bool base_id (id && &id->scope () != &c); // Comes from base.
member_access* id_ma (id ? &id->get<member_access> ("get") : 0);
- bool has_ptr (has_a (c, test_pointer));
-
data_member* opt (optimistic (c));
member_access* opt_ma_get (opt ? &opt->get<member_access> ("get") : 0);
member_access* opt_ma_set (opt ? &opt->get<member_access> ("set") : 0);
@@ -61,16 +59,30 @@ traverse_object (type& c)
object_extra (c);
//
- // Query.
+ // Query (abstract and concrete).
//
if (options.generate_query ())
{
+ bool has_ptr (has_a (c, test_pointer | exclude_base));
+
+ // Generate alias_traits specializations. While the class
+ // is generated even if our base has a pointer, there is
+ // not source code if we don't have pointers ourselves.
+ //
+ if (has_ptr)
+ {
+ bool false_ (false); //@@ (im)perfect forwarding
+ instance<query_alias_traits> t (c, false_);
+ t->traverse (c);
+ }
+
// query_columns_base
//
if (has_ptr)
{
- instance<query_columns_base> t (c);
+ bool false_ (false); //@@ (im)perfect forwarding.
+ instance<query_columns_base> t (c, false_);
t->traverse (c);
}
}
@@ -2865,6 +2877,39 @@ traverse_view (type& c)
view_extra (c);
+ if (c.get<size_t> ("object-count") != 0)
+ {
+ view_objects& objs (c.get<view_objects> ("objects"));
+
+ // Generate alias_traits specializations.
+ //
+ {
+ bool false_ (false); //@@ (im)perfect forwarding
+ instance<query_alias_traits> at (c, false_);
+
+ for (view_objects::const_iterator i (objs.begin ());
+ i < objs.end ();
+ ++i)
+ {
+ if (i->kind != view_object::object)
+ continue; // Skip tables.
+
+ if (i->alias.empty ())
+ continue;
+
+ semantics::class_& o (*i->obj);
+ qname const& t (table_name (o));
+
+ // Check that the alias is not the same as the table name
+ // (if this is a polymorphic object, then the alias is just
+ // a prefix).
+ //
+ if (polymorphic (o) || t.qualified () || i->alias != t.uname ())
+ at->generate_def (i->alias, o, i->alias);
+ }
+ }
+ }
+
//
// Functions.
//