aboutsummaryrefslogtreecommitdiff
path: root/common/session/custom/session.txx
blob: 65ab9336209c9042f5accc7c1ba08e4f403a6863 (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
// file      : common/session/custom/session.txx
// license   : GNU GPL v2; see accompanying LICENSE file

#include <cassert>

template <typename T>
typename session::cache_position<T> session::
_cache_insert (odb::database&,
               const typename odb::object_traits<T>::id_type& id,
               const typename odb::object_traits<T>::pointer_type& obj)
{
  if (current == 0)
    return cache_position<T> (); // No session, return empty position.

  std::shared_ptr<object_map_base>& pm (current->map_[&typeid (T)]);

  if (!pm)
    pm.reset (new object_map<T>);

  object_map<T>& m (static_cast<object_map<T>&> (*pm));

  typename object_map<T>::value_type vt (id, object_data<T> (obj));
  std::pair<typename object_map<T>::iterator, bool> r (m.insert (vt));

  // We shall never try to re-insert the same object into the cache.
  //
  assert (r.second);

  return cache_position<T> (m, r.first);
}

template <typename T>
typename odb::object_traits<T>::pointer_type session::
_cache_find (odb::database&, const typename odb::object_traits<T>::id_type& id)
{
  typedef typename odb::object_traits<T>::pointer_type pointer_type;

  if (current == 0)
    return pointer_type (); // No session, return NULL pointer.

  type_map::const_iterator ti (current->map_.find (&typeid (T)));

  if (ti == current->map_.end ())
    return pointer_type ();

  const object_map<T>& m (static_cast<const object_map<T>&> (*ti->second));
  typename object_map<T>::const_iterator oi (m.find (id));

  if (oi == m.end ())
    return pointer_type ();

  return oi->second.obj;
}

template <typename T>
void session::
_cache_load (const cache_position<T>& p)
{
  typedef typename odb::object_traits<T>::pointer_type pointer_type;

  if (p.map_ == 0)
    return; // Empty position.

  // Make a copy for change tracking. If our object model had a
  // polymorphic hierarchy, then we would have had to use a
  // virtual function-based mechanism (e.g., clone()) instead of
  // the copy constructor since for a polymorphic hierarchy all
  // the derived objects are stored as pointers to the root object.
  //
  p.pos_->second.orig = pointer_type (new T (*p.pos_->second.obj));
}

template <typename T>
void session::
_cache_update (odb::database&, const T& obj)
{
  typedef odb::object_traits<T> object_traits;
  typedef typename object_traits::pointer_type pointer_type;

  if (current == 0)
    return; // No session.

  // User explicitly updated the object by calling database::update().
  // Change the state to flushed and reset the original copy (we are
  // still tracking changes after the update).
  //
  type_map::iterator ti (current->map_.find (&typeid (T)));

  if (ti == current->map_.end ())
    return; // This object is not in the session.

  object_map<T>& m (static_cast<object_map<T>&> (*ti->second));
  typename object_map<T>::iterator oi (m.find (object_traits::id (obj)));

  if (oi == m.end ())
    return; // This object is not in the session.

  object_data<T>& d (oi->second);
  d.orig = pointer_type (new T (*d.obj));
  d.state = flushed;
}

template <typename T>
void session::
_cache_erase (odb::database&,
              const typename odb::object_traits<T>::id_type& id)
{
  if (current == 0)
    return; // No session.

  type_map::iterator ti (current->map_.find (&typeid (T)));

  if (ti == current->map_.end ())
    return;

  object_map<T>& m (static_cast<object_map<T>&> (*ti->second));
  typename object_map<T>::iterator oi (m.find (id));

  if (oi == m.end ())
    return;

  m.erase (oi);

  if (m.empty ())
    current->map_.erase (ti);
}

template <typename T>
bool session::object_map<T>::
flush (odb::database& db)
{
  bool r (false);
  for (typename object_map<T>::iterator i (this->begin ()), e (this->end ());
       i != e; ++i)
  {
    object_data<T>& d (i->second);

    if (d.state == changed || d.obj->changed (*d.orig))
      db.update (d.obj); // State changed by the update() notification.

    r = r || d.state == flushed;
  }

  return r;
}

template <typename T>
void session::object_map<T>::
mark (unsigned short event)
{
  for (typename object_map<T>::iterator i (this->begin ()), e (this->end ());
       i != e; ++i)
  {
    object_data<T>& d (i->second);

    if (d.state == flushed)
      d.state = event == odb::transaction::event_commit ? tracking : changed;
  }
}