-
Notifications
You must be signed in to change notification settings - Fork 0
/
asset.go
111 lines (95 loc) · 2.9 KB
/
asset.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
package history
import (
"context"
"sort"
sq "github.com/Masterminds/squirrel"
"github.com/shantanu-hashcash/go/support/db"
"github.com/shantanu-hashcash/go/support/errors"
"github.com/shantanu-hashcash/go/xdr"
)
// GetAssetID fetches the id for an Asset
func (q *Q) GetAssetID(ctx context.Context, asset xdr.Asset) (id int64, err error) {
var (
assetType string
assetCode string
assetIssuer string
)
err = asset.Extract(&assetType, &assetCode, &assetIssuer)
if err != nil {
return
}
sql := sq.Select("id").From("history_assets").Limit(1).Where(sq.Eq{
"asset_type": assetType,
"asset_code": assetCode,
"asset_issuer": assetIssuer})
err = q.Get(ctx, &id, sql)
return
}
// CreateAssets creates rows in the history_assets table for a given list of assets.
func (q *Q) CreateAssets(ctx context.Context, assets []xdr.Asset, batchSize int) (map[string]Asset, error) {
searchStrings := make([]string, 0, len(assets))
assetToKey := map[[3]string]string{}
builder := &db.BatchInsertBuilder{
Table: q.GetTable("history_assets"),
MaxBatchSize: batchSize,
Suffix: "ON CONFLICT (asset_code, asset_type, asset_issuer) DO NOTHING",
}
// sort assets before inserting rows into history_assets to prevent deadlocks on acquiring a ShareLock
// https://github.com/shantanu-hashcash/go/issues/2370
sort.Slice(assets, func(i, j int) bool {
return assets[i].String() < assets[j].String()
})
for _, asset := range assets {
var assetType, assetCode, assetIssuer string
err := asset.Extract(&assetType, &assetCode, &assetIssuer)
if err != nil {
return nil, errors.Wrap(err, "could not extract asset details")
}
assetTuple := [3]string{
assetType,
assetCode,
assetIssuer,
}
if _, contains := assetToKey[assetTuple]; !contains {
searchStrings = append(searchStrings, assetType+"/"+assetCode+"/"+assetIssuer)
assetToKey[assetTuple] = asset.String()
err = builder.Row(ctx, map[string]interface{}{
"asset_type": assetType,
"asset_code": assetCode,
"asset_issuer": assetIssuer,
})
if err != nil {
return nil, errors.Wrap(err, "could not insert history_assets row")
}
}
}
err := builder.Exec(ctx)
if err != nil {
return nil, errors.Wrap(err, "could not exec asset insert builder")
}
assetMap := map[string]Asset{}
const selectBatchSize = 1000
var rows []Asset
for i := 0; i < len(searchStrings); i += selectBatchSize {
end := i + selectBatchSize
if end > len(searchStrings) {
end = len(searchStrings)
}
subset := searchStrings[i:end]
err = q.Select(ctx, &rows, sq.Select("*").From("history_assets").Where(sq.Eq{
"concat(asset_type, '/', asset_code, '/', asset_issuer)": subset,
}))
if err != nil {
return nil, errors.Wrap(err, "could not select assets")
}
for _, row := range rows {
key := assetToKey[[3]string{
row.Type,
row.Code,
row.Issuer,
}]
assetMap[key] = row
}
}
return assetMap, nil
}