aboutsummaryrefslogtreecommitdiff
path: root/bpkg/database.hxx
blob: 21fc8f7fdd41381ac4317caf9c6ea92774c08ad2 (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
// file      : bpkg/database.hxx -*- C++ -*-
// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd
// license   : MIT; see accompanying LICENSE file

#ifndef BPKG_DATABASE_HXX
#define BPKG_DATABASE_HXX

#include <type_traits> // remove_reference

#include <odb/query.hxx>
#include <odb/result.hxx>
#include <odb/session.hxx>

#include <odb/sqlite/database.hxx>

#include <bpkg/types.hxx>
#include <bpkg/utility.hxx>

#include <bpkg/diagnostics.hxx>

namespace bpkg
{
  using odb::query;
  using odb::result;
  using odb::session;

  using odb::sqlite::database;

  // Transaction wrapper that allow the creation of dummy transactions (start
  // is false) that in reality use an existing transaction.
  //
  struct transaction
  {
    using database_type = bpkg::database;

    explicit
    transaction (database_type& db, bool start = true)
        : db_ (db), start_ (start), t_ () // Finalized.
    {
      if (start)
        t_.reset (db.begin ());
    }

    void
    commit ()
    {
      if (start_)
        t_.commit ();
    }

    void
    rollback ()
    {
      if (start_)
        t_.rollback ();
    }

    database_type&
    database ()
    {
      return db_;
    }

    static bool
    has_current ()
    {
      return odb::sqlite::transaction::has_current ();
    }

    static odb::sqlite::transaction&
    current ()
    {
      return odb::sqlite::transaction::current ();
    }

  private:
    database_type& db_;
    bool start_;
    odb::sqlite::transaction t_;
  };

  database
  open (const dir_path& configuration, tracer&, bool create = false);

  struct tracer_guard
  {
    tracer_guard (database& db, tracer& t)
        : db_ (db), t_ (db.tracer ()) {db.tracer (t);}
    ~tracer_guard () {db_.tracer (*t_);}

  private:
    database& db_;
    odb::tracer* t_;
  };

  // Range-based for-loop iteration over query result that returns
  // object pointers. For example:
  //
  // for (shared_ptr<object> o: pointer_result (db.query<object> (...)))
  //
  template <typename R>
  class pointer_result_range
  {
    R r_;

  public:
    pointer_result_range (R&& r): r_ (forward<R> (r)) {}

    using base_iterator = typename std::remove_reference<R>::type::iterator;

    struct iterator: base_iterator
    {
      iterator () = default;

      explicit
      iterator (base_iterator i): base_iterator (move (i)) {}

      typename base_iterator::pointer_type
      operator* () {return this->load ();}
    };

    iterator begin () {return iterator (r_.begin ());}
    iterator end () {return iterator (r_.end ());}
  };

  template <typename R>
  inline pointer_result_range<R>
  pointer_result (R&& r)
  {
    return pointer_result_range<R> (forward<R> (r));
  }
}

#endif // BPKG_DATABASE_HXX