-
Notifications
You must be signed in to change notification settings - Fork 210
/
iterator.go
100 lines (93 loc) · 2.23 KB
/
iterator.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
package transactions
import (
"fmt"
"strconv"
"strings"
"github.com/spacemeshos/go-spacemesh/codec"
"github.com/spacemeshos/go-spacemesh/common/types"
"github.com/spacemeshos/go-spacemesh/sql"
)
// ResultsFilter applies filter on transaction results query.
type ResultsFilter struct {
Address *types.Address
Start, End *types.LayerID
TID *types.TransactionID
}
func (f *ResultsFilter) query() string {
var q strings.Builder
q.WriteString(`
select distinct id, tx, header, result
from transactions
left join transactions_results_addresses on id=tid
where result is not null
`)
i := 1
if f.Address != nil {
q.WriteString(" and address = ?")
q.WriteString(strconv.Itoa(i))
i++
}
if f.Start != nil {
q.WriteString(" and layer >= ?")
q.WriteString(strconv.Itoa(i))
i++
}
if f.End != nil {
q.WriteString(" and layer <= ?")
q.WriteString(strconv.Itoa(i))
i++
}
if f.TID != nil {
q.WriteString(" and id = ?")
q.WriteString(strconv.Itoa(i))
}
q.WriteString("order by layer, id;")
return q.String()
}
func (f *ResultsFilter) binding(stmt *sql.Statement) {
position := 1
if f.Address != nil {
stmt.BindBytes(position, f.Address[:])
position++
}
if f.Start != nil {
stmt.BindInt64(position, int64(*f.Start))
position++
}
if f.End != nil {
stmt.BindInt64(position, int64(*f.End))
position++
}
if f.TID != nil {
stmt.BindBytes(position, f.TID.Bytes())
}
}
// IterateResults allows to control iteration by the output of `fn`.
func IterateResults(db sql.Executor, filter ResultsFilter, fn func(*types.TransactionWithResult) bool) error {
var ierr error
_, err := db.Exec(filter.query(), filter.binding, func(stmt *sql.Statement) bool {
var tx types.TransactionWithResult
stmt.ColumnBytes(0, tx.ID[:])
tx.Raw = make([]byte, stmt.ColumnLen(1))
stmt.ColumnBytes(1, tx.Raw)
if stmt.ColumnLen(2) > 0 {
tx.TxHeader = &types.TxHeader{}
_, ierr = codec.DecodeFrom(stmt.ColumnReader(2), tx.TxHeader)
if ierr != nil {
return false
}
}
_, ierr = codec.DecodeFrom(stmt.ColumnReader(3), &tx.TransactionResult)
if ierr != nil {
return false
}
return fn(&tx)
})
if err == nil {
err = ierr
}
if err != nil {
return fmt.Errorf("iteration failed %w", err)
}
return nil
}