forked from arp242/goatcounter
-
Notifications
You must be signed in to change notification settings - Fork 1
/
types.go
115 lines (95 loc) · 2.58 KB
/
types.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
112
113
114
115
// Copyright © Martin Tournoij – This file is part of GoatCounter and published
// under the terms of a slightly modified EUPL v1.2 license, which can be found
// in the LICENSE file or at https://license.goatcounter.com
package goatcounter
import (
"database/sql/driver"
"fmt"
"slices"
"strings"
"zgo.at/zstd/zfloat"
"zgo.at/zstd/zint"
)
// Ints stores a slice of []int64 as a comma-separated string.
type Ints []int64
func (l Ints) String() string { return zint.Join(l, ", ") }
func (l Ints) Value() (driver.Value, error) { return zint.Join(l, ","), nil }
func (l *Ints) UnmarshalText(v []byte) error { return l.Scan(v) }
func (l *Ints) Scan(v any) error {
if v == nil {
return nil
}
var err error
*l, err = zint.Split(fmt.Sprintf("%s", v), ",")
return err
}
func (l Ints) MarshalText() ([]byte, error) {
v, err := l.Value()
return []byte(fmt.Sprintf("%s", v)), err
}
// Floats stores a slice of []float64 as a comma-separated string.
type Floats []float64
func (l Floats) String() string { return zfloat.Join(l, ", ") }
func (l Floats) Value() (driver.Value, error) { return zfloat.Join(l, ","), nil }
func (l *Floats) UnmarshalText(v []byte) error { return l.Scan(v) }
func (l *Floats) Scan(v any) error {
if v == nil {
return nil
}
var err error
*l, err = zfloat.Split(fmt.Sprintf("%s", v), ",")
return err
}
func (l Floats) MarshalText() ([]byte, error) {
v, err := l.Value()
return []byte(fmt.Sprintf("%s", v)), err
}
// Strings stores a slice of []string as a comma-separated string.
type Strings []string
func (l Strings) String() string { return strings.Join(l, ", ") }
func (l Strings) Value() (driver.Value, error) {
return strings.Join(slices.DeleteFunc(l, func(s string) bool { return s == "" }), ","), nil
}
func (l *Strings) UnmarshalText(v []byte) error { return l.Scan(v) }
// TODO: move to zstd/zstring
func splitAny(s string, seps ...string) []string {
var split []string
for {
var i int
for _, sep := range seps {
i = strings.Index(s, sep)
if i >= 0 {
break
}
}
if i < 0 {
if len(s) > 0 {
split = append(split, s)
}
break
}
split = append(split, s[:i])
s = s[i+1:]
}
return split
}
func (l *Strings) Scan(v any) error {
if v == nil {
return nil
}
split := splitAny(fmt.Sprintf("%s", v), ",", " ")
strs := make([]string, 0, len(split))
for _, s := range split {
s = strings.TrimSpace(s)
if s == "" {
continue
}
strs = append(strs, s)
}
*l = strs
return nil
}
func (l Strings) MarshalText() ([]byte, error) {
v, err := l.Value()
return []byte(fmt.Sprintf("%s", v)), err
}