Commit 18fcd6d6bfa31d201c800adb6a1177b34ebb1c46
1 parent
cacf57bd4a
Exists in
master
merged with util package
Showing
8 changed files
with
17 additions
and
20 deletions
Show diff stats
default_values.go
1 | package util | 1 | package webutility |
2 | 2 | ||
3 | // IntOrDefault ... | 3 | // IntOrDefault ... |
4 | func IntOrDefault(v *int) int { | 4 | func IntOrDefault(v *int) int { |
5 | if v != nil { | 5 | if v != nil { |
6 | return *v | 6 | return *v |
7 | } | 7 | } |
8 | return 0 | 8 | return 0 |
9 | } | 9 | } |
10 | 10 | ||
11 | // Int32OrDefault ... | 11 | // Int32OrDefault ... |
12 | func Int32OrDefault(v *int32) int32 { | 12 | func Int32OrDefault(v *int32) int32 { |
13 | if v != nil { | 13 | if v != nil { |
14 | return *v | 14 | return *v |
15 | } | 15 | } |
16 | return 0 | 16 | return 0 |
17 | } | 17 | } |
18 | 18 | ||
19 | // Int64OrDefault ... | 19 | // Int64OrDefault ... |
20 | func Int64OrDefault(v *int64) int64 { | 20 | func Int64OrDefault(v *int64) int64 { |
21 | if v != nil { | 21 | if v != nil { |
22 | return *v | 22 | return *v |
23 | } | 23 | } |
24 | return 0 | 24 | return 0 |
25 | } | 25 | } |
26 | 26 | ||
27 | // Uint32OrDefault ... | 27 | // Uint32OrDefault ... |
28 | func Uint32OrDefault(v *uint32) uint32 { | 28 | func Uint32OrDefault(v *uint32) uint32 { |
29 | if v != nil { | 29 | if v != nil { |
30 | return *v | 30 | return *v |
31 | } | 31 | } |
32 | return 0 | 32 | return 0 |
33 | } | 33 | } |
34 | 34 | ||
35 | // Uint64OrDefault ... | 35 | // Uint64OrDefault ... |
36 | func Uint64OrDefault(v *uint64) uint64 { | 36 | func Uint64OrDefault(v *uint64) uint64 { |
37 | if v != nil { | 37 | if v != nil { |
38 | return *v | 38 | return *v |
39 | } | 39 | } |
40 | return 0 | 40 | return 0 |
41 | } | 41 | } |
42 | 42 | ||
43 | // StringOrDefault ... | 43 | // StringOrDefault ... |
44 | func StringOrDefault(v *string) string { | 44 | func StringOrDefault(v *string) string { |
45 | if v != nil { | 45 | if v != nil { |
46 | return *v | 46 | return *v |
47 | } | 47 | } |
48 | return "" | 48 | return "" |
49 | } | 49 | } |
50 | 50 | ||
51 | // Float32OrDefault ... | 51 | // Float32OrDefault ... |
52 | func Float32OrDefault(v *float32) float32 { | 52 | func Float32OrDefault(v *float32) float32 { |
53 | if v != nil { | 53 | if v != nil { |
54 | return *v | 54 | return *v |
55 | } | 55 | } |
56 | return 0.0 | 56 | return 0.0 |
57 | } | 57 | } |
58 | 58 | ||
59 | // Float64OrDefault ... | 59 | // Float64OrDefault ... |
60 | func Float64OrDefault(v *float64) float64 { | 60 | func Float64OrDefault(v *float64) float64 { |
61 | if v != nil { | 61 | if v != nil { |
62 | return *v | 62 | return *v |
63 | } | 63 | } |
64 | return 0.0 | 64 | return 0.0 |
65 | } | 65 | } |
66 | 66 |
diff.go
1 | package util | 1 | package webutility |
2 | 2 | ||
3 | // Diff ... | 3 | // Diff ... |
4 | func Diff(old, new []int64) (added, removed []int64) { | 4 | func Diff(old, new []int64) (added, removed []int64) { |
5 | for i := range old { | 5 | for i := range old { |
6 | isRemoved := true | 6 | isRemoved := true |
7 | for j := range new { | 7 | for j := range new { |
8 | if old[i] == new[j] { | 8 | if old[i] == new[j] { |
9 | isRemoved = false | 9 | isRemoved = false |
10 | break | 10 | break |
11 | } | 11 | } |
12 | } | 12 | } |
13 | if isRemoved { | 13 | if isRemoved { |
14 | removed = append(removed, old[i]) | 14 | removed = append(removed, old[i]) |
15 | } | 15 | } |
16 | } | 16 | } |
17 | 17 | ||
18 | for i := range new { | 18 | for i := range new { |
19 | isAdded := true | 19 | isAdded := true |
20 | for j := range old { | 20 | for j := range old { |
21 | if new[i] == old[j] { | 21 | if new[i] == old[j] { |
22 | isAdded = false | 22 | isAdded = false |
23 | break | 23 | break |
24 | } | 24 | } |
25 | } | 25 | } |
26 | if isAdded { | 26 | if isAdded { |
27 | added = append(added, new[i]) | 27 | added = append(added, new[i]) |
28 | } | 28 | } |
29 | } | 29 | } |
30 | 30 | ||
31 | return added, removed | 31 | return added, removed |
32 | } | 32 | } |
33 | 33 |
file_util.go
1 | package util | 1 | package webutility |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "bytes" | 4 | "bytes" |
5 | "io" | 5 | "io" |
6 | "io/ioutil" | 6 | "io/ioutil" |
7 | "os" | 7 | "os" |
8 | "strings" | 8 | "strings" |
9 | ) | 9 | ) |
10 | 10 | ||
11 | func ReadFileContent(path string) ([]byte, error) { | 11 | func ReadFileContent(path string) ([]byte, error) { |
12 | f, err := os.Open(path) | 12 | f, err := os.Open(path) |
13 | if err != nil { | 13 | if err != nil { |
14 | return nil, err | 14 | return nil, err |
15 | } | 15 | } |
16 | defer f.Close() | 16 | defer f.Close() |
17 | 17 | ||
18 | buf := &bytes.Buffer{} | 18 | buf := &bytes.Buffer{} |
19 | if _, err = io.Copy(buf, f); err != nil { | 19 | if _, err = io.Copy(buf, f); err != nil { |
20 | return nil, err | 20 | return nil, err |
21 | } | 21 | } |
22 | 22 | ||
23 | return buf.Bytes(), nil | 23 | return buf.Bytes(), nil |
24 | } | 24 | } |
25 | 25 | ||
26 | // ReadFileLines ... | 26 | // ReadFileLines ... |
27 | func ReadFileLines(path string) ([]string, error) { | 27 | func ReadFileLines(path string) ([]string, error) { |
28 | f, err := os.Open(path) | 28 | f, err := os.Open(path) |
29 | if err != nil { | 29 | if err != nil { |
30 | return nil, err | 30 | return nil, err |
31 | } | 31 | } |
32 | defer f.Close() | 32 | defer f.Close() |
33 | 33 | ||
34 | var s strings.Builder | 34 | var s strings.Builder |
35 | 35 | ||
36 | if _, err = io.Copy(&s, f); err != nil { | 36 | if _, err = io.Copy(&s, f); err != nil { |
37 | return nil, err | 37 | return nil, err |
38 | } | 38 | } |
39 | 39 | ||
40 | lines := strings.Split(s.String(), "\n") | 40 | lines := strings.Split(s.String(), "\n") |
41 | for i := range lines { | 41 | for i := range lines { |
42 | lines[i] = strings.TrimRight(lines[i], "\r\n") | 42 | lines[i] = strings.TrimRight(lines[i], "\r\n") |
43 | } | 43 | } |
44 | 44 | ||
45 | return lines, nil | 45 | return lines, nil |
46 | } | 46 | } |
47 | 47 | ||
48 | // LinesToFile ... | 48 | // LinesToFile ... |
49 | func LinesToFile(path string, lines []string) error { | 49 | func LinesToFile(path string, lines []string) error { |
50 | content := "" | 50 | content := "" |
51 | for _, l := range lines { | 51 | for _, l := range lines { |
52 | content += l + "\n" | 52 | content += l + "\n" |
53 | } | 53 | } |
54 | 54 | ||
55 | return ioutil.WriteFile(path, []byte(content), 0644) // drw-r--r-- | 55 | return ioutil.WriteFile(path, []byte(content), 0644) // drw-r--r-- |
56 | } | 56 | } |
57 | 57 | ||
58 | // InsertLine ... | 58 | // InsertLine ... |
59 | func InsertLine(lines *[]string, pos int64, l string) { | 59 | func InsertLine(lines *[]string, pos int64, l string) { |
60 | tail := append([]string{l}, (*lines)[pos:]...) | 60 | tail := append([]string{l}, (*lines)[pos:]...) |
61 | 61 | ||
62 | *lines = append((*lines)[:pos], tail...) | 62 | *lines = append((*lines)[:pos], tail...) |
63 | } | 63 | } |
64 | 64 |
int_util.go
1 | package util | 1 | package webutility |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "fmt" | 4 | "fmt" |
5 | "strconv" | 5 | "strconv" |
6 | ) | 6 | ) |
7 | 7 | ||
8 | // ClampInt64 ... | 8 | // ClampInt64 ... |
9 | func ClampInt64(v, min, max int64) int64 { | 9 | func ClampInt64(v, min, max int64) int64 { |
10 | if v < min { | 10 | if v < min { |
11 | return min | 11 | return min |
12 | } else if v > max { | 12 | } else if v > max { |
13 | return max | 13 | return max |
14 | } | 14 | } |
15 | 15 | ||
16 | return v | 16 | return v |
17 | } | 17 | } |
18 | 18 | ||
19 | // InRangeInt64 ... | 19 | // InRangeInt64 ... |
20 | func InRangeInt64(v, min, max int64) bool { | 20 | func InRangeInt64(v, min, max int64) bool { |
21 | return (v >= min && v <= max) | 21 | return (v >= min && v <= max) |
22 | } | 22 | } |
23 | 23 | ||
24 | // StringToInt64 ... | 24 | // StringToInt64 ... |
25 | func StringToInt64(s string) int64 { | 25 | func StringToInt64(s string) int64 { |
26 | i, _ := strconv.ParseInt(s, 10, 64) | 26 | i, _ := strconv.ParseInt(s, 10, 64) |
27 | return i | 27 | return i |
28 | } | 28 | } |
29 | 29 | ||
30 | // Int64ToString ... | 30 | // Int64ToString ... |
31 | func Int64ToString(i int64) string { | 31 | func Int64ToString(i int64) string { |
32 | return fmt.Sprintf("%d", i) | 32 | return fmt.Sprintf("%d", i) |
33 | } | 33 | } |
34 | 34 | ||
35 | // BoolToInt64 ... | 35 | // BoolToInt64 ... |
36 | func BoolToInt64(b bool) int64 { | 36 | func BoolToInt64(b bool) int64 { |
37 | if b { | 37 | if b { |
38 | return 1 | 38 | return 1 |
39 | } | 39 | } |
40 | return 0 | 40 | return 0 |
41 | } | 41 | } |
42 | 42 | ||
43 | // Int64ToBool ... | 43 | // Int64ToBool ... |
44 | func Int64ToBool(i int64) bool { | 44 | func Int64ToBool(i int64) bool { |
45 | return i != 0 | 45 | return i != 0 |
46 | } | 46 | } |
47 | 47 |
nullables.go
1 | package util | 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 | // SQLCast ... | 57 | // SQLCast ... |
58 | func (nb *NullBool) SQLCast() sql.NullBool { | 58 | func (nb *NullBool) SQLCast() 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 | // MarshalJSON ... | 84 | // MarshalJSON ... |
85 | func (ns NullString) MarshalJSON() ([]byte, error) { | 85 | func (ns NullString) MarshalJSON() ([]byte, error) { |
86 | if ns.Valid { | 86 | if ns.Valid { |
87 | return json.Marshal(ns.String) | 87 | return json.Marshal(ns.String) |
88 | } | 88 | } |
89 | return json.Marshal(nil) | 89 | return json.Marshal(nil) |
90 | } | 90 | } |
91 | 91 | ||
92 | // UnmarshalJSON ... | 92 | // UnmarshalJSON ... |
93 | func (ns *NullString) UnmarshalJSON(b []byte) error { | 93 | func (ns *NullString) UnmarshalJSON(b []byte) error { |
94 | var temp *string | 94 | var temp *string |
95 | if err := json.Unmarshal(b, &temp); err != nil { | 95 | if err := json.Unmarshal(b, &temp); err != nil { |
96 | return err | 96 | return err |
97 | } | 97 | } |
98 | if temp != nil { | 98 | if temp != nil { |
99 | ns.Valid = true | 99 | ns.Valid = true |
100 | ns.String = *temp | 100 | ns.String = *temp |
101 | } else { | 101 | } else { |
102 | ns.Valid = false | 102 | ns.Valid = false |
103 | } | 103 | } |
104 | return nil | 104 | return nil |
105 | } | 105 | } |
106 | 106 | ||
107 | // SQLCast ... | 107 | // SQLCast ... |
108 | func (ns *NullString) SQLCast() sql.NullString { | 108 | func (ns *NullString) SQLCast() sql.NullString { |
109 | return sql.NullString(*ns) | 109 | return sql.NullString(*ns) |
110 | } | 110 | } |
111 | 111 | ||
112 | // NullInt64 is a wrapper for sql.NullInt64 with added JSON (un)marshalling | 112 | // NullInt64 is a wrapper for sql.NullInt64 with added JSON (un)marshalling |
113 | type NullInt64 sql.NullInt64 | 113 | type NullInt64 sql.NullInt64 |
114 | 114 | ||
115 | // Scan ... | 115 | // Scan ... |
116 | func (ni *NullInt64) Scan(value interface{}) error { | 116 | func (ni *NullInt64) Scan(value interface{}) error { |
117 | var i sql.NullInt64 | 117 | var i sql.NullInt64 |
118 | if err := i.Scan(value); err != nil { | 118 | if err := i.Scan(value); err != nil { |
119 | ni.Int64, ni.Valid = 0, false | 119 | ni.Int64, ni.Valid = 0, false |
120 | return err | 120 | return err |
121 | } | 121 | } |
122 | ni.Int64, ni.Valid = i.Int64, i.Valid | 122 | ni.Int64, ni.Valid = i.Int64, i.Valid |
123 | return nil | 123 | return nil |
124 | } | 124 | } |
125 | 125 | ||
126 | // Value ... | 126 | // Value ... |
127 | func (ni *NullInt64) Value() (driver.Value, error) { | 127 | func (ni *NullInt64) Value() (driver.Value, error) { |
128 | if !ni.Valid { | 128 | if !ni.Valid { |
129 | return nil, nil | 129 | return nil, nil |
130 | } | 130 | } |
131 | return ni.Int64, nil | 131 | return ni.Int64, nil |
132 | } | 132 | } |
133 | 133 | ||
134 | // MarshalJSON ... | 134 | // MarshalJSON ... |
135 | func (ni NullInt64) MarshalJSON() ([]byte, error) { | 135 | func (ni NullInt64) MarshalJSON() ([]byte, error) { |
136 | if ni.Valid { | 136 | if ni.Valid { |
137 | return json.Marshal(ni.Int64) | 137 | return json.Marshal(ni.Int64) |
138 | } | 138 | } |
139 | return json.Marshal(nil) | 139 | return json.Marshal(nil) |
140 | } | 140 | } |
141 | 141 | ||
142 | // UnmarshalJSON ... | 142 | // UnmarshalJSON ... |
143 | func (ni *NullInt64) UnmarshalJSON(b []byte) error { | 143 | func (ni *NullInt64) UnmarshalJSON(b []byte) error { |
144 | var temp *int64 | 144 | var temp *int64 |
145 | if err := json.Unmarshal(b, &temp); err != nil { | 145 | if err := json.Unmarshal(b, &temp); err != nil { |
146 | return err | 146 | return err |
147 | } | 147 | } |
148 | if temp != nil { | 148 | if temp != nil { |
149 | ni.Valid = true | 149 | ni.Valid = true |
150 | ni.Int64 = *temp | 150 | ni.Int64 = *temp |
151 | } else { | 151 | } else { |
152 | ni.Valid = false | 152 | ni.Valid = false |
153 | } | 153 | } |
154 | return nil | 154 | return nil |
155 | } | 155 | } |
156 | 156 | ||
157 | // SQLCast ... | 157 | // SQLCast ... |
158 | func (ni *NullInt64) SQLCast() sql.NullInt64 { | 158 | func (ni *NullInt64) SQLCast() sql.NullInt64 { |
159 | return sql.NullInt64(*ni) | 159 | return sql.NullInt64(*ni) |
160 | } | 160 | } |
161 | 161 | ||
162 | // NullFloat64 is a wrapper for sql.NullFloat64 with added JSON (un)marshalling | 162 | // NullFloat64 is a wrapper for sql.NullFloat64 with added JSON (un)marshalling |
163 | type NullFloat64 sql.NullFloat64 | 163 | type NullFloat64 sql.NullFloat64 |
164 | 164 | ||
165 | // Scan ... | 165 | // Scan ... |
166 | func (nf *NullFloat64) Scan(value interface{}) error { | 166 | func (nf *NullFloat64) Scan(value interface{}) error { |
167 | var f sql.NullFloat64 | 167 | var f sql.NullFloat64 |
168 | if err := f.Scan(value); err != nil { | 168 | if err := f.Scan(value); err != nil { |
169 | nf.Float64, nf.Valid = 0.0, false | 169 | nf.Float64, nf.Valid = 0.0, false |
170 | return err | 170 | return err |
171 | } | 171 | } |
172 | nf.Float64, nf.Valid = f.Float64, f.Valid | 172 | nf.Float64, nf.Valid = f.Float64, f.Valid |
173 | return nil | 173 | return nil |
174 | } | 174 | } |
175 | 175 | ||
176 | // Value ... | 176 | // Value ... |
177 | func (nf *NullFloat64) Value() (driver.Value, error) { | 177 | func (nf *NullFloat64) Value() (driver.Value, error) { |
178 | if !nf.Valid { | 178 | if !nf.Valid { |
179 | return nil, nil | 179 | return nil, nil |
180 | } | 180 | } |
181 | return nf.Float64, nil | 181 | return nf.Float64, nil |
182 | } | 182 | } |
183 | 183 | ||
184 | // MarshalJSON ... | 184 | // MarshalJSON ... |
185 | func (nf NullFloat64) MarshalJSON() ([]byte, error) { | 185 | func (nf NullFloat64) MarshalJSON() ([]byte, error) { |
186 | if nf.Valid { | 186 | if nf.Valid { |
187 | return json.Marshal(nf.Float64) | 187 | return json.Marshal(nf.Float64) |
188 | } | 188 | } |
189 | return json.Marshal(nil) | 189 | return json.Marshal(nil) |
190 | } | 190 | } |
191 | 191 | ||
192 | // UnmarshalJSON ... | 192 | // UnmarshalJSON ... |
193 | func (nf *NullFloat64) UnmarshalJSON(b []byte) error { | 193 | func (nf *NullFloat64) UnmarshalJSON(b []byte) error { |
194 | var temp *float64 | 194 | var temp *float64 |
195 | if err := json.Unmarshal(b, &temp); err != nil { | 195 | if err := json.Unmarshal(b, &temp); err != nil { |
196 | return err | 196 | return err |
197 | } | 197 | } |
198 | if temp != nil { | 198 | if temp != nil { |
199 | nf.Valid = true | 199 | nf.Valid = true |
200 | nf.Float64 = *temp | 200 | nf.Float64 = *temp |
201 | } else { | 201 | } else { |
202 | nf.Valid = false | 202 | nf.Valid = false |
203 | } | 203 | } |
204 | return nil | 204 | return nil |
205 | } | 205 | } |
206 | 206 | ||
207 | // SQLCast ... | 207 | // SQLCast ... |
208 | func (nf *NullFloat64) SQLCast() sql.NullFloat64 { | 208 | func (nf *NullFloat64) SQLCast() sql.NullFloat64 { |
209 | return sql.NullFloat64(*nf) | 209 | return sql.NullFloat64(*nf) |
210 | } | 210 | } |
211 | 211 | ||
212 | // NullTime ... | 212 | // NullTime ... |
213 | type NullTime struct { | 213 | type NullTime struct { |
214 | Time time.Time | 214 | Time time.Time |
215 | Valid bool // Valid is true if Time is not NULL | 215 | Valid bool // Valid is true if Time is not NULL |
216 | } | 216 | } |
217 | 217 | ||
218 | // Scan ... | 218 | // Scan ... |
219 | func (nt *NullTime) Scan(value interface{}) (err error) { | 219 | func (nt *NullTime) Scan(value interface{}) (err error) { |
220 | if value == nil { | 220 | if value == nil { |
221 | nt.Time, nt.Valid = time.Time{}, false | 221 | nt.Time, nt.Valid = time.Time{}, false |
222 | return | 222 | return |
223 | } | 223 | } |
224 | 224 | ||
225 | switch v := value.(type) { | 225 | switch v := value.(type) { |
226 | case time.Time: | 226 | case time.Time: |
227 | nt.Time, nt.Valid = v, true | 227 | nt.Time, nt.Valid = v, true |
228 | return | 228 | return |
229 | case []byte: | 229 | case []byte: |
230 | nt.Time, err = parseDateTime(string(v), time.UTC) | 230 | nt.Time, err = parseDateTime(string(v), time.UTC) |
231 | nt.Valid = (err == nil) | 231 | nt.Valid = (err == nil) |
232 | return | 232 | return |
233 | case string: | 233 | case string: |
234 | nt.Time, err = parseDateTime(v, time.UTC) | 234 | nt.Time, err = parseDateTime(v, time.UTC) |
235 | nt.Valid = (err == nil) | 235 | nt.Valid = (err == nil) |
236 | return | 236 | return |
237 | } | 237 | } |
238 | 238 | ||
239 | nt.Valid = false | 239 | nt.Valid = false |
240 | return fmt.Errorf("Can't convert %T to time.Time", value) | 240 | return fmt.Errorf("Can't convert %T to time.Time", value) |
241 | } | 241 | } |
242 | 242 | ||
243 | // Value implements the driver Valuer interface. | 243 | // Value implements the driver Valuer interface. |
244 | func (nt NullTime) Value() (driver.Value, error) { | 244 | func (nt NullTime) Value() (driver.Value, error) { |
245 | if !nt.Valid { | 245 | if !nt.Valid { |
246 | return nil, nil | 246 | return nil, nil |
247 | } | 247 | } |
248 | return nt.Time, nil | 248 | return nt.Time, nil |
249 | } | 249 | } |
250 | 250 | ||
251 | // MarshalJSON ... | 251 | // MarshalJSON ... |
252 | func (nt NullTime) MarshalJSON() ([]byte, error) { | 252 | func (nt NullTime) MarshalJSON() ([]byte, error) { |
253 | if nt.Valid { | 253 | if nt.Valid { |
254 | format := nt.Time.Format("2006-01-02 15:04:05") | 254 | format := nt.Time.Format("2006-01-02 15:04:05") |
255 | return json.Marshal(format) | 255 | return json.Marshal(format) |
256 | } | 256 | } |
257 | return json.Marshal(nil) | 257 | return json.Marshal(nil) |
258 | } | 258 | } |
259 | 259 | ||
260 | // UnmarshalJSON ... | 260 | // UnmarshalJSON ... |
261 | func (nt *NullTime) UnmarshalJSON(b []byte) error { | 261 | func (nt *NullTime) UnmarshalJSON(b []byte) error { |
262 | var temp *time.Time | 262 | var temp *time.Time |
263 | var t1 time.Time | 263 | var t1 time.Time |
264 | var err error | 264 | var err error |
265 | 265 | ||
266 | s1 := string(b) | 266 | s1 := string(b) |
267 | s2 := s1[1 : len(s1)-1] | 267 | s2 := s1[1 : len(s1)-1] |
268 | if s1 == "null" { | 268 | if s1 == "null" { |
269 | temp = nil | 269 | temp = nil |
270 | } else { | 270 | } else { |
271 | t1, err = time.Parse("2006-01-02 15:04:05", s2) | 271 | t1, err = time.Parse("2006-01-02 15:04:05", s2) |
272 | if err != nil { | 272 | if err != nil { |
273 | return err | 273 | return err |
274 | } | 274 | } |
275 | temp = &t1 | 275 | temp = &t1 |
276 | } | 276 | } |
277 | 277 | ||
278 | if temp != nil { | 278 | if temp != nil { |
279 | nt.Valid = true | 279 | nt.Valid = true |
280 | nt.Time = *temp | 280 | nt.Time = *temp |
281 | } else { | 281 | } else { |
282 | nt.Valid = false | 282 | nt.Valid = false |
283 | } | 283 | } |
284 | return nil | 284 | return nil |
285 | } | 285 | } |
286 | 286 | ||
287 | func parseDateTime(str string, loc *time.Location) (t time.Time, err error) { | 287 | func parseDateTime(str string, loc *time.Location) (t time.Time, err error) { |
288 | base := "0000-00-00 00:00:00.0000000" | 288 | base := "0000-00-00 00:00:00.0000000" |
289 | timeFormat := "2006-01-02 15:04:05.999999" | 289 | timeFormat := "2006-01-02 15:04:05.999999" |
290 | switch len(str) { | 290 | switch len(str) { |
291 | case 10, 19, 21, 22, 23, 24, 25, 26: // up to "YYYY-MM-DD HH:MM:SS.MMMMMM" | 291 | case 10, 19, 21, 22, 23, 24, 25, 26: // up to "YYYY-MM-DD HH:MM:SS.MMMMMM" |
292 | if str == base[:len(str)] { | 292 | if str == base[:len(str)] { |
293 | return | 293 | return |
294 | } | 294 | } |
295 | t, err = time.Parse(timeFormat[:len(str)], str) | 295 | t, err = time.Parse(timeFormat[:len(str)], str) |
296 | default: | 296 | default: |
297 | err = fmt.Errorf("invalid time string: %s", str) | 297 | err = fmt.Errorf("invalid time string: %s", str) |
298 | return | 298 | return |
299 | } | 299 | } |
300 | 300 | ||
301 | // Adjust location | 301 | // Adjust location |
302 | if err == nil && loc != time.UTC { | 302 | if err == nil && loc != time.UTC { |
303 | y, mo, d := t.Date() | 303 | y, mo, d := t.Date() |
304 | h, mi, s := t.Clock() | 304 | h, mi, s := t.Clock() |
305 | t, err = time.Date(y, mo, d, h, mi, s, t.Nanosecond(), loc), nil | 305 | t, err = time.Date(y, mo, d, h, mi, s, t.Nanosecond(), loc), nil |
306 | } | 306 | } |
307 | 307 | ||
308 | return | 308 | return |
309 | } | 309 | } |
310 | 310 |
payload.go
1 | package webutility | 1 | package webutility |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "database/sql" | 4 | "database/sql" |
5 | "encoding/json" | 5 | "encoding/json" |
6 | "errors" | 6 | "errors" |
7 | "fmt" | 7 | "fmt" |
8 | "io" | 8 | "io" |
9 | "net/http" | 9 | "net/http" |
10 | "strings" | 10 | "strings" |
11 | "sync" | 11 | "sync" |
12 | "time" | 12 | "time" |
13 | 13 | ||
14 | "git.to-net.rs/marko.tikvic/gologger" | 14 | "git.to-net.rs/marko.tikvic/gologger" |
15 | "git.to-net.rs/marko.tikvic/util" | ||
16 | ) | 15 | ) |
17 | 16 | ||
18 | var ( | 17 | var ( |
19 | mu = &sync.Mutex{} | 18 | mu = &sync.Mutex{} |
20 | metadata = make(map[string]Payload) | 19 | metadata = make(map[string]Payload) |
21 | 20 | ||
22 | updateQue = make(map[string][]byte) | 21 | updateQue = make(map[string][]byte) |
23 | 22 | ||
24 | metadataDB *sql.DB | 23 | metadataDB *sql.DB |
25 | activeProject string | 24 | activeProject string |
26 | 25 | ||
27 | inited bool | 26 | inited bool |
28 | driver string | 27 | metaDriver string |
29 | logger *gologger.Logger | 28 | logger *gologger.Logger |
30 | ) | 29 | ) |
31 | 30 | ||
32 | // LangMap ... | 31 | // LangMap ... |
33 | type LangMap map[string]map[string]string | 32 | type LangMap map[string]map[string]string |
34 | 33 | ||
35 | // Field ... | 34 | // Field ... |
36 | type Field struct { | 35 | type Field struct { |
37 | Parameter string `json:"param"` | 36 | Parameter string `json:"param"` |
38 | Type string `json:"type"` | 37 | Type string `json:"type"` |
39 | Visible bool `json:"visible"` | 38 | Visible bool `json:"visible"` |
40 | Editable bool `json:"editable"` | 39 | Editable bool `json:"editable"` |
41 | } | 40 | } |
42 | 41 | ||
43 | // CorrelationField ... | 42 | // CorrelationField ... |
44 | type CorrelationField struct { | 43 | type CorrelationField struct { |
45 | Result string `json:"result"` | 44 | Result string `json:"result"` |
46 | Elements []string `json:"elements"` | 45 | Elements []string `json:"elements"` |
47 | Type string `json:"type"` | 46 | Type string `json:"type"` |
48 | } | 47 | } |
49 | 48 | ||
50 | // Translation ... | 49 | // Translation ... |
51 | type Translation struct { | 50 | type Translation struct { |
52 | Language string `json:"language"` | 51 | Language string `json:"language"` |
53 | FieldsLabels map[string]string `json:"fieldsLabels"` | 52 | FieldsLabels map[string]string `json:"fieldsLabels"` |
54 | } | 53 | } |
55 | 54 | ||
56 | // PaginationLinks ... | 55 | // PaginationLinks ... |
57 | type PaginationLinks struct { | 56 | type PaginationLinks struct { |
58 | Base string `json:"base"` | 57 | Base string `json:"base"` |
59 | Next string `json:"next"` | 58 | Next string `json:"next"` |
60 | Prev string `json:"prev"` | 59 | Prev string `json:"prev"` |
61 | Self string `json:"self"` | 60 | Self string `json:"self"` |
62 | } | 61 | } |
63 | 62 | ||
64 | // PaginationParameters ... | 63 | // PaginationParameters ... |
65 | type PaginationParameters struct { | 64 | type PaginationParameters struct { |
66 | URL string `json:"-"` | 65 | URL string `json:"-"` |
67 | Offset int64 `json:"offset"` | 66 | Offset int64 `json:"offset"` |
68 | Limit int64 `json:"limit"` | 67 | Limit int64 `json:"limit"` |
69 | SortBy string `json:"sortBy"` | 68 | SortBy string `json:"sortBy"` |
70 | Order string `json:"order"` | 69 | Order string `json:"order"` |
71 | } | 70 | } |
72 | 71 | ||
73 | // GetPaginationParameters ... | 72 | // GetPaginationParameters ... |
74 | // TODO(marko) | 73 | // TODO(marko) |
75 | func GetPaginationParameters(req *http.Request) (p PaginationParameters) { | 74 | func GetPaginationParameters(req *http.Request) (p PaginationParameters) { |
76 | return p | 75 | return p |
77 | } | 76 | } |
78 | 77 | ||
79 | // TODO(marko) | 78 | // TODO(marko) |
80 | func (p *PaginationParameters) paginationLinks() (links PaginationLinks) { | 79 | func (p *PaginationParameters) paginationLinks() (links PaginationLinks) { |
81 | return links | 80 | return links |
82 | } | 81 | } |
83 | 82 | ||
84 | // Payload ... | 83 | // Payload ... |
85 | type Payload struct { | 84 | type Payload struct { |
86 | Method string `json:"method"` | 85 | Method string `json:"method"` |
87 | Params map[string]string `json:"params"` | 86 | Params map[string]string `json:"params"` |
88 | Lang []Translation `json:"lang"` | 87 | Lang []Translation `json:"lang"` |
89 | Fields []Field `json:"fields"` | 88 | Fields []Field `json:"fields"` |
90 | Correlations []CorrelationField `json:"correlationFields"` | 89 | Correlations []CorrelationField `json:"correlationFields"` |
91 | IDField string `json:"idField"` | 90 | IDField string `json:"idField"` |
92 | 91 | ||
93 | // Pagination | 92 | // Pagination |
94 | Count int64 `json:"count"` | 93 | Count int64 `json:"count"` |
95 | Total int64 `json:"total"` | 94 | Total int64 `json:"total"` |
96 | Links PaginationLinks `json:"_links"` | 95 | Links PaginationLinks `json:"_links"` |
97 | 96 | ||
98 | // Data holds JSON payload. It can't be used for itteration. | 97 | // Data holds JSON payload. It can't be used for itteration. |
99 | Data interface{} `json:"data"` | 98 | Data interface{} `json:"data"` |
100 | } | 99 | } |
101 | 100 | ||
102 | func (p *Payload) addLang(code string, labels map[string]string) { | 101 | func (p *Payload) addLang(code string, labels map[string]string) { |
103 | t := Translation{ | 102 | t := Translation{ |
104 | Language: code, | 103 | Language: code, |
105 | FieldsLabels: labels, | 104 | FieldsLabels: labels, |
106 | } | 105 | } |
107 | p.Lang = append(p.Lang, t) | 106 | p.Lang = append(p.Lang, t) |
108 | } | 107 | } |
109 | 108 | ||
110 | // SetData ... | 109 | // SetData ... |
111 | func (p *Payload) SetData(data interface{}) { | 110 | func (p *Payload) SetData(data interface{}) { |
112 | p.Data = data | 111 | p.Data = data |
113 | } | 112 | } |
114 | 113 | ||
115 | // SetPaginationInfo ... | 114 | // SetPaginationInfo ... |
116 | func (p *Payload) SetPaginationInfo(count, total int64, params PaginationParameters) { | 115 | func (p *Payload) SetPaginationInfo(count, total int64, params PaginationParameters) { |
117 | p.Count = count | 116 | p.Count = count |
118 | p.Total = total | 117 | p.Total = total |
119 | p.Links = params.paginationLinks() | 118 | p.Links = params.paginationLinks() |
120 | } | 119 | } |
121 | 120 | ||
122 | // NewPayload returs a payload sceleton for entity described with key. | 121 | // NewPayload returs a payload sceleton for entity described with key. |
123 | func NewPayload(r *http.Request, key string) Payload { | 122 | func NewPayload(r *http.Request, key string) Payload { |
124 | p := metadata[key] | 123 | p := metadata[key] |
125 | p.Method = r.Method + " " + r.RequestURI | 124 | p.Method = r.Method + " " + r.RequestURI |
126 | return p | 125 | return p |
127 | } | 126 | } |
128 | 127 | ||
129 | // DecodeJSON decodes JSON data from r to v. | 128 | // DecodeJSON decodes JSON data from r to v. |
130 | // Returns an error if it fails. | 129 | // Returns an error if it fails. |
131 | func DecodeJSON(r io.Reader, v interface{}) error { | 130 | func DecodeJSON(r io.Reader, v interface{}) error { |
132 | return json.NewDecoder(r).Decode(v) | 131 | return json.NewDecoder(r).Decode(v) |
133 | } | 132 | } |
134 | 133 | ||
135 | // InitPayloadsMetadata loads all payloads' information into 'metadata' variable. | 134 | // InitPayloadsMetadata loads all payloads' information into 'metadata' variable. |
136 | func InitPayloadsMetadata(drv string, db *sql.DB, project string) error { | 135 | func InitPayloadsMetadata(drv string, db *sql.DB, project string) error { |
137 | var err error | 136 | var err error |
138 | if drv != "ora" && drv != "mysql" { | 137 | if drv != "ora" && drv != "mysql" { |
139 | err = errors.New("driver not supported") | 138 | err = errors.New("driver not supported") |
140 | return err | 139 | return err |
141 | } | 140 | } |
142 | 141 | ||
143 | driver = drv | 142 | metaDriver = drv |
144 | metadataDB = db | 143 | metadataDB = db |
145 | activeProject = project | 144 | activeProject = project |
146 | 145 | ||
147 | logger, err = gologger.New("metadata", gologger.MaxLogSize100KB) | 146 | logger, err = gologger.New("metadata", gologger.MaxLogSize100KB) |
148 | if err != nil { | 147 | if err != nil { |
149 | fmt.Printf("webutility: %s\n", err.Error()) | 148 | fmt.Printf("webutility: %s\n", err.Error()) |
150 | } | 149 | } |
151 | 150 | ||
152 | mu.Lock() | 151 | mu.Lock() |
153 | defer mu.Unlock() | 152 | defer mu.Unlock() |
154 | err = initMetadata(project) | 153 | err = initMetadata(project) |
155 | if err != nil { | 154 | if err != nil { |
156 | return err | 155 | return err |
157 | } | 156 | } |
158 | inited = true | 157 | inited = true |
159 | 158 | ||
160 | return nil | 159 | return nil |
161 | } | 160 | } |
162 | 161 | ||
163 | // EnableHotloading ... | 162 | // EnableHotloading ... |
164 | func EnableHotloading(interval int) { | 163 | func EnableHotloading(interval int) { |
165 | if interval > 0 { | 164 | if interval > 0 { |
166 | go hotload(interval) | 165 | go hotload(interval) |
167 | } | 166 | } |
168 | } | 167 | } |
169 | 168 | ||
170 | // GetMetadataForAllEntities ... | 169 | // GetMetadataForAllEntities ... |
171 | func GetMetadataForAllEntities() map[string]Payload { | 170 | func GetMetadataForAllEntities() map[string]Payload { |
172 | return metadata | 171 | return metadata |
173 | } | 172 | } |
174 | 173 | ||
175 | // GetMetadataForEntity ... | 174 | // GetMetadataForEntity ... |
176 | func GetMetadataForEntity(t string) (Payload, bool) { | 175 | func GetMetadataForEntity(t string) (Payload, bool) { |
177 | p, ok := metadata[t] | 176 | p, ok := metadata[t] |
178 | return p, ok | 177 | return p, ok |
179 | } | 178 | } |
180 | 179 | ||
181 | // QueEntityModelUpdate ... | 180 | // QueEntityModelUpdate ... |
182 | func QueEntityModelUpdate(entityType string, v interface{}) { | 181 | func QueEntityModelUpdate(entityType string, v interface{}) { |
183 | updateQue[entityType], _ = json.Marshal(v) | 182 | updateQue[entityType], _ = json.Marshal(v) |
184 | } | 183 | } |
185 | 184 | ||
186 | // UpdateEntityModels ... | 185 | // UpdateEntityModels ... |
187 | func UpdateEntityModels(command string) (total, upd, add int, err error) { | 186 | func UpdateEntityModels(command string) (total, upd, add int, err error) { |
188 | if command != "force" && command != "missing" { | 187 | if command != "force" && command != "missing" { |
189 | return total, 0, 0, errors.New("webutility: unknown command: " + command) | 188 | return total, 0, 0, errors.New("webutility: unknown command: " + command) |
190 | } | 189 | } |
191 | 190 | ||
192 | if !inited { | 191 | if !inited { |
193 | return 0, 0, 0, errors.New("webutility: metadata not initialized but update was tried") | 192 | return 0, 0, 0, errors.New("webutility: metadata not initialized but update was tried") |
194 | } | 193 | } |
195 | 194 | ||
196 | total = len(updateQue) | 195 | total = len(updateQue) |
197 | 196 | ||
198 | toUpdate := make([]string, 0) | 197 | toUpdate := make([]string, 0) |
199 | toAdd := make([]string, 0) | 198 | toAdd := make([]string, 0) |
200 | 199 | ||
201 | for k := range updateQue { | 200 | for k := range updateQue { |
202 | if _, exists := metadata[k]; exists { | 201 | if _, exists := metadata[k]; exists { |
203 | if command == "force" { | 202 | if command == "force" { |
204 | toUpdate = append(toUpdate, k) | 203 | toUpdate = append(toUpdate, k) |
205 | } | 204 | } |
206 | } else { | 205 | } else { |
207 | toAdd = append(toAdd, k) | 206 | toAdd = append(toAdd, k) |
208 | } | 207 | } |
209 | } | 208 | } |
210 | 209 | ||
211 | var uStmt *sql.Stmt | 210 | var uStmt *sql.Stmt |
212 | if driver == "ora" { | 211 | if metaDriver == "ora" { |
213 | uStmt, err = metadataDB.Prepare("update entities set entity_model = :1 where entity_type = :2") | 212 | uStmt, err = metadataDB.Prepare("update entities set entity_model = :1 where entity_type = :2") |
214 | if err != nil { | 213 | if err != nil { |
215 | logger.Trace(err.Error()) | 214 | logger.Trace(err.Error()) |
216 | return | 215 | return |
217 | } | 216 | } |
218 | } else if driver == "mysql" { | 217 | } else if metaDriver == "mysql" { |
219 | uStmt, err = metadataDB.Prepare("update entities set entity_model = ? where entity_type = ?") | 218 | uStmt, err = metadataDB.Prepare("update entities set entity_model = ? where entity_type = ?") |
220 | if err != nil { | 219 | if err != nil { |
221 | logger.Trace(err.Error()) | 220 | logger.Trace(err.Error()) |
222 | return | 221 | return |
223 | } | 222 | } |
224 | } | 223 | } |
225 | for _, k := range toUpdate { | 224 | for _, k := range toUpdate { |
226 | _, err = uStmt.Exec(string(updateQue[k]), k) | 225 | _, err = uStmt.Exec(string(updateQue[k]), k) |
227 | if err != nil { | 226 | if err != nil { |
228 | logger.Trace(err.Error()) | 227 | logger.Trace(err.Error()) |
229 | return | 228 | return |
230 | } | 229 | } |
231 | upd++ | 230 | upd++ |
232 | } | 231 | } |
233 | 232 | ||
234 | blankPayload, _ := json.Marshal(Payload{}) | 233 | blankPayload, _ := json.Marshal(Payload{}) |
235 | var iStmt *sql.Stmt | 234 | var iStmt *sql.Stmt |
236 | if driver == "ora" { | 235 | if metaDriver == "ora" { |
237 | iStmt, err = metadataDB.Prepare("insert into entities(projekat, metadata, entity_type, entity_model) values(:1, :2, :3, :4)") | 236 | iStmt, err = metadataDB.Prepare("insert into entities(projekat, metadata, entity_type, entity_model) values(:1, :2, :3, :4)") |
238 | if err != nil { | 237 | if err != nil { |
239 | logger.Trace(err.Error()) | 238 | logger.Trace(err.Error()) |
240 | return | 239 | return |
241 | } | 240 | } |
242 | } else if driver == "mysql" { | 241 | } else if metaDriver == "mysql" { |
243 | iStmt, err = metadataDB.Prepare("insert into entities(projekat, metadata, entity_type, entity_model) values(?, ?, ?, ?)") | 242 | iStmt, err = metadataDB.Prepare("insert into entities(projekat, metadata, entity_type, entity_model) values(?, ?, ?, ?)") |
244 | if err != nil { | 243 | if err != nil { |
245 | logger.Trace(err.Error()) | 244 | logger.Trace(err.Error()) |
246 | return | 245 | return |
247 | } | 246 | } |
248 | } | 247 | } |
249 | for _, k := range toAdd { | 248 | for _, k := range toAdd { |
250 | _, err = iStmt.Exec(activeProject, string(blankPayload), k, string(updateQue[k])) | 249 | _, err = iStmt.Exec(activeProject, string(blankPayload), k, string(updateQue[k])) |
251 | if err != nil { | 250 | if err != nil { |
252 | logger.Trace(err.Error()) | 251 | logger.Trace(err.Error()) |
253 | return | 252 | return |
254 | } | 253 | } |
255 | metadata[k] = Payload{} | 254 | metadata[k] = Payload{} |
256 | add++ | 255 | add++ |
257 | } | 256 | } |
258 | 257 | ||
259 | return total, upd, add, nil | 258 | return total, upd, add, nil |
260 | } | 259 | } |
261 | 260 | ||
262 | func initMetadata(project string) error { | 261 | func initMetadata(project string) error { |
263 | rows, err := metadataDB.Query(`select | 262 | rows, err := metadataDB.Query(`select |
264 | entity_type, | 263 | entity_type, |
265 | metadata | 264 | metadata |
266 | from entities | 265 | from entities |
267 | where projekat = ` + fmt.Sprintf("'%s'", project)) | 266 | where projekat = ` + fmt.Sprintf("'%s'", project)) |
268 | if err != nil { | 267 | if err != nil { |
269 | return err | 268 | return err |
270 | } | 269 | } |
271 | defer rows.Close() | 270 | defer rows.Close() |
272 | 271 | ||
273 | if len(metadata) > 0 { | 272 | if len(metadata) > 0 { |
274 | metadata = nil | 273 | metadata = nil |
275 | } | 274 | } |
276 | metadata = make(map[string]Payload) | 275 | metadata = make(map[string]Payload) |
277 | for rows.Next() { | 276 | for rows.Next() { |
278 | var name, load string | 277 | var name, load string |
279 | rows.Scan(&name, &load) | 278 | rows.Scan(&name, &load) |
280 | 279 | ||
281 | p := Payload{} | 280 | p := Payload{} |
282 | err := json.Unmarshal([]byte(load), &p) | 281 | err := json.Unmarshal([]byte(load), &p) |
283 | if err != nil { | 282 | if err != nil { |
284 | logger.Log("webutility: couldn't init: '%s' metadata: %s:\n%s\n", name, err.Error(), load) | 283 | logger.Log("webutility: couldn't init: '%s' metadata: %s:\n%s\n", name, err.Error(), load) |
285 | } else { | 284 | } else { |
286 | metadata[name] = p | 285 | metadata[name] = p |
287 | } | 286 | } |
288 | } | 287 | } |
289 | 288 | ||
290 | return nil | 289 | return nil |
291 | } | 290 | } |
292 | 291 | ||
293 | // LoadMetadataFromFile expects file in format: | 292 | // LoadMetadataFromFile expects file in format: |
294 | // | 293 | // |
295 | // [ payload A identifier ] | 294 | // [ payload A identifier ] |
296 | // key1 = value1 | 295 | // key1 = value1 |
297 | // key2 = value2 | 296 | // key2 = value2 |
298 | // ... | 297 | // ... |
299 | // [ payload B identifier ] | 298 | // [ payload B identifier ] |
300 | // key1 = value1 | 299 | // key1 = value1 |
301 | // key2 = value2 | 300 | // key2 = value2 |
302 | // ... | 301 | // ... |
303 | // | 302 | // |
304 | // TODO(marko): Currently supports only one hardcoded language... | 303 | // TODO(marko): Currently supports only one hardcoded language... |
305 | func LoadMetadataFromFile(path string) error { | 304 | func LoadMetadataFromFile(path string) error { |
306 | lines, err := util.ReadFileLines(path) | 305 | lines, err := ReadFileLines(path) |
307 | if err != nil { | 306 | if err != nil { |
308 | return err | 307 | return err |
309 | } | 308 | } |
310 | 309 | ||
311 | metadata = make(map[string]Payload) | 310 | metadata = make(map[string]Payload) |
312 | 311 | ||
313 | var name string | 312 | var name string |
314 | for i, l := range lines { | 313 | for i, l := range lines { |
315 | // skip empty lines | 314 | // skip empty lines |
316 | if l = strings.TrimSpace(l); len(l) == 0 { | 315 | if l = strings.TrimSpace(l); len(l) == 0 { |
317 | continue | 316 | continue |
318 | } | 317 | } |
319 | 318 | ||
320 | if util.IsWrappedWith(l, "[", "]") { | 319 | if IsWrappedWith(l, "[", "]") { |
321 | name = strings.Trim(l, "[]") | 320 | name = strings.Trim(l, "[]") |
322 | p := Payload{} | 321 | p := Payload{} |
323 | p.addLang("sr", make(map[string]string)) | 322 | p.addLang("sr", make(map[string]string)) |
324 | metadata[name] = p | 323 | metadata[name] = p |
325 | continue | 324 | continue |
326 | } | 325 | } |
327 | 326 | ||
328 | if name == "" { | 327 | if name == "" { |
329 | return fmt.Errorf("webutility: LoadMetadataFromFile: error on line %d: [no header] [%s]", i+1, l) | 328 | return fmt.Errorf("webutility: LoadMetadataFromFile: error on line %d: [no header] [%s]", i+1, l) |
330 | } | 329 | } |
331 | 330 | ||
332 | parts := strings.Split(l, "=") | 331 | parts := strings.Split(l, "=") |
333 | if len(parts) != 2 { | 332 | if len(parts) != 2 { |
334 | return fmt.Errorf("webutility: LoadMetadataFromFile: error on line %d: [invalid format] [%s]", i+1, l) | 333 | return fmt.Errorf("webutility: LoadMetadataFromFile: error on line %d: [invalid format] [%s]", i+1, l) |
335 | } | 334 | } |
336 | 335 | ||
337 | k := strings.TrimSpace(parts[0]) | 336 | k := strings.TrimSpace(parts[0]) |
338 | v := strings.TrimSpace(parts[1]) | 337 | v := strings.TrimSpace(parts[1]) |
339 | if v != "-" { | 338 | if v != "-" { |
340 | metadata[name].Lang[0].FieldsLabels[k] = v | 339 | metadata[name].Lang[0].FieldsLabels[k] = v |
341 | } | 340 | } |
342 | } | 341 | } |
343 | 342 | ||
344 | return nil | 343 | return nil |
345 | } | 344 | } |
346 | 345 | ||
347 | func hotload(n int) { | 346 | func hotload(n int) { |
348 | entityScan := make(map[string]int64) | 347 | entityScan := make(map[string]int64) |
349 | firstCheck := true | 348 | firstCheck := true |
350 | for { | 349 | for { |
351 | time.Sleep(time.Duration(n) * time.Second) | 350 | time.Sleep(time.Duration(n) * time.Second) |
352 | rows, err := metadataDB.Query(`select | 351 | rows, err := metadataDB.Query(`select |
353 | ora_rowscn, | 352 | ora_rowscn, |
354 | entity_type | 353 | entity_type |
355 | from entities where projekat = ` + fmt.Sprintf("'%s'", activeProject)) | 354 | from entities where projekat = ` + fmt.Sprintf("'%s'", activeProject)) |
356 | if err != nil { | 355 | if err != nil { |
357 | logger.Log("webutility: hotload failed: %v\n", err) | 356 | logger.Log("webutility: hotload failed: %v\n", err) |
358 | time.Sleep(time.Duration(n) * time.Second) | 357 | time.Sleep(time.Duration(n) * time.Second) |
359 | continue | 358 | continue |
360 | } | 359 | } |
361 | 360 | ||
362 | var toRefresh []string | 361 | var toRefresh []string |
363 | for rows.Next() { | 362 | for rows.Next() { |
364 | var scanID int64 | 363 | var scanID int64 |
365 | var entity string | 364 | var entity string |
366 | rows.Scan(&scanID, &entity) | 365 | rows.Scan(&scanID, &entity) |
367 | oldID, ok := entityScan[entity] | 366 | oldID, ok := entityScan[entity] |
368 | if !ok || oldID != scanID { | 367 | if !ok || oldID != scanID { |
369 | entityScan[entity] = scanID | 368 | entityScan[entity] = scanID |
370 | toRefresh = append(toRefresh, entity) | 369 | toRefresh = append(toRefresh, entity) |
371 | } | 370 | } |
372 | } | 371 | } |
373 | rows.Close() | 372 | rows.Close() |
374 | 373 | ||
375 | if rows.Err() != nil { | 374 | if rows.Err() != nil { |
376 | logger.Log("webutility: hotload rset error: %v\n", rows.Err()) | 375 | logger.Log("webutility: hotload rset error: %v\n", rows.Err()) |
377 | time.Sleep(time.Duration(n) * time.Second) | 376 | time.Sleep(time.Duration(n) * time.Second) |
378 | continue | 377 | continue |
379 | } | 378 | } |
380 | 379 | ||
381 | if len(toRefresh) > 0 && !firstCheck { | 380 | if len(toRefresh) > 0 && !firstCheck { |
382 | mu.Lock() | 381 | mu.Lock() |
383 | refreshMetadata(toRefresh) | 382 | refreshMetadata(toRefresh) |
384 | mu.Unlock() | 383 | mu.Unlock() |
385 | } | 384 | } |
386 | if firstCheck { | 385 | if firstCheck { |
387 | firstCheck = false | 386 | firstCheck = false |
388 | } | 387 | } |
389 | } | 388 | } |
390 | } | 389 | } |
391 | 390 | ||
392 | func refreshMetadata(entities []string) { | 391 | func refreshMetadata(entities []string) { |
393 | for _, e := range entities { | 392 | for _, e := range entities { |
394 | fmt.Printf("refreshing %s\n", e) | 393 | fmt.Printf("refreshing %s\n", e) |
395 | rows, err := metadataDB.Query(`select | 394 | rows, err := metadataDB.Query(`select |
396 | metadata | 395 | metadata |
397 | from entities | 396 | from entities |
398 | where projekat = ` + fmt.Sprintf("'%s'", activeProject) + | 397 | where projekat = ` + fmt.Sprintf("'%s'", activeProject) + |
399 | ` and entity_type = ` + fmt.Sprintf("'%s'", e)) | 398 | ` and entity_type = ` + fmt.Sprintf("'%s'", e)) |
400 | 399 | ||
401 | if err != nil { | 400 | if err != nil { |
402 | logger.Log("webutility: refresh: prep: %v\n", err) | 401 | logger.Log("webutility: refresh: prep: %v\n", err) |
403 | rows.Close() | 402 | rows.Close() |
404 | continue | 403 | continue |
405 | } | 404 | } |
406 | 405 | ||
407 | for rows.Next() { | 406 | for rows.Next() { |
408 | var load string | 407 | var load string |
409 | rows.Scan(&load) | 408 | rows.Scan(&load) |
410 | p := Payload{} | 409 | p := Payload{} |
411 | err := json.Unmarshal([]byte(load), &p) | 410 | err := json.Unmarshal([]byte(load), &p) |
412 | if err != nil { | 411 | if err != nil { |
413 | logger.Log("webutility: couldn't refresh: '%s' metadata: %s\n%s\n", e, err.Error(), load) | 412 | logger.Log("webutility: couldn't refresh: '%s' metadata: %s\n%s\n", e, err.Error(), load) |
414 | } else { | 413 | } else { |
415 | metadata[e] = p | 414 | metadata[e] = p |
416 | } | 415 | } |
417 | } | 416 | } |
418 | rows.Close() | 417 | rows.Close() |
419 | } | 418 | } |
420 | } | 419 | } |
421 | 420 | ||
422 | /* | 421 | /* |
423 | func ModifyMetadataForEntity(entityType string, p *Payload) error { | 422 | func ModifyMetadataForEntity(entityType string, p *Payload) error { |
424 | md, err := json.Marshal(*p) | 423 | md, err := json.Marshal(*p) |
425 | if err != nil { | 424 | if err != nil { |
426 | return err | 425 | return err |
427 | } | 426 | } |
428 | 427 | ||
429 | mu.Lock() | 428 | mu.Lock() |
430 | defer mu.Unlock() | 429 | defer mu.Unlock() |
431 | _, err = metadataDB.PrepAndExe(`update entities set | 430 | _, err = metadataDB.PrepAndExe(`update entities set |
432 | metadata = :1 | 431 | metadata = :1 |
433 | where projekat = :2 | 432 | where projekat = :2 |
434 | and entity_type = :3`, | 433 | and entity_type = :3`, |
435 | string(md), | 434 | string(md), |
436 | activeProject, | 435 | activeProject, |
437 | entityType) | 436 | entityType) |
438 | if err != nil { | 437 | if err != nil { |
439 | return err | 438 | return err |
440 | } | 439 | } |
441 | return nil | 440 | return nil |
442 | } | 441 | } |
443 | 442 | ||
444 | func DeleteEntityModel(entityType string) error { | 443 | func DeleteEntityModel(entityType string) error { |
445 | _, err := metadataDB.PrepAndExe("delete from entities where entity_type = :1", entityType) | 444 | _, err := metadataDB.PrepAndExe("delete from entities where entity_type = :1", entityType) |
446 | if err == nil { | 445 | if err == nil { |
447 | mu.Lock() | 446 | mu.Lock() |
448 | delete(metadata, entityType) | 447 | delete(metadata, entityType) |
449 | mu.Unlock() | 448 | mu.Unlock() |
450 | } | 449 | } |
451 | return err | 450 | return err |
452 | } | 451 | } |
453 | */ | 452 | */ |
454 | 453 |
string_sanitisation.go
1 | package webutility | 1 | package webutility |
2 | 2 | ||
3 | import "git.to-net.rs/marko.tikvic/util" | ||
4 | |||
5 | const patern = "\"';&*<>=\\`:" | 3 | const patern = "\"';&*<>=\\`:" |
6 | 4 | ||
7 | // SanitiseString removes characters from s found in patern and returns new modified string. | 5 | // SanitiseString removes characters from s found in patern and returns new modified string. |
8 | func SanitiseString(s string) string { | 6 | func SanitiseString(s string) string { |
9 | return util.ReplaceAny(s, patern, "") | 7 | return ReplaceAny(s, patern, "") |
10 | } | 8 | } |
11 | 9 |
string_util.go
1 | package util | 1 | package webutility |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "fmt" | 4 | "fmt" |
5 | "strings" | 5 | "strings" |
6 | ) | 6 | ) |
7 | 7 | ||
8 | // IsWrappedWith ... | 8 | // IsWrappedWith ... |
9 | func IsWrappedWith(src, begin, end string) bool { | 9 | func IsWrappedWith(src, begin, end string) bool { |
10 | return strings.HasPrefix(src, begin) && strings.HasSuffix(src, end) | 10 | return strings.HasPrefix(src, begin) && strings.HasSuffix(src, end) |
11 | } | 11 | } |
12 | 12 | ||
13 | // ParseInt64Arr ... | 13 | // ParseInt64Arr ... |
14 | func ParseInt64Arr(s, sep string) (arr []int64) { | 14 | func ParseInt64Arr(s, sep string) (arr []int64) { |
15 | s = strings.TrimSpace(s) | 15 | s = strings.TrimSpace(s) |
16 | if s != "" { | 16 | if s != "" { |
17 | parts := strings.Split(s, sep) | 17 | parts := strings.Split(s, sep) |
18 | arr = make([]int64, len(parts)) | 18 | arr = make([]int64, len(parts)) |
19 | for i, p := range parts { | 19 | for i, p := range parts { |
20 | num := StringToInt64(p) | 20 | num := StringToInt64(p) |
21 | arr[i] = num | 21 | arr[i] = num |
22 | } | 22 | } |
23 | } | 23 | } |
24 | 24 | ||
25 | return arr | 25 | return arr |
26 | } | 26 | } |
27 | 27 | ||
28 | // Int64SliceToString ... | 28 | // Int64SliceToString ... |
29 | func Int64SliceToString(arr []int64) (s string) { | 29 | func Int64SliceToString(arr []int64) (s string) { |
30 | for i, num := range arr { | 30 | for i, num := range arr { |
31 | if i == 0 { | 31 | if i == 0 { |
32 | s += fmt.Sprintf("%d", num) | 32 | s += fmt.Sprintf("%d", num) |
33 | } else { | 33 | } else { |
34 | s += fmt.Sprintf(",%d", num) | 34 | s += fmt.Sprintf(",%d", num) |
35 | } | 35 | } |
36 | } | 36 | } |
37 | 37 | ||
38 | return s | 38 | return s |
39 | } | 39 | } |
40 | 40 | ||
41 | // CombineStrings ... | 41 | // CombineStrings ... |
42 | func CombineStrings(s1, s2, s3 string) string { | 42 | func CombineStrings(s1, s2, s3 string) string { |
43 | s1 = strings.TrimSpace(s1) | 43 | s1 = strings.TrimSpace(s1) |
44 | s2 = strings.TrimSpace(s2) | 44 | s2 = strings.TrimSpace(s2) |
45 | 45 | ||
46 | if s1 != "" && s2 != "" { | 46 | if s1 != "" && s2 != "" { |
47 | s1 += s3 + s2 | 47 | s1 += s3 + s2 |
48 | } else { | 48 | } else { |
49 | s1 += s2 | 49 | s1 += s2 |
50 | } | 50 | } |
51 | 51 | ||
52 | return s1 | 52 | return s1 |
53 | } | 53 | } |
54 | 54 | ||
55 | // ReplaceAny replaces any of the characters from patern found in s with r and returns a new resulting string. | 55 | // ReplaceAny replaces any of the characters from patern found in s with r and returns a new resulting string. |
56 | func ReplaceAny(s, patern, r string) (n string) { | 56 | func ReplaceAny(s, patern, r string) (n string) { |
57 | n = s | 57 | n = s |
58 | for _, c := range patern { | 58 | for _, c := range patern { |
59 | n = strings.Replace(n, string(c), r, -1) | 59 | n = strings.Replace(n, string(c), r, -1) |
60 | } | 60 | } |
61 | return n | 61 | return n |
62 | } | 62 | } |
63 | 63 | ||
64 | func StringToBool(s string) bool { | 64 | func StringToBool(s string) bool { |
65 | s = strings.ToLower(s) | 65 | s = strings.ToLower(s) |
66 | if s == "true" { | 66 | if s == "true" { |
67 | return true | 67 | return true |
68 | } | 68 | } |
69 | return false | 69 | return false |
70 | } | 70 | } |
71 | 71 | ||
72 | func BoolToString(b bool) string { | 72 | func BoolToString(b bool) string { |
73 | return fmt.Sprintf("%b", b) | 73 | return fmt.Sprintf("%b", b) |
74 | } | 74 | } |
75 | 75 | ||
76 | func StringSliceContains(slice []string, s string) bool { | 76 | func StringSliceContains(slice []string, s string) bool { |
77 | for i := range slice { | 77 | for i := range slice { |
78 | if slice[i] == s { | 78 | if slice[i] == s { |
79 | return true | 79 | return true |
80 | } | 80 | } |
81 | } | 81 | } |
82 | return false | 82 | return false |
83 | } | 83 | } |
84 | 84 |