/
sqlite.go
160 lines (156 loc) 路 3.88 KB
/
sqlite.go
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
//go:build cgo
// +build cgo
// File is part of the build only if cgo is enabled.
// Otherwise, the compilation will complains about missing type sqlite3,Error
// It is due to the fact than sqlite lib use import "C" statement.
// The presence of these statement during the build exclude the file if CGO is disabled.
package sqlstorage
import (
"database/sql"
"encoding/json"
"regexp"
"strconv"
"github.com/buger/jsonparser"
"github.com/mattn/go-sqlite3"
"github.com/numary/ledger/pkg/core"
"github.com/numary/ledger/pkg/storage"
)
func init() {
errorHandlers[SQLite] = func(err error) error {
eerr, ok := err.(sqlite3.Error)
if !ok {
return err
}
if eerr.Code == sqlite3.ErrConstraint {
return storage.NewError(storage.ConstraintFailed, err)
}
return err
}
sql.Register("sqlite3-custom", &sqlite3.SQLiteDriver{
ConnectHook: func(conn *sqlite3.SQLiteConn) error {
err := conn.RegisterFunc("hash_log", func(v1, v2 string) string {
m1 := make(map[string]interface{})
m2 := make(map[string]interface{})
err := json.Unmarshal([]byte(v1), &m1)
if err != nil {
panic(err)
}
err = json.Unmarshal([]byte(v2), &m2)
if err != nil {
panic(err)
}
return core.Hash(m1, m2)
}, true)
if err != nil {
return err
}
err = conn.RegisterFunc("regexp", func(re, s string) (bool, error) {
b, e := regexp.MatchString(re, s)
return b, e
}, true)
if err != nil {
return err
}
err = conn.RegisterFunc("use_account", func(v string, act string) (bool, error) {
r, err := regexp.Compile("^" + act + "$")
if err != nil {
return false, err
}
postings := core.Postings{}
err = json.Unmarshal([]byte(v), &postings)
if err != nil {
return false, nil
}
for _, p := range postings {
if r.MatchString(p.Source) || r.MatchString(p.Destination) {
return true, nil
}
}
return false, nil
}, true)
if err != nil {
return err
}
err = conn.RegisterFunc("use_account_as_source", func(v string, act string) (bool, error) {
r, err := regexp.Compile("^" + act + "$")
if err != nil {
return false, err
}
postings := core.Postings{}
err = json.Unmarshal([]byte(v), &postings)
if err != nil {
return false, nil
}
for _, p := range postings {
if r.MatchString(p.Source) {
return true, nil
}
}
return false, nil
}, true)
if err != nil {
return err
}
err = conn.RegisterFunc("use_account_as_destination", func(v string, act string) (bool, error) {
r, err := regexp.Compile("^" + act + "$")
if err != nil {
return false, err
}
postings := core.Postings{}
err = json.Unmarshal([]byte(v), &postings)
if err != nil {
return false, nil
}
for _, p := range postings {
if r.MatchString(p.Destination) {
return true, nil
}
}
return false, nil
}, true)
if err != nil {
return err
}
err = conn.RegisterFunc(SQLCustomFuncMetaCompare, func(metadata string, value string, key ...string) bool {
bytes, dataType, _, err := jsonparser.Get([]byte(metadata), key...)
if err != nil {
return false
}
switch dataType {
case jsonparser.String:
str, err := jsonparser.ParseString(bytes)
if err != nil {
return false
}
return value == str
case jsonparser.Boolean:
b, err := jsonparser.ParseBoolean(bytes)
if err != nil {
return false
}
switch value {
case "true":
return b
case "false":
return !b
}
return false
case jsonparser.Number:
i, err := jsonparser.ParseInt(bytes)
if err != nil {
return false
}
vi, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return false
}
return i == vi
default:
return false
}
}, true)
return err
},
})
UpdateSQLDriverMapping(SQLite, "sqlite3-custom")
}