aboutsummaryrefslogtreecommitdiff
path: root/common/session/custom/session.hxx
blob: 3b1789a3df92579ad4b800463a36ebeda58d3f93 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// file      : common/session/custom/session.hxx
// copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC
// license   : GNU GPL v2; see accompanying LICENSE file

#ifndef SESSION_HXX
#define SESSION_HXX

#include <map>
#include <memory>
#include <typeinfo>

#include <odb/database.hxx>
#include <odb/traits.hxx>            // odb::object_traits
#include <odb/details/type-info.hxx> // odb::details::type_info_comparator

// This custom session implementation assumes we are working with
// one database at a time.
//
class session
{
public:
  session ();
  ~session ();

private:
  session (const session&);
  session& operator= (const session&);

  // Session for the current thread. This can be implemented in pretty
  // much any way that makes sense to the application. It can be a global
  // session as we have here. In multi-threaded applications we could use
  // TLS instead.
  //
public:
  static session* current;

  // Change tracking interface.
  //
  // Call flush() within a transaction to apply the changes to the
  // database. Then after successfully committing the transaction,
  // call mark() to mark all the changed objects as again unchanged.
  //
public:
  void
  flush (odb::database&);

  void
  mark ();

private:
  struct object_map_base
  {
    virtual
    ~object_map_base () {}

    virtual void
    flush (odb::database&) = 0;

    virtual void
    mark () = 0;
  };

  enum object_state
  {
    tracking, // Tracking any modifications by storing the original copy.
    changed,  // Known to be changed.
    flushed   // Flushed but not yet committed/rolled back.
  };

  template <typename T>
  struct object_data
  {
    typedef typename odb::object_traits<T>::pointer_type pointer_type;

    explicit
    object_data (pointer_type o): obj (o), state (tracking) {}

    pointer_type obj;
    pointer_type orig;
    object_state state;
  };

  template <typename T>
  struct object_map: object_map_base,
                     std::map<typename odb::object_traits<T>::id_type,
                              object_data<T> >
  {
    virtual void
    flush (odb::database&);

    virtual void
    mark ();
  };

  // Object cache interface.
  //
public:
  template <typename T>
  struct position
  {
    typedef object_map<T> map;
    typedef typename map::iterator iterator;

    position (): map_ (0) {}
    position (map& m, const iterator& p): map_ (&m), pos_ (p) {}

    map* map_;
    iterator pos_;
  };

  // Cache management.
  //
  template <typename T>
  static position<T>
  insert (odb::database&,
          const typename odb::object_traits<T>::id_type&,
          const typename odb::object_traits<T>::pointer_type&);

  template <typename T>
  static typename odb::object_traits<T>::pointer_type
  find (odb::database&, const typename odb::object_traits<T>::id_type&);

  template <typename T>
  static void
  erase (const position<T>& p)
  {
    if (p.map_ != 0)
      p.map_->erase (p.pos_);
  }

  // Notifications.
  //
  template <typename T>
  static void
  persist (const position<T>& p)
  {
    load (p);
  }

  template <typename T>
  static void
  load (const position<T>&);

  template <typename T>
  static void
  update (odb::database&, const T&);

  template <typename T>
  static void
  erase (odb::database&, const typename odb::object_traits<T>::id_type&);

private:
  typedef std::map<const std::type_info*,
                   std::shared_ptr<object_map_base>,
                   odb::details::type_info_comparator> type_map;
  type_map map_;
};

#include "session.txx"

#endif // SESSION_HXX