1 module utile.db;
2 import std, utile.except;
3 
4 public import utile.db.mysql, utile.db.sqlite;
5 
6 alias Blob = const(ubyte)[];
7 
8 string DB_NULL_STRING()
9 {
10 	__gshared immutable char z;
11 	return (&z)[0 .. 1];
12 }
13 
14 Blob DB_NULL_BLOB()
15 {
16 	__gshared immutable ubyte z;
17 	return (&z)[0 .. 1];
18 }
19 
20 unittest
21 {
22 	{
23 		scope db = new SQLite(null);
24 
25 		{
26 			Blob arr = [1, 2, 3];
27 
28 			auto res = db.queryOne!Blob(`select ?;`, arr);
29 
30 			assert(res == arr);
31 		}
32 
33 		{
34 			auto res = db.query!(uint, string)(`select ?, ?;`, 123, `hello`).array;
35 
36 			assert(res.equal(tuple(123, `hello`).only));
37 		}
38 
39 		{
40 			auto res = db.queryOne!uint(`select ?;`, 123);
41 
42 			assert(res == 123);
43 		}
44 	}
45 
46 	version (Utile_Mysql)
47 	{
48 		MySQL db;
49 
50 		auto res = db.query!(uint, string)(`select ?, ?;`, 123, `hello`);
51 		auto res2 = db.queryOne!uint(`select ?;`, 123);
52 	}
53 }
54 
55 package:
56 
57 mixin template DbBase()
58 {
59 	template query(T...)
60 	{
61 		auto query(A...)(string sql, A args)
62 		{
63 			auto stmt = prepare(sql);
64 			bind(stmt, args);
65 
66 			static if (T.length)
67 			{
68 				return process!T(stmt);
69 			}
70 			else
71 			{
72 				process(stmt);
73 				auto that = this;
74 
75 				struct S
76 				{
77 					auto id() => that.lastId(stmt);
78 					auto affected() => that.affected(stmt);
79 				}
80 
81 				return S();
82 			}
83 		}
84 	}
85 
86 	template queryOne(T...)
87 	{
88 		auto queryOne(A...)(string sql, A args)
89 		{
90 			auto res = query!T(sql, args);
91 			res.empty && throwError(`query returned no rows`);
92 
93 			auto e = res.front;
94 
95 			res.popFront;
96 			res.empty || throwError(`query returned multiple rows`);
97 
98 			return e;
99 		}
100 	}
101 }