From 7082f3a11bcbba197b8fbc3c825b58b8b3875345 Mon Sep 17 00:00:00 2001
From: Boris Kolpackov <boris@codesynthesis.com>
Date: Thu, 4 Aug 2011 13:29:42 +0200
Subject: Add support for value wrappers

Wrapper is a class that wraps another type. Examples of wrappers are
various smart pointers, holders, etc. A wrapper can be transparent or
it can handle the NULL semantics.

The new odb::nullable class template is a NULL wrapper that helps
to add the NULL semantics to a value type.

New test: common/wrapper.
---
 odb/sqlite/traits.hxx | 119 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 118 insertions(+), 1 deletion(-)

diff --git a/odb/sqlite/traits.hxx b/odb/sqlite/traits.hxx
index 8863fb1..e2a4a4d 100644
--- a/odb/sqlite/traits.hxx
+++ b/odb/sqlite/traits.hxx
@@ -13,7 +13,10 @@
 #include <cstddef> // std::size_t
 
 #include <odb/traits.hxx>
+#include <odb/wrapper-traits.hxx>
+
 #include <odb/details/buffer.hxx>
+#include <odb/details/wrapper-p.hxx>
 
 #include <odb/sqlite/version.hxx>
 #include <odb/sqlite/details/export.hxx>
@@ -53,12 +56,126 @@ namespace odb
     // value_traits
     //
 
+    template <typename W, database_type_id, bool null_handler>
+    struct wrapped_value_traits;
+
     template <typename T, database_type_id>
     struct default_value_traits;
 
+    template <typename T, database_type_id, bool w = details::wrapper_p<T>::r>
+    struct select_traits;
+
+    template <typename T, database_type_id ID>
+    struct select_traits<T, ID, false>
+    {
+      typedef default_value_traits<T, ID> type;
+    };
+
+    template <typename W, database_type_id ID>
+    struct select_traits<W, ID, true>
+    {
+      typedef
+      wrapped_value_traits<W, ID, wrapper_traits<W>::null_handler>
+      type;
+    };
+
     template <typename T, database_type_id ID>
-    class value_traits: public default_value_traits<T, ID>
+    class value_traits: public select_traits<T, ID>::type
+    {
+    };
+
+    // The wrapped_value_traits specializations should be able to handle
+    // any value type which means we have to have every possible signature
+    // of the set_value() and set_image() functions.
+    //
+    template <typename W, database_type_id ID>
+    struct wrapped_value_traits<W, ID, false>
     {
+      typedef wrapper_traits<W> wtraits;
+      typedef typename wtraits::wrapped_type wrapped_type;
+
+      typedef W value_type;
+      typedef wrapped_type query_type;
+      typedef typename image_traits<ID>::image_type image_type;
+
+      typedef value_traits<wrapped_type, ID> vtraits;
+
+      static void
+      set_value (W& v, const image_type& i, bool is_null)
+      {
+        vtraits::set_value (wtraits::set_ref (v), i, is_null);
+      }
+
+      static void
+      set_image (image_type& i, bool& is_null, const W& v)
+      {
+        vtraits::set_image (i, is_null, wtraits::get_ref (v));
+      }
+
+      // TEXT and BLOB.
+      //
+      static void
+      set_value (W& v, const details::buffer& b, std::size_t n, bool is_null)
+      {
+        vtraits::set_value (wtraits::set_ref (v), b, n, is_null);
+      }
+
+      static void
+      set_image (details::buffer& b, std::size_t& n, bool& is_null, const W& v)
+      {
+        vtraits::set_image (b, n, is_null, wtraits::get_ref (v));
+      }
+    };
+
+    template <typename W, database_type_id ID>
+    struct wrapped_value_traits<W, ID, true>
+    {
+      typedef wrapper_traits<W> wtraits;
+      typedef typename wtraits::wrapped_type wrapped_type;
+
+      typedef W value_type;
+      typedef wrapped_type query_type;
+      typedef typename image_traits<ID>::image_type image_type;
+
+      typedef value_traits<wrapped_type, ID> vtraits;
+
+      static void
+      set_value (W& v, const image_type& i, bool is_null)
+      {
+        if (is_null)
+          wtraits::set_null (v);
+        else
+          vtraits::set_value (wtraits::set_ref (v), i, is_null);
+      }
+
+      static void
+      set_image (image_type& i, bool& is_null, const W& v)
+      {
+        is_null = wtraits::get_null (v);
+
+        if (!is_null)
+          vtraits::set_image (i, is_null, wtraits::get_ref (v));
+      }
+
+      // TEXT and BLOB.
+      //
+      static void
+      set_value (W& v, const details::buffer& b, std::size_t n, bool is_null)
+      {
+        if (is_null)
+          wtraits::set_null (v);
+        else
+          vtraits::set_value (wtraits::set_ref (v), b, n, is_null);
+      }
+
+      static void
+      set_image (details::buffer& b, std::size_t& n, bool& is_null, const W& v)
+      {
+        is_null = wtraits::get_null (v);
+
+        if (!is_null)
+          vtraits::set_image (b, n, is_null, wtraits::get_ref (v));
+      }
     };
 
     template <typename T, database_type_id ID>
-- 
cgit v1.1