arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/db/utils.go
db/utils.goRaw
 1package db
 2
 3import (
 4	"encoding/base64"
 5	"fmt"
 6	"math/big"
 7	"reflect"
 8	"strings"
 9
10	"github.com/russross/meddler"
11)
12
13// InitMeddler registers tags to be used to read/write from SQL DBs using meddler
14func InitMeddler() {
15	meddler.Register("bigint", BigIntMeddler{})
16}
17
18// BulkInsert performs a bulk insert with a single statement into the specified table.  Example:
19// `db.BulkInsert(myDB, "INSERT INTO block (eth_block_num, timestamp, hash) VALUES %s", blocks[:])`
20// Note that all the columns must be specified in the query, and they must be in the same order as in the table.
21func BulkInsert(db meddler.DB, q string, args interface{}) error {
22	arrayValue := reflect.ValueOf(args)
23	arrayLen := arrayValue.Len()
24	valueStrings := make([]string, 0, arrayLen)
25	var arglist = make([]interface{}, 0)
26	for i := 0; i < arrayLen; i++ {
27		arg := arrayValue.Index(i).Addr().Interface()
28		elemArglist, err := meddler.Default.Values(arg, true)
29		if err != nil {
30			return err
31		}
32		arglist = append(arglist, elemArglist...)
33		value := "("
34		for j := 0; j < len(elemArglist); j++ {
35			value += fmt.Sprintf("$%d, ", i*len(elemArglist)+j+1)
36		}
37		value = value[:len(value)-2] + ")"
38		valueStrings = append(valueStrings, value)
39	}
40	stmt := fmt.Sprintf(q, strings.Join(valueStrings, ","))
41	_, err := db.Exec(stmt, arglist...)
42	return err
43}
44
45// BigIntMeddler encodes or decodes the field value to or from JSON
46type BigIntMeddler struct{}
47
48// PreRead is called before a Scan operation for fields that have the BigIntMeddler
49func (b BigIntMeddler) PreRead(fieldAddr interface{}) (scanTarget interface{}, err error) {
50	// give a pointer to a byte buffer to grab the raw data
51	return new(string), nil
52}
53
54// PostRead is called after a Scan operation for fields that have the BigIntMeddler
55func (b BigIntMeddler) PostRead(fieldPtr, scanTarget interface{}) error {
56	ptr := scanTarget.(*string)
57	if ptr == nil {
58		return fmt.Errorf("BigIntMeddler.PostRead: nil pointer")
59	}
60
61	data, err := base64.StdEncoding.DecodeString(*ptr)
62	if err != nil {
63		return fmt.Errorf("big.Int decode error: %v", err)
64	}
65	field := fieldPtr.(**big.Int)
66	*field = new(big.Int).SetBytes(data)
67
68	return nil
69}
70
71// PreWrite is called before an Insert or Update operation for fields that have the BigIntMeddler
72func (b BigIntMeddler) PreWrite(fieldPtr interface{}) (saveValue interface{}, err error) {
73	field := fieldPtr.(*big.Int)
74
75	str := base64.StdEncoding.EncodeToString(field.Bytes())
76
77	return str, nil
78}