summaryrefslogtreecommitdiff
path: root/p2pvr/lib/dbClient.h
blob: 84cf5e7d3b72b5dc701b37105752627236b0dd75 (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
#ifndef DBCLIENT_H
#define DBCLIENT_H

#include <commonObjects.h>
#include <variableType.h>
#include <list>
#include <selectcommand.h>
#include <modifycommand.h>
#include <scopeObject.h>
#include <rdbmsDataSource.h>
#include <sqlVariableBinder.h>
#include <sqlHandleAsVariableType.h>
#include "p2Helpers.h"

class SqlMergeTask;

class DatabaseClient : public virtual CommonObjects {
	public:
		typedef boost::shared_ptr<DB::SelectCommand> SelectPtr;
		typedef boost::shared_ptr<DB::ModifyCommand> ModifyPtr;

		static void SqlMergeColumnsInserter(SqlMergeTask * merge, const std::string & name, bool key);

		class TxHelper {
			public:
				TxHelper(const DatabaseClient *);
				void Commit() const;

			private:
				const DatabaseClient * client;
				ScopeObject so;
		};

		template <typename... Args>
		std::pair<RdbmsDataSource::ConnectionRef, ModifyPtr> Modify(const std::string & sql, const Args & ... args) const
		{
			auto db = dataSource<RdbmsDataSource>("postgres")->getWritable();
			auto cmd = ModifyPtr(db->newModifyCommand(sql));
			Bind(cmd.get(), 0, args...);
			return {db, cmd};
		}

		template <typename... Args>
		std::pair<RdbmsDataSource::ConnectionRef, SelectPtr> Select(const std::string & sql, const Args & ... args) const
		{
			auto db = dataSource<RdbmsDataSource>("postgres")->getReadonly();
			auto cmd = SelectPtr(db->newSelectCommand(sql));
			Bind(cmd.get(), 0, args...);
			return {db, cmd};
		}

		class NoRowsFoundException : public std::runtime_error {
			public:
				NoRowsFoundException();
		};

		template <typename Rtn, typename... Args>
		Rtn SelectScalar(const std::string & sql, const Args & ... args) const
		{
			auto db = dataSource<RdbmsDataSource>("postgres");
			auto cmd = SelectPtr(db->getReadonly()->newSelectCommand(sql));
			Bind(cmd.get(), 0, args...);
			while (cmd->fetch()) {
				HandleAsVariableType h;
				(*cmd)[0].apply(h);
				Rtn r;
				h.variable >> r;
				return r;
			}
			throw NoRowsFoundException();
		}

	private:
		static void Bind(DB::Command *, unsigned int) { }

		template <typename Arg>
		static void Bind(DB::Command * cmd, unsigned int offset, const Arg & arg)
		{
			VariableType v;
			v << arg;
			boost::apply_visitor<const SqlVariableBinder, const VariableType>(SqlVariableBinder(cmd, offset), v);
		}
		
		template <typename Arg, typename... Args>
		static void Bind(DB::Command * cmd, unsigned int offset, const Arg & arg, const Args & ... args)
		{
			Bind(cmd, offset, arg);
			Bind(cmd, offset + 1, args...);
		}

		friend class TxHelper;
		typedef boost::function<void(DataSourcePtr)> DataSourceCall;
		void onAllDatasources(const DataSourceCall &) const;
};

VariableType
operator/(const DatabaseClient::SelectPtr & cmd, unsigned int col);

VariableType
operator/(const DatabaseClient::SelectPtr & cmd, const std::string & col);

#endif