← history for db.go
0b9f6e49db.go113 lines⬡ raw↓ download
  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
package main

import (
	"encoding/json"
	"fmt"
	"os"
	"time"

	"github.com/gocql/gocql"
)

// Config holds the connection settings loaded from the JSON config file.
type Config struct {
	Server   string `json:"servername"`
	Port     int    `json:"port"`
	Keyspace string `json:"keyspace"`
	Username string `json:"username"`
	Password string `json:"password"`
}

func LoadConfig(path string) (*Config, error) {
	data, err := os.ReadFile(path)
	if err != nil {
		return nil, fmt.Errorf("reading config file: %w", err)
	}

	var cfg Config
	if err := json.Unmarshal(data, &cfg); err != nil {
		return nil, fmt.Errorf("parsing config file: %w", err)
	}

	if cfg.Server == "" {
		return nil, fmt.Errorf("servername is required in config")
	}
	if cfg.Port == 0 {
		cfg.Port = 9042
	}

	return &cfg, nil
}

func Connect(cfg *Config) (*gocql.Session, error) {
	cluster := gocql.NewCluster(cfg.Server)
	cluster.Port = cfg.Port
	cluster.Keyspace = cfg.Keyspace
	cluster.Consistency = gocql.Quorum
	cluster.Timeout = 10 * time.Second

	if cfg.Username != "" {
		cluster.Authenticator = gocql.PasswordAuthenticator{
			Username: cfg.Username,
			Password: cfg.Password,
		}
	}

	session, err := cluster.CreateSession()
	if err != nil {
		return nil, fmt.Errorf("connecting to cassandra: %w", err)
	}

	return session, nil
}

// QueryResult holds column names and row data returned from a CQL query.
type QueryResult struct {
	Columns []string
	Rows    [][]string
}

func RunQuery(session *gocql.Session, query string) (*QueryResult, error) {
	iter := session.Query(query).Iter()

	columns := iter.Columns()
	colNames := make([]string, len(columns))
	for i, c := range columns {
		colNames[i] = c.Name
	}

	result := &QueryResult{Columns: colNames}

	row := make(map[string]interface{})
	for iter.MapScan(row) {
		strRow := make([]string, len(colNames))
		for i, name := range colNames {
			strRow[i] = formatValue(row[name])
		}
		result.Rows = append(result.Rows, strRow)
		row = make(map[string]interface{})
	}

	if err := iter.Close(); err != nil {
		return nil, fmt.Errorf("query error: %w", err)
	}

	return result, nil
}

func formatValue(v interface{}) string {
	if v == nil {
		return "null"
	}

	switch val := v.(type) {
	case []byte:
		return string(val)
	case time.Time:
		return val.Format(time.RFC3339)
	case gocql.UUID:
		return val.String()
	default:
		return fmt.Sprintf("%v", val)
	}
}