diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2015-07-03 18:23:51 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2015-07-03 18:23:51 +0200 |
commit | 80b868be1e7c249daa714b0c7a5f87694edb8664 (patch) | |
tree | d8e0dd6eca09d33d70224f7289ae096a0976cd6b /odb/validator.cxx | |
parent | 89ba09f073b103953c53e63bd78f644973d9154e (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.cxx | 79 |
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 () |