summaryrefslogtreecommitdiff
path: root/odb/validator.cxx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-07-03 18:23:51 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-07-03 18:23:51 +0200
commit80b868be1e7c249daa714b0c7a5f87694edb8664 (patch)
treed8e0dd6eca09d33d70224f7289ae096a0976cd6b /odb/validator.cxx
parent89ba09f073b103953c53e63bd78f644973d9154e (diff)
Implement nested id support
Now the 'id' specifier can optionally include the data member path to the id inside the composite value. For example: #pragma db id(first) std::pair<int, int> p; Note that one somewhat counter-intuitive aspect of this new feature is that the whole member marked with id ('p' in the above example) and not just the actual id member ('p.first' in the above example) is treated as readonly. Such nested id also cannot be automatically assigned (auto specifier).
Diffstat (limited to 'odb/validator.cxx')
-rw-r--r--odb/validator.cxx79
1 files changed, 61 insertions, 18 deletions
diff --git a/odb/validator.cxx b/odb/validator.cxx
index a76848f..c1d82c6 100644
--- a/odb/validator.cxx
+++ b/odb/validator.cxx
@@ -12,6 +12,7 @@
#include <odb/context.hxx>
#include <odb/diagnostics.hxx>
#include <odb/validator.hxx>
+#include <odb/cxx-lexer.hxx>
#include <odb/relational/validator.hxx>
@@ -346,7 +347,7 @@ namespace
virtual void
traverse (semantics::data_member& m)
{
- if (id (m))
+ if (m.count ("id"))
{
if (id_ == 0)
id_ = &m;
@@ -605,8 +606,10 @@ namespace
// Check special members.
//
- semantics::data_member* id (0);
- semantics::data_member* optimistic (0);
+ using semantics::data_member;
+
+ data_member* id (0);
+ data_member* optimistic (0);
{
special_members t (class_object, valid_, id, optimistic);
t.traverse (c);
@@ -636,39 +639,75 @@ namespace
}
else
{
- c.set ("id-member", id);
+ // Convert id to a member path. This has to happen early since
+ // a lot of code that runs next (e.g., processor, pass 1) depends
+ // on this information being available.
+ //
+ data_member_path& idp (c.set ("id-member", data_member_path ()));
+ idp.push_back (id);
+
+ // See if we have a member path that we need to resolve.
+ //
+ const string& name (id->get<string> ("id"));
+ location_t l (id->get<location_t> ("id-location"));
+
+ if (!name.empty ())
+ {
+ if (id->count ("auto"))
+ {
+ error (l) << "nested id cannot be automatically assigned" << endl;
+ valid_ = false;
+ }
+
+ if (semantics::class_* comp = utype (*id).is_a<semantics::class_> ())
+ {
+ try
+ {
+ resolve_data_members (idp, *comp, name, l, lex_);
+ }
+ catch (const operation_failed&) {valid_ = false;}
+ }
+ else
+ {
+ error (l) << "nested id requires composite member" << endl;
+ valid_ = false;
+ }
+
+ // Mark the whole member as readonly.
+ //
+ id->set ("readonly", true);
+ }
+
+ data_member* idf (idp.front ());
+ data_member* idb (idp.back ());
// Complain if an id member has a default value (default value
// for the id's type is ok -- we will ignore it).
//
- if (id->count ("default"))
+ if (idb->count ("default"))
{
- os << id->file () << ":" << id->line () << ":" << id->column ()
- << ": error: object id member cannot have default value" << endl;
+ error (l) << "object id member cannot have default value" << endl;
valid_ = false;
}
// Complain if an id member is in a section.
//
- if (id->count ("section-member"))
+ if (idf->count ("section-member"))
{
- os << id->file () << ":" << id->line () << ":" << id->column ()
- << ": error: object id member cannot be in a section" << endl;
+ error (l) << "object id member cannot be in a section" << endl;
valid_ = false;
}
// Automatically mark the id member as not null. If we already have
// an explicit null pragma for this member, issue an error.
//
- if (id->count ("null"))
+ if (idb->count ("null"))
{
- os << id->file () << ":" << id->line () << ":" << id->column ()
- << ": error: object id member cannot be null" << endl;
-
+ error (l) << "object id member cannot be null" << endl;
valid_ = false;
}
else
- id->set ("not-null", true);
+ idf->set ("not-null", true);
}
if (optimistic != 0)
@@ -1021,6 +1060,8 @@ namespace
value_type vt_;
data_member1 member_;
traversal::names names_member_;
+
+ cxx_string_lexer lex_;
};
//
@@ -1080,7 +1121,7 @@ namespace
// Make sure the pointed-to class has object id unless it is in a
// view where we can load no-id objects.
//
- if (semantics::data_member* id = id_member (*c))
+ if (data_member_path* id = id_member (*c))
{
semantics::type& idt (utype (*id));
@@ -1437,7 +1478,7 @@ namespace
}
}
- if (semantics::data_member* id = id_member (c))
+ if (data_member_path* id = id_member (c))
{
semantics::type& t (utype (*id));
@@ -1478,6 +1519,8 @@ namespace
if (!v)
{
+ semantics::data_member& idm (*id->front ());
+
os << t.file () << ":" << t.line () << ":" << t.column ()
<< ": error: value type that is used as object id in "
<< "persistent class with session support does not define "
@@ -1486,7 +1529,7 @@ namespace
os << t.file () << ":" << t.line () << ":" << t.column ()
<< ": info: provide operator< for this value type" << endl;
- os << id->file () << ":" << id->line () << ":" << id->column ()
+ os << idm.file () << ":" << idm.line () << ":" << idm.column ()
<< ": info: id member is defined here" << endl;
os << c.file () << ":" << c.line () << ":" << c.column ()