First commit

This commit is contained in:
Pavel Shevaev 2022-10-26 14:26:49 +03:00
commit 490ecb0be2
5 changed files with 161 additions and 0 deletions

9
go.mod Normal file
View File

@ -0,0 +1,9 @@
module git.bit5.ru/backend/clickhouse
go 1.13
require (
github.com/stretchr/testify v1.6.1
git.bit5.ru/backend/errors v1.0.0
)

11
go.sum Normal file
View File

@ -0,0 +1,11 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

86
settings/settings.go Normal file
View File

@ -0,0 +1,86 @@
package settings
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/url"
"strconv"
"git.bit5.ru/backend/errors"
)
// username/password - auth credentials
// database - select the current default database
// read_timeout/write_timeout - timeout in second
// no_delay - disable/enable the Nagle Algorithm for tcp socket (default is 'true' - disable)
// alt_hosts - comma separated list of single address host for load-balancing
// connection_open_strategy - random/in_order (default random).
// random - choose random server from set
// in_order - first live server is chosen in specified order
// block_size - maximum rows in block (default is 1000000). If the rows are larger then the data will be split into several blocks to send them to the server
// pool size - maximum amount of preallocated byte chunks used in queries (default is 100). Decrease this if you experience memory problems at the expense of more GC pressure and vice versa.
// debug - enable debug output (boolean value)
// Load
func Load(path string) (ClickhouseSettings, error) {
bytes, err := ioutil.ReadFile(path)
if err != nil {
return ClickhouseSettings{}, errors.WithStack(err)
}
settings := ClickhouseSettings{}
if err := json.Unmarshal(bytes, &settings); err != nil {
return ClickhouseSettings{}, errors.WithStack(err)
}
return settings, nil
}
// ClickhouseSettings
type ClickhouseSettings struct {
Host string `json:"host"`
Port int `json:"port"`
Database string `json:"database"`
Username string `json:"username"`
Password string `json:"password"`
Options map[string]json.RawMessage `json:"opts"`
}
func (s ClickhouseSettings) DSN() string {
options := url.Values{
"database": []string{s.Database},
}
if len(s.Username) > 0 {
options.Set("username", s.Username)
}
if len(s.Password) > 0 {
options.Set("password", s.Password)
}
for name, value := range s.Options {
var valueString string
if value[0] == '"' {
if err := json.Unmarshal(value, &valueString); err != nil {
panic(err)
}
} else {
var valueInt int
if err := json.Unmarshal(value, &valueInt); err != nil {
panic(err)
}
valueString = strconv.Itoa(valueInt)
}
options.Set(name, valueString)
}
uri := url.URL{
Scheme: "tcp",
Host: fmt.Sprintf("%s:%d", s.Host, s.Port),
RawQuery: options.Encode(),
}
return uri.String()
}

46
settings/settings_test.go Normal file
View File

@ -0,0 +1,46 @@
package settings_test
import (
"clickhouse/settings"
"encoding/json"
"testing"
"github.com/stretchr/testify/assert"
)
func TestLoad(t *testing.T) {
expectedSettings := settings.ClickhouseSettings{
Host: "localhost",
Port: 9000,
Database: "regency_dev",
Options: map[string]json.RawMessage{
"read_timeout": json.RawMessage(`1`),
"no_delay": json.RawMessage(`"disable"`),
},
}
actualSettings, err := settings.Load("./test_settings.json")
assert.NoError(t, err)
assert.Equal(t, expectedSettings, actualSettings)
}
func TestClickhouseSettings(t *testing.T) {
t.Run("DSN", func(t *testing.T) {
clickSettings := settings.ClickhouseSettings{
Host: "localhost",
Port: 9000,
Username: "user",
Password: "pwd#1",
Database: "regency_dev",
Options: map[string]json.RawMessage{
"read_timeout": json.RawMessage(`1`),
"no_delay": json.RawMessage(`"disable"`),
},
}
expectedDSN := "tcp://localhost:9000?database=regency_dev&no_delay=disable&password=pwd%231&read_timeout=1&username=user"
assert.Equal(t, expectedDSN, clickSettings.DSN())
})
}

View File

@ -0,0 +1,9 @@
{
"host": "localhost",
"port": 9000,
"database": "regency_dev",
"opts": {
"read_timeout": 1,
"no_delay": "disable"
}
}