aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2011-10-27 15:16:49 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2011-10-27 15:16:49 +0200
commit658a2f07b47ed80bd3ca35edd7380493c326daa3 (patch)
tree9df443d8820a2a53f6b8839adc36cde0c723f5cd
parentac2c76e2412ff332022215b71bb106c8ea6dd3d0 (diff)
Add support for persistent classes without object ids
New pragma id (object). New test: common/no-id.
-rw-r--r--odb/cache-traits.hxx127
-rw-r--r--odb/database.txx20
-rw-r--r--odb/object-result.hxx262
-rw-r--r--odb/object-result.txx41
-rw-r--r--odb/result.hxx5
-rw-r--r--odb/view-result.hxx10
-rw-r--r--odb/view-result.txx10
7 files changed, 398 insertions, 77 deletions
diff --git a/odb/cache-traits.hxx b/odb/cache-traits.hxx
index e4b2495..067812b 100644
--- a/odb/cache-traits.hxx
+++ b/odb/cache-traits.hxx
@@ -17,8 +17,19 @@ namespace odb
{
// Caching traits for objects passed by pointer.
//
- template <typename P, pointer_kind = pointer_traits<P>::kind>
- struct pointer_cache_traits
+ template <typename P, typename ID, pointer_kind kind>
+ struct pointer_cache_traits_impl;
+
+ template <typename P>
+ struct pointer_cache_traits: pointer_cache_traits_impl<
+ P,
+ typename object_traits<typename pointer_traits<P>::element_type>::id_type,
+ pointer_traits<P>::kind>
+ {
+ };
+
+ template <typename P, typename ID, pointer_kind kind>
+ struct pointer_cache_traits_impl
{
typedef P pointer_type;
typedef odb::pointer_traits<pointer_type> pointer_traits;
@@ -45,20 +56,36 @@ namespace odb
position_type pos_;
};
+ // We need the insert() overload with explicit id to handle self-
+ // references. In such cases the object is not yet loaded and the
+ // id member does not contain the correct id.
+ //
// Qualify the database type to resolve a phony ambiguity in VC 10.
//
static position_type
insert (odb::database& db, const id_type& id, const pointer_type& p)
{
if (session::has_current ())
+ {
// Cast away constness if any.
//
return session::current ().insert<object_type> (
db, id, pointer_traits::cast (p));
+ }
else
return position_type ();
}
+ static position_type
+ insert (odb::database& db, const pointer_type& p)
+ {
+ const id_type& id (
+ object_traits<object_type>::id (
+ pointer_traits::get_ref (p)));
+
+ return insert (db, id, p);
+ }
+
static pointer_type
find (odb::database& db, const id_type& id)
{
@@ -83,10 +110,23 @@ namespace odb
}
};
+ template <typename P, pointer_kind kind>
+ struct pointer_cache_traits_impl<P, void, kind>
+ {
+ typedef P pointer_type;
+ struct position_type {};
+
+ static position_type
+ insert (odb::database&, const pointer_type&)
+ {
+ return position_type ();
+ }
+ };
+
// Unique pointers don't work with the object cache.
//
- template <typename P>
- struct pointer_cache_traits<P, pk_unique>
+ template <typename P, typename ID>
+ struct pointer_cache_traits_impl<P, ID, pk_unique>
{
typedef P pointer_type;
typedef typename pointer_traits<pointer_type>::element_type element_type;
@@ -110,6 +150,12 @@ namespace odb
return position_type ();
}
+ static position_type
+ insert (odb::database&, const pointer_type&)
+ {
+ return position_type ();
+ }
+
static pointer_type
find (odb::database&, const id_type&) { return pointer_type (); }
@@ -120,13 +166,35 @@ namespace odb
erase (const position_type&) {}
};
+ template <typename P>
+ struct pointer_cache_traits_impl<P, void, pk_unique>
+ {
+ typedef P pointer_type;
+ struct position_type {};
+
+ static position_type
+ insert (odb::database&, const pointer_type&)
+ {
+ return position_type ();
+ }
+ };
+
// Caching traits for objects passed by reference. Only if the object
// pointer kind is raw do we add the object to the session.
//
- template <typename T,
- pointer_kind =
- pointer_traits<typename object_traits<T>::pointer_type>::kind>
- struct reference_cache_traits
+ template <typename T, typename ID, pointer_kind kind>
+ struct reference_cache_traits_impl;
+
+ template <typename T>
+ struct reference_cache_traits: reference_cache_traits_impl<
+ T,
+ typename object_traits<T>::id_type,
+ pointer_traits<typename object_traits<T>::pointer_type>::kind>
+ {
+ };
+
+ template <typename T, typename ID, pointer_kind kind>
+ struct reference_cache_traits_impl
{
typedef T element_type;
typedef typename object_traits<element_type>::pointer_type pointer_type;
@@ -152,10 +220,29 @@ namespace odb
{
return position_type ();
}
+
+ static position_type
+ insert (odb::database&, element_type&)
+ {
+ return position_type ();
+ }
};
- template <typename T>
- struct reference_cache_traits<T, pk_raw>
+ template <typename T, pointer_kind kind>
+ struct reference_cache_traits_impl<T, void, kind>
+ {
+ typedef T element_type;
+ struct position_type {};
+
+ static position_type
+ insert (odb::database&, element_type&)
+ {
+ return position_type ();
+ }
+ };
+
+ template <typename T, typename ID>
+ struct reference_cache_traits_impl<T, ID, pk_raw>
{
typedef T element_type;
typedef typename object_traits<element_type>::pointer_type pointer_type;
@@ -175,6 +262,26 @@ namespace odb
pointer_type p (&obj);
return pointer_cache_traits<pointer_type>::insert (db, id, p);
}
+
+ static position_type
+ insert (odb::database& db, element_type& obj)
+ {
+ pointer_type p (&obj);
+ return pointer_cache_traits<pointer_type>::insert (db, p);
+ }
+ };
+
+ template <typename T>
+ struct reference_cache_traits_impl<T, void, pk_raw>
+ {
+ typedef T element_type;
+ struct position_type {};
+
+ static position_type
+ insert (odb::database&, element_type&)
+ {
+ return position_type ();
+ }
};
}
diff --git a/odb/database.txx b/odb/database.txx
index c70697d..42643aa 100644
--- a/odb/database.txx
+++ b/odb/database.txx
@@ -28,9 +28,9 @@ namespace odb
object_traits::persist (*this, obj);
object_traits::callback (*this, obj, callback_event::post_persist);
- const typename object_traits::id_type& id (object_traits::id (obj));
- reference_cache_traits<T>::insert (*this, id, obj);
- return id;
+ reference_cache_traits<T>::insert (*this, obj);
+
+ return object_traits::id (obj);
}
template <typename T>
@@ -54,9 +54,9 @@ namespace odb
object_traits::persist (*this, obj);
object_traits::callback (*this, obj, callback_event::post_persist);
- const typename object_traits::id_type& id (object_traits::id (obj));
- pointer_cache_traits<pointer_type>::insert (*this, id, pobj);
- return id;
+ pointer_cache_traits<pointer_type>::insert (*this, pobj);
+
+ return object_traits::id (obj);
}
template <typename T>
@@ -139,8 +139,8 @@ namespace odb
object_traits::callback (*this, obj,callback_event::pre_update);
- // Compiler error pointing here? Perhaps the object is readonly and
- // therefore does not provide the update() function?
+ // Compiler error pointing here? Perhaps the object is readonly or
+ // doesn't have an object id? Such objects cannot be updated.
//
object_traits::update (*this, obj);
@@ -166,8 +166,8 @@ namespace odb
object_traits::callback (*this, obj, callback_event::pre_update);
- // Compiler error pointing here? Perhaps the object is readonly and
- // therefore does not provide the update() function?
+ // Compiler error pointing here? Perhaps the object is readonly or
+ // doesn't have an object id? Such objects cannot be updated.
//
object_traits::update (*this, obj);
diff --git a/odb/object-result.hxx b/odb/object-result.hxx
index 4c25962..e4d28ee 100644
--- a/odb/object-result.hxx
+++ b/odb/object-result.hxx
@@ -20,30 +20,158 @@
namespace odb
{
template <typename T>
- class result_impl<T, class_object>: public details::shared_base
+ class object_result_impl;
+
+ template <typename T>
+ class object_result_impl_no_id;
+
+ template <typename T, typename ID>
+ class object_result_iterator;
+
+ template <typename T, typename ID = typename object_traits<T>::id_type>
+ struct object_result_impl_selector
+ {
+ typedef object_result_impl<T> type;
+ };
+
+ template <typename T>
+ struct object_result_impl_selector<T, void>
+ {
+ typedef object_result_impl_no_id<T> type;
+ };
+
+ // Implementation for objects with object id.
+ //
+ template <typename T>
+ class object_result_impl: public details::shared_base
{
public:
virtual
- ~result_impl ();
+ ~object_result_impl ();
protected:
+ typedef odb::database database_type;
+
+ // In result_impl, T is always non-const and the same as object_type.
+ //
+ typedef T object_type;
+ typedef odb::object_traits<object_type> object_traits;
+ typedef typename object_traits::id_type id_type;
+
+ typedef typename object_traits::pointer_type pointer_type;
+ typedef odb::pointer_traits<pointer_type> pointer_traits;
+
friend class result<T>;
friend class result<const T>;
friend class result_iterator<T, class_object>;
friend class result_iterator<const T, class_object>;
+ friend class object_result_iterator<T, id_type>;
+ friend class object_result_iterator<const T, id_type>;
+
+ protected:
+ object_result_impl (database_type& db)
+ : begin_ (true), end_ (false), db_ (db), current_ ()
+ {
+ }
+
+ database_type&
+ database () const
+ {
+ return db_;
+ }
+
+ // To make this work with all kinds of pointers (raw, std::auto_ptr,
+ // shared), we need to make sure we don't make any copies of the
+ // pointer on the return path.
+ //
+ pointer_type&
+ current ();
+
+ void
+ release ()
+ {
+ current_ = pointer_type ();
+ guard_.release ();
+ }
+
+ void
+ begin ()
+ {
+ if (begin_)
+ {
+ next ();
+ begin_ = false;
+ }
+ }
+
+ bool
+ end () const
+ {
+ return end_;
+ }
+
+ protected:
+ virtual void
+ load (object_type&) = 0;
+
+ virtual id_type
+ load_id () = 0;
+
+ virtual void
+ next () = 0;
+
+ virtual void
+ cache () = 0;
+
+ virtual std::size_t
+ size () = 0;
+
+ protected:
+ void
+ current (pointer_type p)
+ {
+ current_ = p;
+ guard_.reset (current_);
+ }
+
+ bool begin_;
+ bool end_;
+
+ private:
+ database_type& db_;
+ pointer_type current_;
+ typename pointer_traits::guard guard_;
+ };
+
+ // Implementation for objects without object id.
+ //
+ template <typename T>
+ class object_result_impl_no_id: public details::shared_base
+ {
+ public:
+ virtual
+ ~object_result_impl_no_id ();
+ protected:
typedef odb::database database_type;
// In result_impl, T is always non-const and the same as object_type.
//
typedef T object_type;
typedef odb::object_traits<object_type> object_traits;
- typedef typename object_traits::id_type id_type;
typedef typename object_traits::pointer_type pointer_type;
typedef odb::pointer_traits<pointer_type> pointer_traits;
- result_impl (database_type& db)
+ friend class result<T>;
+ friend class result<const T>;
+ friend class result_iterator<T, class_object>;
+ friend class result_iterator<const T, class_object>;
+ friend class object_result_iterator<T, void>;
+ friend class object_result_iterator<const T, void>;
+
+ protected:
+ object_result_impl_no_id (database_type& db)
: begin_ (true), end_ (false), db_ (db), current_ ()
{
}
@@ -88,9 +216,6 @@ namespace odb
virtual void
load (object_type&) = 0;
- virtual id_type
- load_id () = 0;
-
virtual void
next () = 0;
@@ -117,8 +242,85 @@ namespace odb
typename pointer_traits::guard guard_;
};
+ //
+ // result_iterator
+ //
+
+ template <typename T, typename ID>
+ class object_result_iterator
+ {
+ public:
+ // T can be const T while object_type is always non-const.
+ //
+ typedef typename object_traits<T>::object_type object_type;
+ typedef typename object_traits<T>::id_type id_type;
+
+ typedef object_result_impl<object_type> result_impl_type;
+
+ public:
+ object_result_iterator (result_impl_type* res)
+ : res_ (res)
+ {
+ }
+
+ public:
+ typename object_traits<T>::pointer_type
+ load ()
+ {
+ typename object_traits<T>::pointer_type r (res_->current ());
+ res_->release ();
+ return r;
+ }
+
+ void
+ load (object_type&);
+
+ protected:
+ result_impl_type* res_;
+ };
+
template <typename T>
- class result_iterator<T, class_object>
+ class object_result_iterator<T, void>
+ {
+ public:
+ // T can be const T while object_type is always non-const.
+ //
+ typedef typename object_traits<T>::object_type object_type;
+
+ typedef object_result_impl_no_id<object_type> result_impl_type;
+
+ public:
+ object_result_iterator (result_impl_type* res)
+ : res_ (res)
+ {
+ }
+
+ public:
+ typename object_traits<T>::pointer_type
+ load ()
+ {
+ typename object_traits<T>::pointer_type r (res_->current ());
+ res_->release ();
+ return r;
+ }
+
+ void
+ load (object_type& obj)
+ {
+ // Objects without ids are not stored in session cache.
+ //
+ if (!res_->end ())
+ res_->load (obj);
+ }
+
+ protected:
+ result_impl_type* res_;
+ };
+
+ template <typename T>
+ class result_iterator<T, class_object>: public object_result_iterator<
+ T,
+ typename object_traits<T>::id_type>
{
public:
typedef T value_type;
@@ -129,15 +331,14 @@ namespace odb
// T can be const T while object_type is always non-const.
//
- typedef typename object_traits<T>::object_type object_type;
- typedef typename object_traits<T>::id_type id_type;
-
- typedef result_impl<object_type, class_object> result_impl_type;
+ typedef
+ object_result_iterator<T, typename object_traits<T>::id_type>
+ base_type;
public:
explicit
- result_iterator (result_impl_type* res = 0)
- : res_ (res)
+ result_iterator (typename base_type::result_impl_type* res = 0)
+ : base_type (res)
{
}
@@ -147,7 +348,7 @@ namespace odb
reference
operator* () const
{
- return pointer_traits::get_ref (res_->current ());
+ return pointer_traits::get_ref (this->res_->current ());
}
// Our value_type is already a pointer so return it instead of
@@ -157,13 +358,13 @@ namespace odb
pointer
operator-> () const
{
- return pointer_traits::get_ptr (res_->current ());
+ return pointer_traits::get_ptr (this->res_->current ());
}
result_iterator&
operator++ ()
{
- res_->next ();
+ this->res_->next ();
return *this;
}
@@ -172,27 +373,16 @@ namespace odb
{
// All non-end iterators for a result object move together.
//
- res_->next ();
+ this->res_->next ();
return *this;
}
public:
- typename object_traits<T>::pointer_type
- load ()
- {
- typename object_traits<T>::pointer_type r (res_->current ());
- res_->release ();
- return r;
- }
-
- void
- load (object_type&);
-
- public:
bool
equal (result_iterator j) const
{
- return (res_ ? res_->end () : true) == (j.res_ ? j.res_->end () : true);
+ return (this->res_ ? this->res_->end () : true) ==
+ (j.res_ ? j.res_->end () : true);
}
private:
@@ -200,10 +390,10 @@ namespace odb
// result_impl.
//
typedef
- odb::pointer_traits<typename object_traits<object_type>::pointer_type>
+ odb::pointer_traits<
+ typename object_traits<
+ typename base_type::object_type>::pointer_type>
pointer_traits;
-
- result_impl_type* res_;
};
//
@@ -217,7 +407,9 @@ namespace odb
// T can be const T while object_type is always non-const.
//
typedef typename object_traits<T>::object_type object_type;
- typedef result_impl<object_type, class_object> result_impl_type;
+ typedef
+ typename object_result_impl_selector<object_type>::type
+ result_impl_type;
};
}
diff --git a/odb/object-result.txx b/odb/object-result.txx
index c19e482..843ec59 100644
--- a/odb/object-result.txx
+++ b/odb/object-result.txx
@@ -9,18 +9,18 @@
namespace odb
{
//
- // result_impl
+ // object_result_impl
//
template <typename T>
- result_impl<T, class_object>::
- ~result_impl ()
+ object_result_impl<T>::
+ ~object_result_impl ()
{
}
template <typename T>
- typename result_impl<T, class_object>::pointer_type&
- result_impl<T, class_object>::
+ typename object_result_impl<T>::pointer_type&
+ object_result_impl<T>::
current ()
{
if (pointer_traits::null_ptr (current_) && !end_)
@@ -62,11 +62,38 @@ namespace odb
}
//
- // result_iterator
+ // object_result_impl_no_id
//
+ template <typename T>
+ object_result_impl_no_id<T>::
+ ~object_result_impl_no_id ()
+ {
+ }
template <typename T>
- void result_iterator<T, class_object>::
+ typename object_result_impl_no_id<T>::pointer_type&
+ object_result_impl_no_id<T>::
+ current ()
+ {
+ if (pointer_traits::null_ptr (current_) && !end_)
+ {
+ // Objects without ids are not stored in session cache.
+ //
+ pointer_type p (object_traits::create ());
+ object_type& obj (pointer_traits::get_ref (p));
+ current (p);
+ load (obj);
+ }
+
+ return current_;
+ }
+
+ //
+ // object_result_iterator
+ //
+
+ template <typename T, typename ID>
+ void object_result_iterator<T, ID>::
load (object_type& obj)
{
if (res_->end ())
diff --git a/odb/result.hxx b/odb/result.hxx
index 1d4a199..91c1a39 100644
--- a/odb/result.hxx
+++ b/odb/result.hxx
@@ -18,9 +18,6 @@ namespace odb
template <typename T, class_kind kind>
class result_base;
- template <typename T, class_kind kind>
- class result_impl;
-
template <typename T, class_kind kind = class_traits<T>::kind>
class result_iterator;
@@ -59,8 +56,6 @@ namespace odb
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
- // T can be const T while result_impl's argument is always non-const.
- //
typedef typename base::result_impl_type result_impl_type;
public:
diff --git a/odb/view-result.hxx b/odb/view-result.hxx
index a3cebf8..3f5a043 100644
--- a/odb/view-result.hxx
+++ b/odb/view-result.hxx
@@ -20,11 +20,11 @@
namespace odb
{
template <typename T>
- class result_impl<T, class_view>: public details::shared_base
+ class view_result_impl: public details::shared_base
{
public:
virtual
- ~result_impl ();
+ ~view_result_impl ();
protected:
friend class result<T>;
@@ -42,7 +42,7 @@ namespace odb
typedef typename view_traits::pointer_type pointer_type;
typedef odb::pointer_traits<pointer_type> pointer_traits;
- result_impl (database_type& db)
+ view_result_impl (database_type& db)
: begin_ (true), end_ (false), db_ (db), current_ ()
{
}
@@ -127,7 +127,7 @@ namespace odb
//
typedef typename view_traits<T>::view_type view_type;
- typedef result_impl<view_type, class_view> result_impl_type;
+ typedef view_result_impl<view_type> result_impl_type;
public:
explicit
@@ -212,7 +212,7 @@ namespace odb
// T can be const T while view_type is always non-const.
//
typedef typename view_traits<T>::view_type view_type;
- typedef result_impl<view_type, class_view> result_impl_type;
+ typedef view_result_impl<view_type> result_impl_type;
};
}
diff --git a/odb/view-result.txx b/odb/view-result.txx
index 95f34e0..afc65b4 100644
--- a/odb/view-result.txx
+++ b/odb/view-result.txx
@@ -6,18 +6,18 @@
namespace odb
{
//
- // result_impl
+ // view_result_impl
//
template <typename T>
- result_impl<T, class_view>::
- ~result_impl ()
+ view_result_impl<T>::
+ ~view_result_impl ()
{
}
template <typename T>
- typename result_impl<T, class_view>::pointer_type&
- result_impl<T, class_view>::
+ typename view_result_impl<T>::pointer_type&
+ view_result_impl<T>::
current ()
{
if (pointer_traits::null_ptr (current_) && !end_)