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	meddler.Register("bigintnull", BigIntNullMeddler{})
 17}
 18
 19// BulkInsert performs a bulk insert with a single statement into the specified table.  Example:
 20// `db.BulkInsert(myDB, "INSERT INTO block (eth_block_num, timestamp, hash) VALUES %s", blocks[:])`
 21// Note that all the columns must be specified in the query, and they must be in the same order as in the table.
 22func BulkInsert(db meddler.DB, q string, args interface{}) error {
 23	arrayValue := reflect.ValueOf(args)
 24	arrayLen := arrayValue.Len()
 25	valueStrings := make([]string, 0, arrayLen)
 26	var arglist = make([]interface{}, 0)
 27	for i := 0; i < arrayLen; i++ {
 28		arg := arrayValue.Index(i).Addr().Interface()
 29		elemArglist, err := meddler.Default.Values(arg, true)
 30		if err != nil {
 31			return err
 32		}
 33		arglist = append(arglist, elemArglist...)
 34		value := "("
 35		for j := 0; j < len(elemArglist); j++ {
 36			value += fmt.Sprintf("$%d, ", i*len(elemArglist)+j+1)
 37		}
 38		value = value[:len(value)-2] + ")"
 39		valueStrings = append(valueStrings, value)
 40	}
 41	stmt := fmt.Sprintf(q, strings.Join(valueStrings, ","))
 42	_, err := db.Exec(stmt, arglist...)
 43	return err
 44}
 45
 46// BigIntMeddler encodes or decodes the field value to or from JSON
 47type BigIntMeddler struct{}
 48
 49// PreRead is called before a Scan operation for fields that have the BigIntMeddler
 50func (b BigIntMeddler) PreRead(fieldAddr interface{}) (scanTarget interface{}, err error) {
 51	// give a pointer to a byte buffer to grab the raw data
 52	return new(string), nil
 53}
 54
 55// PostRead is called after a Scan operation for fields that have the BigIntMeddler
 56func (b BigIntMeddler) PostRead(fieldPtr, scanTarget interface{}) error {
 57	ptr := scanTarget.(*string)
 58	if ptr == nil {
 59		return fmt.Errorf("BigIntMeddler.PostRead: nil pointer")
 60	}
 61
 62	data, err := base64.StdEncoding.DecodeString(*ptr)
 63	if err != nil {
 64		return fmt.Errorf("big.Int decode error: %v", err)
 65	}
 66	field := fieldPtr.(**big.Int)
 67	*field = new(big.Int).SetBytes(data)
 68
 69	return nil
 70}
 71
 72// PreWrite is called before an Insert or Update operation for fields that have the BigIntMeddler
 73func (b BigIntMeddler) PreWrite(fieldPtr interface{}) (saveValue interface{}, err error) {
 74	field := fieldPtr.(*big.Int)
 75
 76	str := base64.StdEncoding.EncodeToString(field.Bytes())
 77
 78	return str, nil
 79}
 80
 81// BigIntNullMeddler encodes or decodes the field value to or from JSON
 82type BigIntNullMeddler struct{}
 83
 84// PreRead is called before a Scan operation for fields that have the BigIntNullMeddler
 85func (b BigIntNullMeddler) PreRead(fieldAddr interface{}) (scanTarget interface{}, err error) {
 86	return &fieldAddr, nil
 87}
 88
 89// PostRead is called after a Scan operation for fields that have the BigIntNullMeddler
 90func (b BigIntNullMeddler) PostRead(fieldPtr, scanTarget interface{}) error {
 91	sv := reflect.ValueOf(scanTarget)
 92	if sv.Elem().IsNil() {
 93		// null column, so set target to be zero value
 94		fv := reflect.ValueOf(fieldPtr)
 95		fv.Elem().Set(reflect.Zero(fv.Elem().Type()))
 96		return nil
 97	}
 98	// not null
 99	encoded := new([]byte)
100	refEnc := reflect.ValueOf(encoded)
101	refEnc.Elem().Set(sv.Elem().Elem())
102	data, err := base64.StdEncoding.DecodeString(string(*encoded))
103	if err != nil {
104		return fmt.Errorf("big.Int decode error: %v", err)
105	}
106	field := fieldPtr.(**big.Int)
107	*field = new(big.Int).SetBytes(data)
108	return nil
109}
110
111// PreWrite is called before an Insert or Update operation for fields that have the BigIntNullMeddler
112func (b BigIntNullMeddler) PreWrite(fieldPtr interface{}) (saveValue interface{}, err error) {
113	field := fieldPtr.(*big.Int)
114	if field == nil {
115		return nil, nil
116	}
117	return base64.StdEncoding.EncodeToString(field.Bytes()), nil
118}