Commit 0c71c5487302d1b7d5dda0210fe12d2be4a034f8

Authored by Marko Tikvić
1 parent 6cc94a06e9
Exists in master

minor changes

1 package webutility 1 package webutility
2 2
3 import ( 3 import (
4 "fmt" 4 "fmt"
5 "strings" 5 "strings"
6 "time" 6 "time"
7 ) 7 )
8 8
9 const ( 9 const (
10 YYYYMMDD_sl = "2006/01/02" 10 YYYYMMDD_sl = "2006/01/02"
11 YYYYMMDD_ds = "2006-01-02" 11 YYYYMMDD_ds = "2006-01-02"
12 YYYYMMDD_dt = "2006.01.02." 12 YYYYMMDD_dt = "2006.01.02."
13 13
14 DDMMYYYY_sl = "02/01/2006" 14 DDMMYYYY_sl = "02/01/2006"
15 DDMMYYYY_ds = "02-01-2006" 15 DDMMYYYY_ds = "02-01-2006"
16 DDMMYYYY_dt = "02.01.2006." 16 DDMMYYYY_dt = "02.01.2006."
17 17
18 YYYYMMDD_HHMMSS_sl = "2006/01/02 15:04:05" 18 YYYYMMDD_HHMMSS_sl = "2006/01/02 15:04:05"
19 YYYYMMDD_HHMMSS_ds = "2006-01-02 15:04:05" 19 YYYYMMDD_HHMMSS_ds = "2006-01-02 15:04:05"
20 YYYYMMDD_HHMMSS_dt = "2006.01.02. 15:04:05" 20 YYYYMMDD_HHMMSS_dt = "2006.01.02. 15:04:05"
21 21
22 DDMMYYYY_HHMMSS_sl = "02/01/2006 15:04:05" 22 DDMMYYYY_HHMMSS_sl = "02/01/2006 15:04:05"
23 DDMMYYYY_HHMMSS_ds = "02-01-2006 15:04:05" 23 DDMMYYYY_HHMMSS_ds = "02-01-2006 15:04:05"
24 DDMMYYYY_HHMMSS_dt = "02.01.2006. 15:04:05" 24 DDMMYYYY_HHMMSS_dt = "02.01.2006. 15:04:05"
25 ) 25 )
26 26
27 const DaySeconds = 24 * 60 * 60
28
27 var ( 29 var (
28 regularYear = [12]int64{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} 30 regularYear = [12]int64{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
29 leapYear = [12]int64{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} 31 leapYear = [12]int64{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
30 ) 32 )
31 33
32 func Systime() int64 { 34 func Systime() int64 {
33 return time.Now().Unix() 35 return time.Now().Unix()
34 } 36 }
35 37
36 func DateToEpoch(date, format string) int64 { 38 func DateToEpoch(date, format string) int64 {
37 t, err := time.Parse(format, date) 39 t, err := time.Parse(format, date)
38 if err != nil { 40 if err != nil {
39 fmt.Println(err.Error()) 41 fmt.Println(err.Error())
40 return 0 42 return 0
41 } 43 }
42 return t.Unix() 44 return t.Unix()
43 } 45 }
44 46
45 func EpochToDate(e int64, format string) string { 47 func EpochToDate(e int64, format string) string {
46 return time.Unix(e, 0).Format(format) 48 return time.Unix(e, 0).Format(format)
47 } 49 }
48 50
49 func EpochToDayMonthYear(timestamp int64) (d, m, y int64) { 51 func EpochToDayMonthYear(timestamp int64) (d, m, y int64) {
50 datestring := EpochToDate(timestamp, DDMMYYYY_sl) 52 datestring := EpochToDate(timestamp, DDMMYYYY_sl)
51 parts := strings.Split(datestring, "/") 53 parts := strings.Split(datestring, "/")
52 d = StringToInt64(parts[0]) 54 d = StringToInt64(parts[0])
53 m = StringToInt64(parts[1]) 55 m = StringToInt64(parts[1])
54 y = StringToInt64(parts[2]) 56 y = StringToInt64(parts[2])
55 return d, m, y 57 return d, m, y
56 } 58 }
57 59
58 func DaysInMonth(year, month int64) int64 { 60 func DaysInMonth(year, month int64) int64 {
59 if month < 1 || month > 12 { 61 if month < 1 || month > 12 {
60 return 0 62 return 0
61 } 63 }
62 if IsLeapYear(year) { 64 if IsLeapYear(year) {
63 return leapYear[month-1] 65 return leapYear[month-1]
64 } 66 }
65 return regularYear[month-1] 67 return regularYear[month-1]
66 } 68 }
67 69
68 func IsLeapYear(year int64) bool { 70 func IsLeapYear(year int64) bool {
69 return year%4 == 0 && !((year%100 == 0) && (year%400 != 0)) 71 return year%4 == 0 && !((year%100 == 0) && (year%400 != 0))
70 } 72 }
71 73
72 // FirstDayOfNextMonthEpoch ... 74 // FirstDayOfNextMonthEpoch ...
73 func FirstDayOfNextMonthEpoch(e int64) int64 { 75 func NextMonths1st(e int64) int64 {
74 d, m, y := EpochToDayMonthYear(e) 76 d, m, y := EpochToDayMonthYear(e)
75 m++ 77 m++
76 if m > 12 { 78 if m > 12 {
77 m = 1 79 m = 1
78 y++ 80 y++
79 } 81 }
80 d = 1 82 d = 1
81 83
82 date := fmt.Sprintf("%02d/%02d/%d", d, m, y) 84 date := fmt.Sprintf("%02d/%02d/%d", d, m, y)
83 85
84 return DateToEpoch(date, DDMMYYYY_sl) 86 return DateToEpoch(date, DDMMYYYY_sl)
85 } 87 }
88
89 func SameDate(e1, e2 int64) bool {
90 d1, m1, y1 := EpochToDayMonthYear(e1)
91 d2, m2, y2 := EpochToDayMonthYear(e2)
92
93 if d1 == d2 && m1 == m2 && y1 == y2 {
94 return true
95 }
96
97 return false
98 }
99
100 func ToStartOfDay(d int64) int64 {
101 rem := d % DaySeconds
102 if rem != 0 {
103 d -= rem
104 }
105 return d
106 }
107
108 func ParseTime(date, format string) time.Time {
109 t, err := time.Parse(format, date)
110 if err != nil {
111 fmt.Println(err.Error())
112 }
113 return t
114 }
86 115
1 package webutility 1 package webutility
2 2
3 import ( 3 import (
4 "fmt" 4 "fmt"
5 "math" 5 "math"
6 "math/big" 6 "math/big"
7 "strings" 7 "strings"
8 ) 8 )
9 9
10 func RoundFloat64(f float64, dec int) float64 { 10 func RoundFloat64(f float64, dec int) float64 {
11 p := math.Pow(10, float64(dec)) 11 p := math.Pow(10, float64(dec))
12 return math.Round(f*p) / p 12 return math.Round(f*p) / p
13 } 13 }
14 14
15 func NewBF(f float64, prec uint) *big.Float { 15 func NewBF(f float64, prec uint) *big.Float {
16 x := big.NewFloat(f) 16 x := big.NewFloat(f)
17 x.SetPrec(prec) 17 x.SetPrec(prec)
18 return x 18 return x
19 } 19 }
20 20
21 func AddBF(x, y *big.Float) *big.Float { 21 func AddBF(x, y *big.Float) *big.Float {
22 z := big.NewFloat(0.0) 22 z := big.NewFloat(0.0)
23 z.SetPrec(x.Prec()) 23 z.SetPrec(x.Prec())
24 z.Add(x, y) 24 z.Add(x, y)
25 return z 25 return z
26 } 26 }
27 27
28 func SubBF(x, y *big.Float) *big.Float { 28 func SubBF(x, y *big.Float) *big.Float {
29 z := big.NewFloat(0.0) 29 z := big.NewFloat(0.0)
30 z.SetPrec(x.Prec()) 30 z.SetPrec(x.Prec())
31 31
32 yneg := big.NewFloat(0.0) 32 yneg := big.NewFloat(0.0)
33 yneg.Neg(y) 33 yneg.Neg(y)
34 34
35 z.Add(x, yneg) 35 z.Add(x, yneg)
36 return z 36 return z
37 } 37 }
38 38
39 func MulBF(x, y *big.Float) *big.Float { 39 func MulBF(x, y *big.Float) *big.Float {
40 z := big.NewFloat(0.0) 40 z := big.NewFloat(0.0)
41 z.SetPrec(x.Prec()) 41 z.SetPrec(x.Prec())
42 z.Mul(x, y) 42 z.Mul(x, y)
43 return z 43 return z
44 } 44 }
45 45
46 func DivBF(x, y *big.Float) *big.Float { 46 func DivBF(x, y *big.Float) *big.Float {
47 z := big.NewFloat(0.0) 47 z := big.NewFloat(0.0)
48 z.SetPrec(x.Prec()) 48 z.SetPrec(x.Prec())
49 z.Quo(x, y) 49 z.Quo(x, y)
50 return z 50 return z
51 } 51 }
52 52
53 func BFtoFloat(f *big.Float) float64 { 53 func BFtoFloat(f *big.Float) float64 {
54 v, _ := f.Float64() 54 v, _ := f.Float64()
55 return v 55 return v
56 } 56 }
57 57
58 func Float64ToString(f float64) string { 58 func Float64ToString(f float64) string {
59 return fmt.Sprintf("%.2f", f) 59 return fmt.Sprintf("%.2f", f)
60 } 60 }
61 61
62 func Float64PtrToString(f *float64) string { 62 func Float64PtrToString(f *float64) string {
63 if f == nil { 63 if f == nil {
64 return "" 64 return ""
65 } 65 }
66 return fmt.Sprintf("%.2f", *f) 66 return fmt.Sprintf("%.2f", *f)
67 } 67 }
68 68
69 func FormatFloat64Number(f float64, dec int) string { 69 func FormatFloat64Number(f float64, dec int) string {
70 res := "" 70 res := ""
71 71
72 f = RoundFloat64(f, dec) 72 f = RoundFloat64(f, dec)
73 73
74 i := int64(f) 74 i := int64(f)
75 75
76 format := fmt.Sprintf("%%.%df", dec) 76 format := fmt.Sprintf("%%.%df", dec)
77 parts := strings.Split(fmt.Sprintf(format, f-float64(i)), ".") 77 parts := strings.Split(fmt.Sprintf(format, f-float64(i)), ".")
78 78
79 decimals := parts[1] 79 decimals := parts[1]
80 80
81 res = FormatInt64Number(i) + "," + decimals 81 res = FormatInt64Number(i) + "," + decimals
82 82
83 return res 83 return res
84 } 84 }
85 85
86 func MaxFlaot64(vars ...float64) (max float64) { 86 func MaxFloat64(vars ...float64) (max float64) {
87 max = vars[0] 87 max = vars[0]
88 for _, v := range vars { 88 for _, v := range vars {
89 if v > max { 89 if v > max {
90 max = v 90 max = v
91 } 91 }
92 } 92 }
93 return max 93 return max
94 } 94 }
95 95
1 package webutility 1 package webutility
2 2
3 import ( 3 import (
4 "database/sql" 4 "database/sql"
5 "database/sql/driver" 5 "database/sql/driver"
6 "encoding/json" 6 "encoding/json"
7 "fmt" 7 "fmt"
8 "time" 8 "time"
9 ) 9 )
10 10
11 // NullBool is a wrapper for sql.NullBool with added JSON (un)marshalling 11 // NullBool is a wrapper for sql.NullBool with added JSON (un)marshalling
12 type NullBool sql.NullBool 12 type NullBool sql.NullBool
13 13
14 // Scan ... 14 // Scan ...
15 func (nb *NullBool) Scan(value interface{}) error { 15 func (nb *NullBool) Scan(value interface{}) error {
16 var b sql.NullBool 16 var b sql.NullBool
17 if err := b.Scan(value); err != nil { 17 if err := b.Scan(value); err != nil {
18 nb.Bool, nb.Valid = false, false 18 nb.Bool, nb.Valid = false, false
19 return err 19 return err
20 } 20 }
21 nb.Bool, nb.Valid = b.Bool, b.Valid 21 nb.Bool, nb.Valid = b.Bool, b.Valid
22 return nil 22 return nil
23 } 23 }
24 24
25 // Value ... 25 // Value ...
26 func (nb *NullBool) Value() (driver.Value, error) { 26 func (nb *NullBool) Value() (driver.Value, error) {
27 if !nb.Valid { 27 if !nb.Valid {
28 return nil, nil 28 return nil, nil
29 } 29 }
30 return nb.Bool, nil 30 return nb.Bool, nil
31 } 31 }
32 32
33 // MarshalJSON ... 33 // MarshalJSON ...
34 func (nb NullBool) MarshalJSON() ([]byte, error) { 34 func (nb NullBool) MarshalJSON() ([]byte, error) {
35 if nb.Valid { 35 if nb.Valid {
36 return json.Marshal(nb.Bool) 36 return json.Marshal(nb.Bool)
37 } 37 }
38 38
39 return json.Marshal(nil) 39 return json.Marshal(nil)
40 } 40 }
41 41
42 // UnmarshalJSON ... 42 // UnmarshalJSON ...
43 func (nb *NullBool) UnmarshalJSON(b []byte) error { 43 func (nb *NullBool) UnmarshalJSON(b []byte) error {
44 var temp *bool 44 var temp *bool
45 if err := json.Unmarshal(b, &temp); err != nil { 45 if err := json.Unmarshal(b, &temp); err != nil {
46 return err 46 return err
47 } 47 }
48 if temp != nil { 48 if temp != nil {
49 nb.Valid = true 49 nb.Valid = true
50 nb.Bool = *temp 50 nb.Bool = *temp
51 } else { 51 } else {
52 nb.Valid = false 52 nb.Valid = false
53 } 53 }
54 return nil 54 return nil
55 } 55 }
56 56
57 // CastToSQL ... 57 // CastToSQL ...
58 func (nb *NullBool) CastToSQL() sql.NullBool { 58 func (nb *NullBool) CastToSQL() sql.NullBool {
59 return sql.NullBool(*nb) 59 return sql.NullBool(*nb)
60 } 60 }
61 61
62 // NullString is a wrapper for sql.NullString with added JSON (un)marshalling 62 // NullString is a wrapper for sql.NullString with added JSON (un)marshalling
63 type NullString sql.NullString 63 type NullString sql.NullString
64 64
65 // Scan ... 65 // Scan ...
66 func (ns *NullString) Scan(value interface{}) error { 66 func (ns *NullString) Scan(value interface{}) error {
67 var s sql.NullString 67 var s sql.NullString
68 if err := s.Scan(value); err != nil { 68 if err := s.Scan(value); err != nil {
69 ns.String, ns.Valid = "", false 69 ns.String, ns.Valid = "", false
70 return err 70 return err
71 } 71 }
72 ns.String, ns.Valid = s.String, s.Valid 72 ns.String, ns.Valid = s.String, s.Valid
73 return nil 73 return nil
74 } 74 }
75 75
76 // Value ... 76 // Value ...
77 func (ns *NullString) Value() (driver.Value, error) { 77 func (ns *NullString) Value() (driver.Value, error) {
78 if !ns.Valid { 78 if !ns.Valid {
79 return nil, nil 79 return nil, nil
80 } 80 }
81 return ns.String, nil 81 return ns.String, nil
82 } 82 }
83 83
84 // Val ...
85 func (ns *NullString) Val() string {
86 return ns.String
87 }
88
84 // MarshalJSON ... 89 // MarshalJSON ...
85 func (ns NullString) MarshalJSON() ([]byte, error) { 90 func (ns NullString) MarshalJSON() ([]byte, error) {
86 if ns.Valid { 91 if ns.Valid {
87 return json.Marshal(ns.String) 92 return json.Marshal(ns.String)
88 } 93 }
89 return json.Marshal(nil) 94 return json.Marshal(nil)
90 } 95 }
91 96
92 // UnmarshalJSON ... 97 // UnmarshalJSON ...
93 func (ns *NullString) UnmarshalJSON(b []byte) error { 98 func (ns *NullString) UnmarshalJSON(b []byte) error {
94 var temp *string 99 var temp *string
95 if err := json.Unmarshal(b, &temp); err != nil { 100 if err := json.Unmarshal(b, &temp); err != nil {
96 return err 101 return err
97 } 102 }
98 if temp != nil { 103 if temp != nil {
99 ns.Valid = true 104 ns.Valid = true
100 ns.String = *temp 105 ns.String = *temp
101 } else { 106 } else {
102 ns.Valid = false 107 ns.Valid = false
103 } 108 }
104 return nil 109 return nil
105 } 110 }
106 111
107 // CastToSQL ... 112 // CastToSQL ...
108 func (ns *NullString) CastToSQL() sql.NullString { 113 func (ns *NullString) CastToSQL() sql.NullString {
109 return sql.NullString(*ns) 114 return sql.NullString(*ns)
110 } 115 }
111 116
112 // NullInt64 is a wrapper for sql.NullInt64 with added JSON (un)marshalling 117 // NullInt64 is a wrapper for sql.NullInt64 with added JSON (un)marshalling
113 type NullInt64 sql.NullInt64 118 type NullInt64 sql.NullInt64
114 119
115 // Scan ... 120 // Scan ...
116 func (ni *NullInt64) Scan(value interface{}) error { 121 func (ni *NullInt64) Scan(value interface{}) error {
117 var i sql.NullInt64 122 var i sql.NullInt64
118 if err := i.Scan(value); err != nil { 123 if err := i.Scan(value); err != nil {
119 ni.Int64, ni.Valid = 0, false 124 ni.Int64, ni.Valid = 0, false
120 return err 125 return err
121 } 126 }
122 ni.Int64, ni.Valid = i.Int64, i.Valid 127 ni.Int64, ni.Valid = i.Int64, i.Valid
123 return nil 128 return nil
124 } 129 }
125 130
126 // ScanPtr ... 131 // ScanPtr ...
127 func (ni *NullInt64) ScanPtr(v interface{}) error { 132 func (ni *NullInt64) ScanPtr(v interface{}) error {
128 if ip, ok := v.(*int64); ok && ip != nil { 133 if ip, ok := v.(*int64); ok && ip != nil {
129 return ni.Scan(*ip) 134 return ni.Scan(*ip)
130 } 135 }
131 return nil 136 return nil
132 } 137 }
133 138
134 // Value ... 139 // Value ...
135 func (ni *NullInt64) Value() (driver.Value, error) { 140 func (ni *NullInt64) Value() (driver.Value, error) {
136 if !ni.Valid { 141 if !ni.Valid {
137 return nil, nil 142 return nil, nil
138 } 143 }
139 return ni.Int64, nil 144 return ni.Int64, nil
140 } 145 }
141 146
142 func (ni *NullInt64) Val() int64 { 147 func (ni *NullInt64) Val() int64 {
143 return ni.Int64 148 return ni.Int64
144 } 149 }
145 150
146 // Add 151 // Add
147 func (ni *NullInt64) Add(i NullInt64) { 152 func (ni *NullInt64) Add(i NullInt64) {
148 ni.Valid = true 153 ni.Valid = true
149 ni.Int64 += i.Int64 154 ni.Int64 += i.Int64
150 } 155 }
151 156
152 func (ni *NullInt64) Set(i int64) { 157 func (ni *NullInt64) Set(i int64) {
153 ni.Valid = true 158 ni.Valid = true
154 ni.Int64 = i 159 ni.Int64 = i
155 } 160 }
156 161
157 // MarshalJSON ... 162 // MarshalJSON ...
158 func (ni NullInt64) MarshalJSON() ([]byte, error) { 163 func (ni NullInt64) MarshalJSON() ([]byte, error) {
159 if ni.Valid { 164 if ni.Valid {
160 return json.Marshal(ni.Int64) 165 return json.Marshal(ni.Int64)
161 } 166 }
162 return json.Marshal(nil) 167 return json.Marshal(nil)
163 } 168 }
164 169
165 // UnmarshalJSON ... 170 // UnmarshalJSON ...
166 func (ni *NullInt64) UnmarshalJSON(b []byte) error { 171 func (ni *NullInt64) UnmarshalJSON(b []byte) error {
167 var temp *int64 172 var temp *int64
168 if err := json.Unmarshal(b, &temp); err != nil { 173 if err := json.Unmarshal(b, &temp); err != nil {
169 return err 174 return err
170 } 175 }
171 if temp != nil { 176 if temp != nil {
172 ni.Valid = true 177 ni.Valid = true
173 ni.Int64 = *temp 178 ni.Int64 = *temp
174 } else { 179 } else {
175 ni.Valid = false 180 ni.Valid = false
176 } 181 }
177 return nil 182 return nil
178 } 183 }
179 184
180 // CastToSQL ... 185 // CastToSQL ...
181 func (ni *NullInt64) CastToSQL() sql.NullInt64 { 186 func (ni *NullInt64) CastToSQL() sql.NullInt64 {
182 return sql.NullInt64(*ni) 187 return sql.NullInt64(*ni)
183 } 188 }
184 189
185 // NullFloat64 is a wrapper for sql.NullFloat64 with added JSON (un)marshalling 190 // NullFloat64 is a wrapper for sql.NullFloat64 with added JSON (un)marshalling
186 type NullFloat64 sql.NullFloat64 191 type NullFloat64 sql.NullFloat64
187 192
188 // Scan ... 193 // Scan ...
189 func (nf *NullFloat64) Scan(value interface{}) error { 194 func (nf *NullFloat64) Scan(value interface{}) error {
190 var f sql.NullFloat64 195 var f sql.NullFloat64
191 if err := f.Scan(value); err != nil { 196 if err := f.Scan(value); err != nil {
192 nf.Float64, nf.Valid = 0.0, false 197 nf.Float64, nf.Valid = 0.0, false
193 return err 198 return err
194 } 199 }
195 nf.Float64, nf.Valid = f.Float64, f.Valid 200 nf.Float64, nf.Valid = f.Float64, f.Valid
196 return nil 201 return nil
197 } 202 }
198 203
199 // ScanPtr ... 204 // ScanPtr ...
200 func (nf *NullFloat64) ScanPtr(v interface{}) error { 205 func (nf *NullFloat64) ScanPtr(v interface{}) error {
201 if fp, ok := v.(*float64); ok && fp != nil { 206 if fp, ok := v.(*float64); ok && fp != nil {
202 return nf.Scan(*fp) 207 return nf.Scan(*fp)
203 } 208 }
204 return nil 209 return nil
205 } 210 }
206 211
207 // Value ... 212 // Value ...
208 func (nf *NullFloat64) Value() (driver.Value, error) { 213 func (nf *NullFloat64) Value() (driver.Value, error) {
209 if !nf.Valid { 214 if !nf.Valid {
210 return nil, nil 215 return nil, nil
211 } 216 }
212 return nf.Float64, nil 217 return nf.Float64, nil
213 } 218 }
214 219
215 // Val ... 220 // Val ...
216 func (nf *NullFloat64) Val() float64 { 221 func (nf *NullFloat64) Val() float64 {
217 return nf.Float64 222 return nf.Float64
218 } 223 }
219 224
220 // Add ... 225 // Add ...
221 func (nf *NullFloat64) Add(f NullFloat64) { 226 func (nf *NullFloat64) Add(f NullFloat64) {
222 nf.Valid = true 227 nf.Valid = true
223 nf.Float64 += f.Float64 228 nf.Float64 += f.Float64
224 } 229 }
225 230
226 func (nf *NullFloat64) Set(f float64) { 231 func (nf *NullFloat64) Set(f float64) {
227 nf.Valid = true 232 nf.Valid = true
228 nf.Float64 = f 233 nf.Float64 = f
229 } 234 }
230 235
231 // MarshalJSON ... 236 // MarshalJSON ...
232 func (nf NullFloat64) MarshalJSON() ([]byte, error) { 237 func (nf NullFloat64) MarshalJSON() ([]byte, error) {
233 if nf.Valid { 238 if nf.Valid {
234 return json.Marshal(nf.Float64) 239 return json.Marshal(nf.Float64)
235 } 240 }
236 return json.Marshal(nil) 241 return json.Marshal(nil)
237 } 242 }
238 243
239 // UnmarshalJSON ... 244 // UnmarshalJSON ...
240 func (nf *NullFloat64) UnmarshalJSON(b []byte) error { 245 func (nf *NullFloat64) UnmarshalJSON(b []byte) error {
241 var temp *float64 246 var temp *float64
242 if err := json.Unmarshal(b, &temp); err != nil { 247 if err := json.Unmarshal(b, &temp); err != nil {
243 return err 248 return err
244 } 249 }
245 if temp != nil { 250 if temp != nil {
246 nf.Valid = true 251 nf.Valid = true
247 nf.Float64 = *temp 252 nf.Float64 = *temp
248 } else { 253 } else {
249 nf.Valid = false 254 nf.Valid = false
250 } 255 }
251 return nil 256 return nil
252 } 257 }
253 258
254 // CastToSQL ... 259 // CastToSQL ...
255 func (nf *NullFloat64) CastToSQL() sql.NullFloat64 { 260 func (nf *NullFloat64) CastToSQL() sql.NullFloat64 {
256 return sql.NullFloat64(*nf) 261 return sql.NullFloat64(*nf)
257 } 262 }
258 263
259 // NullDateTime ... 264 // NullDateTime ...
260 type NullDateTime struct { 265 type NullDateTime struct {
261 Time time.Time 266 Time time.Time
262 Valid bool // Valid is true if Time is not NULL 267 Valid bool // Valid is true if Time is not NULL
263 } 268 }
264 269
265 // Scan ... 270 // Scan ...
266 func (nt *NullDateTime) Scan(value interface{}) (err error) { 271 func (nt *NullDateTime) Scan(value interface{}) (err error) {
267 if value == nil { 272 if value == nil {
268 nt.Time, nt.Valid = time.Time{}, false 273 nt.Time, nt.Valid = time.Time{}, false
269 return 274 return
270 } 275 }
271 276
272 switch v := value.(type) { 277 switch v := value.(type) {
273 case time.Time: 278 case time.Time:
274 nt.Time, nt.Valid = v, true 279 nt.Time, nt.Valid = v, true
275 return 280 return
276 case []byte: 281 case []byte:
277 nt.Time, err = parseSQLDateTime(string(v), time.UTC) 282 nt.Time, err = parseSQLDateTime(string(v), time.UTC)
278 nt.Valid = (err == nil) 283 nt.Valid = (err == nil)
279 return 284 return
280 case string: 285 case string:
281 nt.Time, err = parseSQLDateTime(v, time.UTC) 286 nt.Time, err = parseSQLDateTime(v, time.UTC)
282 nt.Valid = (err == nil) 287 nt.Valid = (err == nil)
283 return 288 return
284 } 289 }
285 290
286 nt.Valid = false 291 nt.Valid = false
287 return fmt.Errorf("Can't convert %T to time.Time", value) 292 return fmt.Errorf("Can't convert %T to time.Time", value)
288 } 293 }
289 294
290 // Value implements the driver Valuer interface. 295 // Value implements the driver Valuer interface.
291 func (nt NullDateTime) Value() (driver.Value, error) { 296 func (nt NullDateTime) Value() (driver.Value, error) {
292 if !nt.Valid { 297 if !nt.Valid {
293 return nil, nil 298 return nil, nil
294 } 299 }
295 return nt.Time, nil 300 return nt.Time, nil
296 } 301 }
297 302
298 // MarshalJSON ... 303 // MarshalJSON ...
299 func (nt NullDateTime) MarshalJSON() ([]byte, error) { 304 func (nt NullDateTime) MarshalJSON() ([]byte, error) {
300 if nt.Valid { 305 if nt.Valid {
301 format := nt.Time.Format("2006-01-02 15:04:05") 306 format := nt.Time.Format("2006-01-02 15:04:05")
302 return json.Marshal(format) 307 return json.Marshal(format)
303 } 308 }
304 return json.Marshal(nil) 309 return json.Marshal(nil)
305 } 310 }
306 311
307 // UnmarshalJSON ... 312 // UnmarshalJSON ...
308 func (nt *NullDateTime) UnmarshalJSON(b []byte) error { 313 func (nt *NullDateTime) UnmarshalJSON(b []byte) error {
309 var temp *time.Time 314 var temp *time.Time
310 var t1 time.Time 315 var t1 time.Time
311 var err error 316 var err error
312 317
313 s1 := string(b) 318 s1 := string(b)
314 s2 := s1[1 : len(s1)-1] 319 s2 := s1[1 : len(s1)-1]
315 if s1 == "null" { 320 if s1 == "null" {
316 temp = nil 321 temp = nil
317 } else { 322 } else {
318 t1, err = time.Parse("2006-01-02 15:04:05", s2) 323 t1, err = time.Parse("2006-01-02 15:04:05", s2)
319 if err != nil { 324 if err != nil {
320 return err 325 return err
321 } 326 }
322 temp = &t1 327 temp = &t1
323 } 328 }
324 329
325 if temp != nil { 330 if temp != nil {
326 nt.Valid = true 331 nt.Valid = true
327 nt.Time = *temp 332 nt.Time = *temp
328 } else { 333 } else {
329 nt.Valid = false 334 nt.Valid = false
330 } 335 }
331 return nil 336 return nil
332 } 337 }
333 338
334 func (nt *NullDateTime) CastToSQL() NullDateTime { 339 func (nt *NullDateTime) CastToSQL() NullDateTime {
335 return *nt 340 return *nt
336 } 341 }
337 342
338 func parseSQLDateTime(str string, loc *time.Location) (t time.Time, err error) { 343 func parseSQLDateTime(str string, loc *time.Location) (t time.Time, err error) {
339 base := "0000-00-00 00:00:00.0000000" 344 base := "0000-00-00 00:00:00.0000000"
340 timeFormat := "2006-01-02 15:04:05.999999" 345 timeFormat := "2006-01-02 15:04:05.999999"
341 switch len(str) { 346 switch len(str) {
342 case 10, 19, 21, 22, 23, 24, 25, 26: // up to "YYYY-MM-DD HH:MM:SS.MMMMMM" 347 case 10, 19, 21, 22, 23, 24, 25, 26: // up to "YYYY-MM-DD HH:MM:SS.MMMMMM"
343 if str == base[:len(str)] { 348 if str == base[:len(str)] {
344 return 349 return
345 } 350 }
346 t, err = time.Parse(timeFormat[:len(str)], str) 351 t, err = time.Parse(timeFormat[:len(str)], str)
347 default: 352 default:
348 err = fmt.Errorf("invalid time string: %s", str) 353 err = fmt.Errorf("invalid time string: %s", str)
349 return 354 return
350 } 355 }
351 356
352 // Adjust location 357 // Adjust location
353 if err == nil && loc != time.UTC { 358 if err == nil && loc != time.UTC {
354 y, mo, d := t.Date() 359 y, mo, d := t.Date()
355 h, mi, s := t.Clock() 360 h, mi, s := t.Clock()
356 t, err = time.Date(y, mo, d, h, mi, s, t.Nanosecond(), loc), nil 361 t, err = time.Date(y, mo, d, h, mi, s, t.Nanosecond(), loc), nil
357 } 362 }
358 363
359 return 364 return
360 } 365 }
361 366
362 // NullDate ... 367 // NullDate ...
363 type NullDate struct { 368 type NullDate struct {
364 Time time.Time 369 Time time.Time
365 Valid bool // Valid is true if Time is not NULL 370 Valid bool // Valid is true if Time is not NULL
366 } 371 }
367 372
368 // Scan ... 373 // Scan ...
369 func (nt *NullDate) Scan(value interface{}) (err error) { 374 func (nt *NullDate) Scan(value interface{}) (err error) {
370 if value == nil { 375 if value == nil {
371 nt.Time, nt.Valid = time.Time{}, false 376 nt.Time, nt.Valid = time.Time{}, false
372 return 377 return
373 } 378 }
374 379
375 switch v := value.(type) { 380 switch v := value.(type) {
376 case time.Time: 381 case time.Time:
377 nt.Time, nt.Valid = v, true 382 nt.Time, nt.Valid = v, true
378 return 383 return
379 case []byte: 384 case []byte:
380 nt.Time, err = parseSQLDate(string(v), time.UTC) 385 nt.Time, err = parseSQLDate(string(v), time.UTC)
381 nt.Valid = (err == nil) 386 nt.Valid = (err == nil)
382 return 387 return
383 case string: 388 case string:
384 nt.Time, err = parseSQLDate(v, time.UTC) 389 nt.Time, err = parseSQLDate(v, time.UTC)
385 nt.Valid = (err == nil) 390 nt.Valid = (err == nil)
386 return 391 return
387 } 392 }
388 393
389 nt.Valid = false 394 nt.Valid = false
390 return fmt.Errorf("Can't convert %T to time.Time", value) 395 return fmt.Errorf("Can't convert %T to time.Time", value)
391 } 396 }
392 397
393 // Value implements the driver Valuer interface. 398 // Value implements the driver Valuer interface.
394 func (nt NullDate) Value() (driver.Value, error) { 399 func (nt NullDate) Value() (driver.Value, error) {
395 if !nt.Valid { 400 if !nt.Valid {
396 return nil, nil 401 return nil, nil
397 } 402 }
398 return nt.Time, nil 403 return nt.Time, nil
399 } 404 }
400 405
401 // MarshalJSON ... 406 // MarshalJSON ...
402 func (nt NullDate) MarshalJSON() ([]byte, error) { 407 func (nt NullDate) MarshalJSON() ([]byte, error) {
403 if nt.Valid { 408 if nt.Valid {
404 format := nt.Time.Format("2006-01-02") 409 format := nt.Time.Format("2006-01-02")
405 return json.Marshal(format) 410 return json.Marshal(format)
406 } 411 }
407 return json.Marshal(nil) 412 return json.Marshal(nil)
408 } 413 }
409 414
410 // UnmarshalJSON ... 415 // UnmarshalJSON ...
411 func (nt *NullDate) UnmarshalJSON(b []byte) error { 416 func (nt *NullDate) UnmarshalJSON(b []byte) error {
412 var temp *time.Time 417 var temp *time.Time
413 var t1 time.Time 418 var t1 time.Time
414 var err error 419 var err error
415 420
416 s1 := string(b) 421 s1 := string(b)
417 s2 := s1[1 : len(s1)-1] 422 s2 := s1[1 : len(s1)-1]
418 if s1 == "null" { 423 if s1 == "null" {
419 temp = nil 424 temp = nil
420 } else { 425 } else {
421 t1, err = time.Parse("2006-01-02", s2) 426 t1, err = time.Parse("2006-01-02", s2)
422 if err != nil { 427 if err != nil {
423 return err 428 return err
424 } 429 }
425 temp = &t1 430 temp = &t1
426 } 431 }
427 432
428 if temp != nil { 433 if temp != nil {
429 nt.Scan(t1) 434 nt.Scan(t1)
430 } else { 435 } else {
431 nt.Valid = false 436 nt.Valid = false
432 } 437 }
433 return nil 438 return nil
434 } 439 }
435 440
436 func (nt *NullDate) CastToSQL() NullDate { 441 func (nt *NullDate) CastToSQL() NullDate {
437 return *nt 442 return *nt
438 } 443 }
439 444
445 func (nd *NullDate) Format(f string) string {
446 if !nd.Valid {
447 return ""
448 }
449
450 return EpochToDate(nd.Time.Unix(), f)
451 }
452
440 func parseSQLDate(str string, loc *time.Location) (t time.Time, err error) { 453 func parseSQLDate(str string, loc *time.Location) (t time.Time, err error) {
441 base := "0000-00-00" 454 base := "0000-00-00"
442 timeFormat := "2006-01-02" 455 timeFormat := "2006-01-02"
443 switch len(str) { 456 switch len(str) {
444 case 10: 457 case 10:
445 if str == base[:len(str)] { 458 if str == base[:len(str)] {
446 return 459 return
447 } 460 }
448 t, err = time.Parse(timeFormat[:len(str)], str) 461 t, err = time.Parse(timeFormat[:len(str)], str)
449 default: 462 default:
450 err = fmt.Errorf("invalid time string: %s", str) 463 err = fmt.Errorf("invalid time string: %s", str)
451 return 464 return
452 } 465 }
453 466
454 // Adjust location 467 // Adjust location
455 if err == nil && loc != time.UTC { 468 if err == nil && loc != time.UTC {
456 y, mo, d := t.Date() 469 y, mo, d := t.Date()
457 h, mi, s := t.Clock() 470 h, mi, s := t.Clock()
458 t, err = time.Date(y, mo, d, h, mi, s, t.Nanosecond(), loc), nil 471 t, err = time.Date(y, mo, d, h, mi, s, t.Nanosecond(), loc), nil
459 } 472 }
460 473
461 return 474 return
462 } 475 }
463 476
464 // NullTime ... 477 // NullTime ...
465 type NullTime struct { 478 type NullTime struct {
466 Time time.Time 479 Time time.Time
467 Valid bool // Valid is true if Time is not NULL 480 Valid bool // Valid is true if Time is not NULL
468 } 481 }
469 482
470 // Scan ... 483 // Scan ...
471 func (nt *NullTime) Scan(value interface{}) (err error) { 484 func (nt *NullTime) Scan(value interface{}) (err error) {
472 if value == nil { 485 if value == nil {
473 nt.Time, nt.Valid = time.Time{}, false 486 nt.Time, nt.Valid = time.Time{}, false
474 return 487 return
475 } 488 }
476 489
477 switch v := value.(type) { 490 switch v := value.(type) {
478 case time.Time: 491 case time.Time:
479 nt.Time, nt.Valid = v, true 492 nt.Time, nt.Valid = v, true
480 return 493 return
481 case []byte: 494 case []byte:
482 nt.Time, err = parseSQLTime(string(v), time.UTC) 495 nt.Time, err = parseSQLTime(string(v), time.UTC)
483 nt.Valid = (err == nil) 496 nt.Valid = (err == nil)
484 return 497 return
485 case string: 498 case string:
486 nt.Time, err = parseSQLTime(v, time.UTC) 499 nt.Time, err = parseSQLTime(v, time.UTC)
487 nt.Valid = (err == nil) 500 nt.Valid = (err == nil)
488 return 501 return
489 } 502 }
490 503
491 nt.Valid = false 504 nt.Valid = false
492 return fmt.Errorf("Can't convert %T to time.Time", value) 505 return fmt.Errorf("Can't convert %T to time.Time", value)
493 } 506 }
494 507
495 // Value implements the driver Valuer interface. 508 // Value implements the driver Valuer interface.
496 func (nt NullTime) Value() (driver.Value, error) { 509 func (nt NullTime) Value() (driver.Value, error) {
497 if !nt.Valid { 510 if !nt.Valid {
498 return nil, nil 511 return nil, nil
499 } 512 }
500 return nt.Time, nil 513 return nt.Time, nil
501 } 514 }
502 515
503 // MarshalJSON ... 516 // MarshalJSON ...
504 func (nt NullTime) MarshalJSON() ([]byte, error) { 517 func (nt NullTime) MarshalJSON() ([]byte, error) {
505 if nt.Valid { 518 if nt.Valid {
506 format := nt.Time.Format("15:04:05") 519 format := nt.Time.Format("15:04:05")
507 return json.Marshal(format) 520 return json.Marshal(format)
508 } 521 }
509 return json.Marshal(nil) 522 return json.Marshal(nil)
510 } 523 }
511 524
512 // UnmarshalJSON ... 525 // UnmarshalJSON ...
513 func (nt *NullTime) UnmarshalJSON(b []byte) error { 526 func (nt *NullTime) UnmarshalJSON(b []byte) error {
514 var temp *time.Time 527 var temp *time.Time
515 var t1 time.Time 528 var t1 time.Time
516 var err error 529 var err error
517 530
518 s1 := string(b) 531 s1 := string(b)
519 s2 := s1[1 : len(s1)-1] 532 s2 := s1[1 : len(s1)-1]
520 if s1 == "null" { 533 if s1 == "null" {
521 temp = nil 534 temp = nil
522 } else { 535 } else {
523 t1, err = time.Parse("2006-05-04 15:04:05", "1970-01-01 "+s2) 536 t1, err = time.Parse("2006-05-04 15:04:05", "1970-01-01 "+s2)
524 if err != nil { 537 if err != nil {
525 return err 538 return err
526 } 539 }
527 temp = &t1 540 temp = &t1
528 } 541 }
529 542
530 if temp != nil { 543 if temp != nil {
531 nt.Scan(t1) 544 nt.Scan(t1)
532 } else { 545 } else {
533 nt.Valid = false 546 nt.Valid = false
534 } 547 }
535 return nil 548 return nil
536 } 549 }
537 550
538 func (nt *NullTime) CastToSQL() NullTime { 551 func (nt *NullTime) CastToSQL() NullTime {
539 return *nt 552 return *nt
540 } 553 }
541 554
542 // NOTE(marko): Date must be included because database can't convert it to TIME otherwise. 555 // NOTE(marko): Date must be included because database can't convert it to TIME otherwise.
543 func parseSQLTime(str string, loc *time.Location) (t time.Time, err error) { 556 func parseSQLTime(str string, loc *time.Location) (t time.Time, err error) {
544 base := "00:00:00" 557 base := "00:00:00"
545 timeFormat := "15:04:05" 558 timeFormat := "15:04:05"
546 switch len(str) { 559 switch len(str) {
547 case 8: 560 case 8:
548 if str == base[:len(str)] { 561 if str == base[:len(str)] {
549 return 562 return
550 } 563 }
551 t, err = time.Parse("2006-05-04 "+timeFormat[:len(str)], "1970-01-01 "+str) 564 t, err = time.Parse("2006-05-04 "+timeFormat[:len(str)], "1970-01-01 "+str)
552 default: 565 default:
553 err = fmt.Errorf("invalid time string: %s", str) 566 err = fmt.Errorf("invalid time string: %s", str)
554 return 567 return
555 } 568 }
556 569
557 // Adjust location 570 // Adjust location
558 if err == nil && loc != time.UTC { 571 if err == nil && loc != time.UTC {
559 y, mo, d := t.Date() 572 y, mo, d := t.Date()
560 h, mi, s := t.Clock() 573 h, mi, s := t.Clock()
561 t, err = time.Date(y, mo, d, h, mi, s, t.Nanosecond(), loc), nil 574 t, err = time.Date(y, mo, d, h, mi, s, t.Nanosecond(), loc), nil
562 } 575 }
563 576
564 return 577 return
565 } 578 }
566 579
1 package webutility 1 package webutility
2 2
3 import ( 3 import (
4 "database/sql" 4 "database/sql"
5 "fmt" 5 "fmt"
6 "net/http" 6 "net/http"
7 "time"
7 8
8 "git.to-net.rs/marko.tikvic/gologger" 9 "git.to-net.rs/marko.tikvic/gologger"
9 "github.com/gorilla/mux" 10 "github.com/gorilla/mux"
10 ) 11 )
11 12
12 type Server struct { 13 type Server struct {
13 DB *sql.DB 14 DB *sql.DB
14 Router *mux.Router 15 Router *mux.Router
15 Logger *gologger.Logger 16 Logger *gologger.Logger
16 Port string 17 Port string
17 UTCOffset int64 18 DBs map[string]*sql.DB
18 DBs map[string]*sql.DB 19 dsn map[string]string
19 } 20 }
20 21
21 func NewODBCServer(dsn, port, logDir string, utcOffset int64) (s *Server, err error) { 22 func NewODBCServer(dsn, port, logDir string) (s *Server, err error) {
22 s = new(Server) 23 s = new(Server)
23 24
24 s.Port = port 25 s.Port = port
25 26
26 if s.DB, err = sql.Open("odbc", fmt.Sprintf("DSN=%s;", dsn)); err != nil { 27 if s.DB, err = sql.Open("odbc", fmt.Sprintf("DSN=%s;", dsn)); err != nil {
27 return nil, err 28 return nil, err
28 } 29 }
29 30
30 s.Router = mux.NewRouter() 31 s.Router = mux.NewRouter()
31 32
32 if s.Logger, err = gologger.New("err", logDir, gologger.MaxLogSize1MB); err != nil { 33 if s.Logger, err = gologger.New("err", logDir, gologger.MaxLogSize1MB); err != nil {
33 return nil, fmt.Errorf("can't create logger: %s", err.Error()) 34 return nil, fmt.Errorf("can't create logger: %s", err.Error())
34 } 35 }
35 36
36 s.UTCOffset = utcOffset
37
38 s.DBs = make(map[string]*sql.DB) 37 s.DBs = make(map[string]*sql.DB)
39 s.DBs["default"] = s.DB 38 s.DBs["default"] = s.DB
40 39
40 s.dsn = make(map[string]string)
41 s.DBs["default"] = s.DB
42
41 return s, nil 43 return s, nil
42 } 44 }
43 45
44 func (s *Server) Run() { 46 func (s *Server) Run() {
45 s.Logger.Print("Server listening on %s", s.Port) 47 s.Logger.Print("Server listening on %s", s.Port)
46 s.Logger.PrintAndTrace(http.ListenAndServe(s.Port, s.Router).Error()) 48 s.Logger.PrintAndTrace(http.ListenAndServe(s.Port, s.Router).Error())
47 } 49 }
48 50
49 func (s *Server) Cleanup() { 51 func (s *Server) Cleanup() {
50 if s.DB != nil { 52 if s.DB != nil {
51 s.DB.Close() 53 s.DB.Close()
52 } 54 }
53 55
54 if s.Logger != nil { 56 if s.Logger != nil {
55 s.Logger.Close() 57 s.Logger.Close()
56 } 58 }
57 } 59 }
58 60
59 func (s *Server) StartTransaction() (*sql.Tx, error) { 61 func (s *Server) StartTransaction() (*sql.Tx, error) {
60 return s.DB.Begin() 62 return s.DB.Begin()
61 } 63 }
62 64
63 func CommitChanges(tx *sql.Tx, err *error, opt ...error) { 65 func CommitChanges(tx *sql.Tx, err *error, opt ...error) {
64 if *err != nil { 66 if *err != nil {
65 tx.Rollback() 67 tx.Rollback()
66 return 68 return
67 } 69 }
68 70
69 for _, e := range opt { 71 for _, e := range opt {
70 if e != nil { 72 if e != nil {
71 tx.Rollback() 73 tx.Rollback()
72 return 74 return
73 } 75 }
74 } 76 }
75 77
76 if *err = tx.Commit(); *err != nil { 78 if *err = tx.Commit(); *err != nil {
77 tx.Rollback() 79 tx.Rollback()
78 } 80 }
79 } 81 }
82
83 func (s *Server) RefreshDatabaseConnections(period time.Duration) {
84 for {
85 for k, db := range s.DBs {
86 if err := db.Ping(); err != nil {
87 if s.Logger != nil {
88 s.Logger.PrintAndTrace("failed to ping database (%s): %s", s.dsn[k], err.Error())
89 } else {
90 fmt.Println("failed to ping database (%s): %s", s.dsn[k], err.Error())
91 }
92 }
93 }
94 time.Sleep(period)
95 }
1 package webutility 1 package webutility
2 2
3 import ( 3 import (
4 "fmt" 4 "fmt"
5 "strconv" 5 "strconv"
6 "strings" 6 "strings"
7 "unicode" 7 "unicode"
8
9 "golang.org/x/exp/utf8string"
10 ) 8 )
11 9
12 const sanitisationPatern = "\"';&*<>=\\`:" 10 const sanitisationPatern = "\"';&*<>=\\`:"
13 11
14 // SanitiseString removes characters from s found in patern and returns new modified string. 12 // SanitiseString removes characters from s found in patern and returns new modified string.
15 func SanitiseString(s string) string { 13 func SanitiseString(s string) string {
16 return ReplaceAny(s, sanitisationPatern, "") 14 return ReplaceAny(s, sanitisationPatern, "")
17 } 15 }
18 16
19 // IsWrappedWith ... 17 // IsWrappedWith ...
20 func IsWrappedWith(src, begin, end string) bool { 18 func IsWrappedWith(src, begin, end string) bool {
21 return strings.HasPrefix(src, begin) && strings.HasSuffix(src, end) 19 return strings.HasPrefix(src, begin) && strings.HasSuffix(src, end)
22 } 20 }
23 21
24 // ParseInt64Arr ... 22 // ParseInt64Arr ...
25 func ParseInt64Arr(s, sep string) (arr []int64) { 23 func ParseInt64Arr(s, sep string) (arr []int64) {
26 s = strings.TrimSpace(s) 24 s = strings.TrimSpace(s)
27 if s == "" { 25 if s == "" {
28 return 26 return
29 } 27 }
30 parts := strings.Split(s, sep) 28 parts := strings.Split(s, sep)
31 arr = make([]int64, len(parts)) 29 arr = make([]int64, len(parts))
32 for i, p := range parts { 30 for i, p := range parts {
33 num := StringToInt64(p) 31 num := StringToInt64(p)
34 arr[i] = num 32 arr[i] = num
35 } 33 }
36 34
37 return arr 35 return arr
38 } 36 }
39 37
40 // Int64SliceToString ... 38 // Int64SliceToString ...
41 func Int64SliceToString(arr []int64) (s string) { 39 func Int64SliceToString(arr []int64) (s string) {
42 if len(arr) == 0 { 40 if len(arr) == 0 {
43 return "" 41 return ""
44 } 42 }
45 43
46 s += fmt.Sprintf("%d", arr[0]) 44 s += fmt.Sprintf("%d", arr[0])
47 for i := 1; i < len(arr); i++ { 45 for i := 1; i < len(arr); i++ {
48 s += fmt.Sprintf(",%d", arr[i]) 46 s += fmt.Sprintf(",%d", arr[i])
49 } 47 }
50 48
51 return s 49 return s
52 } 50 }
53 51
54 // CombineStrings ... 52 // CombineStrings ...
55 func CombineStrings(s1, s2, s3 string) string { 53 func CombineStrings(s1, s2, s3 string) string {
56 s1 = strings.TrimSpace(s1) 54 s1 = strings.TrimSpace(s1)
57 s2 = strings.TrimSpace(s2) 55 s2 = strings.TrimSpace(s2)
58 56
59 if s1 != "" && s2 != "" { 57 if s1 != "" && s2 != "" {
60 s1 += s3 + s2 58 s1 += s3 + s2
61 } else { 59 } else {
62 s1 += s2 60 s1 += s2
63 } 61 }
64 62
65 return s1 63 return s1
66 } 64 }
67 65
68 // ReplaceAny replaces any of the characters from patern found in s with r and returns a new resulting string. 66 // ReplaceAny replaces any of the characters from patern found in s with r and returns a new resulting string.
69 func ReplaceAny(s, patern, r string) (n string) { 67 func ReplaceAny(s, patern, r string) (n string) {
70 n = s 68 n = s
71 for _, c := range patern { 69 for _, c := range patern {
72 n = strings.Replace(n, string(c), r, -1) 70 n = strings.Replace(n, string(c), r, -1)
73 } 71 }
74 return n 72 return n
75 } 73 }
76 74
77 // StringToBool ... 75 // StringToBool ...
78 func StringToBool(s string) bool { 76 func StringToBool(s string) bool {
79 res, _ := strconv.ParseBool(s) 77 res, _ := strconv.ParseBool(s)
80 return res 78 return res
81 } 79 }
82 80
83 // BoolToString ... 81 // BoolToString ...
84 func BoolToString(b bool) string { 82 func BoolToString(b bool) string {
85 return fmt.Sprintf("%b", b) 83 return fmt.Sprintf("%b", b)
86 } 84 }
87 85
88 // StringSliceContains ... 86 // StringSliceContains ...
89 func StringSliceContains(slice []string, s string) bool { 87 func StringSliceContains(slice []string, s string) bool {
90 for i := range slice { 88 for i := range slice {
91 if slice[i] == s { 89 if slice[i] == s {
92 return true 90 return true
93 } 91 }
94 } 92 }
95 return false 93 return false
96 } 94 }
97 95
98 func SplitString(s, sep string) (res []string) { 96 func SplitString(s, sep string) (res []string) {
99 parts := strings.Split(s, sep) 97 parts := strings.Split(s, sep)
100 for _, p := range parts { 98 for _, p := range parts {
101 if p != "" { 99 if p != "" {
102 res = append(res, p) 100 res = append(res, p)
103 } 101 }
104 } 102 }
105 return res 103 return res
106 } 104 }
107 105
108 // StringAt ... 106 // StringAt ...
109 func StringAt(s string, index int) string { 107 func StringAt(s string, index int) string {
110 if len(s)-1 < index || index < 0 { 108 if len(s)-1 < index || index < 0 {
111 return "" 109 return ""
112 } 110 }
113 111
114 return string(s[index]) 112 return string(s[index])
115 } 113 }
116 114
117 func StringAtRune(s string, index int) string { 115 func StringAtRune(s string, index int) string {
118 str := utf8string.NewString(s) 116 str := []rune(s)
119 max := str.RuneCount() 117 if index < len(str) {
120 if index < max { 118 return string(str[index])
121 return string(str.At(index))
122 } 119 }
123 return "" 120 return ""
124 } 121 }
125 122
126 // SplitText ... 123 // SplitText ...
127 func SplitText(s string, maxLen int) (lines []string) { 124 func SplitText(s string, maxLen int) (lines []string) {
128 runes := []rune(s) 125 runes := []rune(s)
129 126
130 i, start, sep, l := 0, 0, 0, 0 127 i, start, sep, l := 0, 0, 0, 0
131 for i = 0; i < len(runes); i++ { 128 for i = 0; i < len(runes); i++ {
132 c := runes[i] 129 c := runes[i]
133 130
134 if unicode.IsSpace(c) { 131 if unicode.IsSpace(c) {
135 sep = i 132 sep = i
136 } 133 }
137 134
138 if c == '\n' { 135 if c == '\n' {
139 if start != sep { 136 if start != sep {
140 lines = append(lines, string(runes[start:sep])) 137 lines = append(lines, string(runes[start:sep]))
141 } 138 }
142 start = i 139 start = i
143 sep = i 140 sep = i
144 l = 0 141 l = 0
145 } else if l >= maxLen { 142 } else if l >= maxLen {
146 if start != sep { 143 if start != sep {
147 lines = append(lines, string(runes[start:sep])) 144 lines = append(lines, string(runes[start:sep]))
148 sep = i 145 sep = i
149 start = i - 1 146 start = i - 1
150 l = 0 147 l = 0
151 } 148 }
152 } else { 149 } else {
153 l++ 150 l++
154 } 151 }
155 } 152 }
156 if start != i-1 { 153 if start != i-1 {
157 lines = append(lines, string(runes[start:i-1])) 154 lines = append(lines, string(runes[start:i-1]))
158 } 155 }
159 156
160 return lines 157 return lines
161 } 158 }
162 159
163 func CutTextWith(txt string, maxLen int, tail string) string { 160 func CutTextWith(txt string, maxLen int, tail string) string {
164 if len(txt) < maxLen || len(txt) <= len(tail) { 161 if len(txt) < maxLen || len(txt) <= len(tail) {
165 return txt 162 return txt
166 } 163 }
167 164
168 return txt[:maxLen-3] + tail 165 return txt[:maxLen-3] + tail
169 } 166 }
170 167
171 func LimitTextWith(txt string, maxLen int, tail string) string { 168 func LimitTextWith(txt string, maxLen int, tail string) string {
172 if len(txt) <= maxLen { 169 if len(txt) <= maxLen {
173 return txt 170 return txt
174 } 171 }
175 172
176 return txt[:maxLen] + tail 173 return txt[:maxLen] + tail
177 } 174 }
178 175
179 // SplitStringAtWholeWords ... 176 // SplitStringAtWholeWords ...
180 func SplitStringAtWholeWords(s string, maxLen int) (res []string) { 177 func SplitStringAtWholeWords(s string, maxLen int) (res []string) {
181 parts := strings.Split(s, " ") 178 parts := strings.Split(s, " ")
182 179
183 res = append(res, parts[0]) 180 res = append(res, parts[0])
184 i := 0 181 i := 0
185 for j := 1; j < len(parts); j++ { 182 for j := 1; j < len(parts); j++ {
186 p := strings.TrimSpace(parts[j]) 183 p := strings.TrimSpace(parts[j])
187 if len(p) > maxLen { 184 if len(p) > maxLen {
188 // TODO(marko): check if maxLen is >= 3 185 // TODO(marko): check if maxLen is >= 3
189 p = p[0 : maxLen-3] 186 p = p[0 : maxLen-3]
190 p += "..." 187 p += "..."
191 } 188 }
192 if len(res[i])+len(p)+1 <= maxLen { 189 if len(res[i])+len(p)+1 <= maxLen {
193 res[i] += " " + p 190 res[i] += " " + p
194 } else { 191 } else {
195 res = append(res, p) 192 res = append(res, p)
196 i++ 193 i++
197 } 194 }
198 } 195 }
199 196
200 return res 197 return res
201 } 198 }
202 199
203 // StringToInt64 ... 200 // StringToInt64 ...
204 func StringToInt64(s string) int64 { 201 func StringToInt64(s string) int64 {
205 i, _ := strconv.ParseInt(s, 10, 64) 202 i, _ := strconv.ParseInt(s, 10, 64)
206 return i 203 return i
207 } 204 }
208 205
209 // StringToFloat64 ... 206 // StringToFloat64 ...
210 func StringToFloat64(s string) float64 { 207 func StringToFloat64(s string) float64 {
211 f, _ := strconv.ParseFloat(s, 64) 208 f, _ := strconv.ParseFloat(s, 64)
212 return f 209 return f
213 } 210 }
214 211
215 func StringToValidInt64(s string) (int64, bool) { 212 func StringToValidInt64(s string) (int64, bool) {
216 i, err := strconv.ParseInt(s, 10, 64) 213 i, err := strconv.ParseInt(s, 10, 64)
217 if err != nil { 214 if err != nil {
218 return i, false 215 return i, false
219 } 216 }
220 return i, true 217 return i, true
221 } 218 }
222 219