-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsqlite.d
124 lines (102 loc) · 1.79 KB
/
sqlite.d
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
module tt.sqlite;
import
std.conv,
std.meta,
std.array,
std.string,
std.typecons,
etc.c.sqlite3,
tt.error;
public import std.typecons : Tuple;
final class SQLite
{
this(string name)
{
!sqlite3_open(name.toStringz, &_db) || throwError(error);
}
~this()
{
sqlite3_close(_db);
}
static escape(string s)
{
return format(`'%s'`, s.replace(`'`, `''`));
}
auto queryOne(T, A...)(auto ref in A args)
{
auto res = query!(Tuple!T)(args);
res.length == 1 || throwError(`a query must return exactly one row`);
return res[0];
}
auto query(T = void, A...)(string q, auto ref in A args)
{
static if(A.length)
{
q = format(q, escapeStrings!args);
}
static if(is(T == void))
{
enum cb = null;
enum data = null;
}
else
{
alias R = T[];
R res;
extern(C) int func(void *data, int n, char **fields, char **cols)
{
auto r = cast(R *)data;
r.length++;
foreach(k, U; T.Types)
{
(*r).back[k] = fields[k].fromStringz.to!U;
}
return 0;
}
auto cb = &func;
auto data = &res;
}
sqlite3_exec(_db, q.toStringz, cb, data, null) == SQLITE_OK || throwError(`can't execute query: %s - %s`, q, error);
static if(is(typeof(res)))
{
return res;
}
}
auto lastId()
{
return cast(uint)sqlite3_last_insert_rowid(_db);
}
auto affected()
{
return cast(uint)sqlite3_changes(_db);
}
private:
auto error()
{
return cast(string)sqlite3_errmsg(_db).fromStringz;
}
sqlite3 *_db;
}
template escapeStrings(Args...)
{
static if(Args.length)
{
auto arg()
{
auto v = Args[0];
static if(is(typeof(v) : string))
{
return SQLite.escape(v);
}
else
{
return v;
}
}
alias escapeStrings = AliasSeq!(arg, escapeStrings!(Args[1..$]));
}
else
{
alias escapeStrings = AliasSeq!();
}
}