-
Notifications
You must be signed in to change notification settings - Fork 2
/
sqlcipher.nim
169 lines (146 loc) · 6.21 KB
/
sqlcipher.nim
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
160
161
162
163
164
165
166
167
168
169
include sqlcipher/tiny_sqlite
#
# Custom.DbConn
#
proc all*[T](db: DbConn, _: typedesc[T], sql: string,
params: varargs[DbValue, toDbValue]): seq[T] =
## Executes ``statement`` and returns all result rows.
for row in db.iterate(sql, params):
var r = T()
row.unpack(r)
result.add r
proc one*[T](db: DbConn, _: typedesc[T], sql: string,
params: varargs[DbValue, toDbValue]): Option[T] =
## Executes `sql`, which must be a single SQL statement, and returns the first result row.
## Returns `none(seq[DbValue])` if the result was empty.
for row in db.iterate(sql, params):
var r = T()
row.unpack(r)
return some(r)
proc value*[T](db: DbConn, _: typedesc[T], sql: string,
params: varargs[DbValue, toDbValue]): Option[T] =
## Executes `sql`, which must be a single SQL statement, and returns the first column of the first result row.
## Returns `none(DbValue)` if the result was empty.
for row in db.iterate(sql, params):
return some(row.values[0].fromDbValue(T))
#
# Custom.SqlStatement
#
proc all*[T](_: typedesc[T], statement: SqlStatement, params: varargs[DbValue, toDbValue]): seq[T] =
## Executes ``statement`` and returns all result rows.
assertCanUseStatement statement
for row in statement.iterate(params):
var r = T()
row.unpack(r)
result.add r
proc one*[T](_: typedesc[T], statement: SqlStatement,
params: varargs[DbValue, toDbValue]): Option[T] =
## Executes `statement` and returns the first row found.
## Returns `none(seq[DbValue])` if no result was found.
assertCanUseStatement statement
for row in statement.iterate(params):
var r = T()
row.unpack(r)
return some(r)
proc value*[T](_: typedesc[T], statement: SqlStatement,
params: varargs[DbValue, toDbValue]): Option[T] =
## Executes `statement` and returns the first column of the first row found.
## Returns `none(DbValue)` if no result was found.
assertCanUseStatement statement
for row in statement.iterate(params):
return some(row.values[0].fromDbValue(T))
#
# Custom.ResultRow
#
proc `[]`*[T](row: ResultRow, columnName: string, _: typedesc[T]): T =
row[columnName].fromDbValue(T)
proc hasRows*(rows: seq[ResultRow]): bool = rows.len > 0
#
# Custom.ORM
# This section was not originally part of tiny_sqlite
#
# TODO: add primaryKey param to pragma, however there is an issue with multiple
# params in getCustomPragmaFixed: https://github.com/status-im/nim-stew/issues/62,
# and we need to wait on a fix or a workaround.
template dbColumnName*(name: string) {.pragma.}
## Specifies the database column name for the object property
template dbTableName*(name: string) {.pragma.}
## Specifies the database table name for the object
template dbForeignKey*(t: typedesc) {.pragma.}
## Specifies the table's foreign key type
template columnName*(obj: auto | typedesc): string =
when macros.hasCustomPragma(obj, dbColumnName):
macros.getCustomPragmaVal(obj, dbColumnName)
else:
typetraits.name(obj.type).toLower
template tableName*(obj: auto | typedesc): string =
when macros.hasCustomPragma(obj, dbTableName):
macros.getCustomPragmaVal(obj, dbTableName)
else:
typetraits.name(obj.type).toLower
template enumInstanceDbColumns*(obj: auto,
fieldNameVar, fieldVar,
body: untyped) =
## Expands a block over all serialized fields of an object.
##
## Inside the block body, the passed `fieldNameVar` identifier
## will refer to the name of each field as a string. `fieldVar`
## will refer to the field value.
##
## The order of visited fields matches the order of the fields in
## the object definition.
type ObjType {.used.} = type(obj)
for fieldName, fieldVar in fieldPairs(obj):
when hasCustomPragmaFixed(ObjType, fieldName, dbColumnName):
const fieldNameVar = getCustomPragmaFixed(ObjType, fieldName, dbColumnName)
else:
const fieldNameVar = fieldName
body
proc unpack*(row: ResultRow, obj: var object) =
obj.enumInstanceDbColumns(dbColName, property):
type ColType = type property
property = row[dbColName, ColType]
#
# Custom.sqlcipher
# The following are APIs from sqlcipher
#
proc key*(db: DbConn, password: string) =
## * Specify the key for an encrypted database. This routine should be
## * called right after sqlite3_open().
## *
## * The code to implement this API is not available in the public release
## * of SQLite.
let rc = sqlite.key(db.handle, password.cstring, int32(password.len))
db.checkRc(rc)
proc key_v2*(db: DbConn, zDbName, password: string) =
## * Specify the key for an encrypted database. This routine should be
## * called right after sqlite3_open().
## *
## * The code to implement this API is not available in the public release
## * of SQLite.
let rc = sqlite.key_v2(db.handle, zDbName.cstring, password.cstring, int32(password.len))
db.checkRc(rc)
proc rekey*(db: DbConn, password: string) =
let rc = sqlite.rekey(db.handle, password.cstring, int32(password.len))
db.checkRc(rc)
## * Change the key on an open database. If the current database is not
## * encrypted, this routine will encrypt it. If pNew==0 or nNew==0, the
## * database is decrypted.
## *
## * The code to implement this API is not available in the public release
## * of SQLite.
proc rekey_v2*(db: DbConn, zDbName, password: string) =
## * Change the key on an open database. If the current database is not
## * encrypted, this routine will encrypt it. If pNew==0 or nNew==0, the
## * database is decrypted.
## *
## * The code to implement this API is not available in the public release
## * of SQLite.
let rc = sqlite.rekey_v2(db.handle, zDbName.cstring, password.cstring, int32(password.len))
db.checkRc(rc)
#
# Custom.Deprecations
#
proc execQuery*[T](db: DbConn, sql: string, params: varargs[DbValue, toDbValue]): seq[T] {.deprecated: "Use all[T] instead".} =
## Executes the query and iterates over the result dataset.
all[T](db, sql, T.type, params)