Commit 79071a5d4fc3720a184381f583e32a94181fec2b
1 parent
b3b60e8b60
Exists in
master
and in
1 other branch
Using database/sql package to make the package driver agnostic
Showing
3 changed files
with
282 additions
and
429 deletions
Show diff stats
json_utility.go
1 | package webutility | 1 | package webutility |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "database/sql" | ||
4 | "encoding/json" | 5 | "encoding/json" |
5 | "errors" | ||
6 | "fmt" | 6 | "fmt" |
7 | "io" | 7 | "io" |
8 | "net/http" | 8 | "net/http" |
9 | "os" | ||
10 | "sync" | 9 | "sync" |
11 | "time" | 10 | "time" |
12 | 11 | ||
13 | "git.to-net.rs/marko.tikvic/gologger" | 12 | "git.to-net.rs/marko.tikvic/gologger" |
14 | |||
15 | "gopkg.in/rana/ora.v4" | ||
16 | ) | 13 | ) |
17 | 14 | ||
18 | var ( | 15 | var ( |
19 | mu = &sync.Mutex{} | 16 | mu = &sync.Mutex{} |
20 | metadata = make(map[string]Payload) | 17 | metadata = make(map[string]Payload) |
21 | updateQue = make(map[string][]byte) | 18 | updateQue = make(map[string][]byte) |
22 | 19 | ||
23 | metadataDB *ora.Ses | 20 | metadataDB *sql.DB |
24 | activeProject string | 21 | activeProject string |
25 | 22 | ||
26 | inited bool | 23 | inited bool |
27 | ) | 24 | ) |
28 | 25 | ||
29 | var logger *gologger.Logger | 26 | var logger *gologger.Logger |
30 | 27 | ||
31 | func init() { | 28 | func init() { |
32 | var err error | 29 | var err error |
33 | logger, err = gologger.New("metadata", gologger.MaxLogSize100KB) | 30 | logger, err = gologger.New("metadata", gologger.MaxLogSize100KB) |
34 | if err != nil { | 31 | if err != nil { |
35 | fmt.Printf("webutility: %s\n", err.Error()) | 32 | fmt.Printf("webutility: %s\n", err.Error()) |
36 | } | 33 | } |
37 | } | 34 | } |
38 | 35 | ||
39 | type LangMap map[string]map[string]string | 36 | type LangMap map[string]map[string]string |
40 | 37 | ||
41 | type Field struct { | 38 | type Field struct { |
42 | Parameter string `json:"param"` | 39 | Parameter string `json:"param"` |
43 | Type string `json:"type"` | 40 | Type string `json:"type"` |
44 | Visible bool `json:"visible"` | 41 | Visible bool `json:"visible"` |
45 | Editable bool `json:"editable"` | 42 | Editable bool `json:"editable"` |
46 | } | 43 | } |
47 | 44 | ||
48 | type CorrelationField struct { | 45 | type CorrelationField struct { |
49 | Result string `json:"result"` | 46 | Result string `json:"result"` |
50 | Elements []string `json:"elements"` | 47 | Elements []string `json:"elements"` |
51 | Type string `json:"type"` | 48 | Type string `json:"type"` |
52 | } | 49 | } |
53 | 50 | ||
54 | type Translation struct { | 51 | type Translation struct { |
55 | Language string `json:"language"` | 52 | Language string `json:"language"` |
56 | FieldsLabels map[string]string `json:"fieldsLabels"` | 53 | FieldsLabels map[string]string `json:"fieldsLabels"` |
57 | } | 54 | } |
58 | 55 | ||
59 | type Payload struct { | 56 | type Payload struct { |
60 | Method string `json:"method"` | 57 | Method string `json:"method"` |
61 | Params map[string]string `json:"params"` | 58 | Params map[string]string `json:"params"` |
62 | Lang []Translation `json:"lang"` | 59 | Lang []Translation `json:"lang"` |
63 | Fields []Field `json:"fields"` | 60 | Fields []Field `json:"fields"` |
64 | Correlations []CorrelationField `json:"correlationFields"` | 61 | Correlations []CorrelationField `json:"correlationFields"` |
65 | IdField string `json:"idField"` | 62 | IdField string `json:"idField"` |
66 | 63 | ||
67 | // Data holds JSON payload. It can't be used for itteration. | 64 | // Data holds JSON payload. It can't be used for itteration. |
68 | Data interface{} `json:"data"` | 65 | Data interface{} `json:"data"` |
69 | } | 66 | } |
70 | 67 | ||
68 | // NewPayload returs a payload sceleton for entity described with etype. | ||
69 | func NewPayload(r *http.Request, etype string) Payload { | ||
70 | pload := metadata[etype] | ||
71 | pload.Method = r.Method + " " + r.RequestURI | ||
72 | return pload | ||
73 | } | ||
74 | |||
75 | // DecodeJSON decodes JSON data from r to v. | ||
76 | // Returns an error if it fails. | ||
77 | func DecodeJSON(r io.Reader, v interface{}) error { | ||
78 | return json.NewDecoder(r).Decode(v) | ||
79 | } | ||
80 | |||
71 | // LoadPayloadsdetaData loads all payloads' information into 'metadata' variable. | 81 | // LoadPayloadsdetaData loads all payloads' information into 'metadata' variable. |
72 | func LoadPayloadsMetadata(db *ora.Ses, project string) error { | 82 | func LoadPayloadsMetadata(db *sql.DB, project string) error { |
73 | metadataDB = db | 83 | metadataDB = db |
74 | activeProject = project | 84 | activeProject = project |
75 | 85 | ||
76 | mu.Lock() | 86 | mu.Lock() |
77 | defer mu.Unlock() | 87 | defer mu.Unlock() |
78 | err := initMetadata(project) | 88 | err := initMetadata(project) |
79 | if err != nil { | 89 | if err != nil { |
80 | return err | 90 | return err |
81 | } | 91 | } |
82 | inited = true | 92 | inited = true |
83 | 93 | ||
84 | return nil | 94 | return nil |
85 | } | 95 | } |
86 | 96 | ||
87 | func EnableHotloading(interval int) { | 97 | func EnableHotloading(interval int) { |
88 | if interval > 0 { | 98 | if interval > 0 { |
89 | go hotload(interval) | 99 | go hotload(interval) |
90 | } | 100 | } |
91 | } | 101 | } |
92 | 102 | ||
93 | func GetMetadataForAllEntities() map[string]Payload { | 103 | func GetMetadataForAllEntities() map[string]Payload { |
94 | return metadata | 104 | return metadata |
95 | } | 105 | } |
96 | 106 | ||
97 | func GetMetadataForEntity(t string) (Payload, bool) { | 107 | func GetMetadataForEntity(t string) (Payload, bool) { |
98 | p, ok := metadata[t] | 108 | p, ok := metadata[t] |
99 | return p, ok | 109 | return p, ok |
100 | } | 110 | } |
101 | 111 | ||
102 | func QueEntityModelUpdate(entityType string, v interface{}) { | 112 | func QueEntityModelUpdate(entityType string, v interface{}) { |
103 | updateQue[entityType], _ = json.Marshal(v) | 113 | updateQue[entityType], _ = json.Marshal(v) |
104 | } | 114 | } |
105 | 115 | ||
116 | func initMetadata(project string) error { | ||
117 | rows, err := metadataDB.Query(`select | ||
118 | entity_type, | ||
119 | metadata | ||
120 | from entities | ||
121 | where projekat = ` + fmt.Sprintf("'%s'", project)) | ||
122 | if err != nil { | ||
123 | return err | ||
124 | } | ||
125 | defer rows.Close() | ||
126 | |||
127 | count := 0 | ||
128 | success := 0 | ||
129 | if len(metadata) > 0 { | ||
130 | metadata = nil | ||
131 | } | ||
132 | metadata = make(map[string]Payload) | ||
133 | for rows.Next() { | ||
134 | var name, load string | ||
135 | rows.Scan(&name, &load) | ||
136 | |||
137 | p := Payload{} | ||
138 | err := json.Unmarshal([]byte(load), &p) | ||
139 | if err != nil { | ||
140 | logger.Log("couldn't init: '%s' metadata: %s\n%s\n", name, err.Error(), load) | ||
141 | } else { | ||
142 | success++ | ||
143 | metadata[name] = p | ||
144 | } | ||
145 | count++ | ||
146 | } | ||
147 | perc := float32(success/count) * 100.0 | ||
148 | logger.Log("loaded %d/%d (%.1f%%) entities\n", success, count, perc) | ||
149 | |||
150 | return nil | ||
151 | } | ||
152 | |||
153 | func hotload(n int) { | ||
154 | entityScan := make(map[string]int64) | ||
155 | firstCheck := true | ||
156 | for { | ||
157 | time.Sleep(time.Duration(n) * time.Second) | ||
158 | rows, err := metadataDB.Query(`select | ||
159 | ora_rowscn, | ||
160 | entity_type | ||
161 | from entities where projekat = ` + fmt.Sprintf("'%s'", activeProject)) | ||
162 | if err != nil { | ||
163 | logger.Log("hotload failed: %v\n", err) | ||
164 | time.Sleep(time.Duration(n) * time.Second) | ||
165 | continue | ||
166 | } | ||
167 | |||
168 | var toRefresh []string | ||
169 | for rows.Next() { | ||
170 | var scanID int64 | ||
171 | var entity string | ||
172 | rows.Scan(&scanID, &entity) | ||
173 | oldID, ok := entityScan[entity] | ||
174 | if !ok || oldID != scanID { | ||
175 | entityScan[entity] = scanID | ||
176 | toRefresh = append(toRefresh, entity) | ||
177 | } | ||
178 | } | ||
179 | rows.Close() | ||
180 | |||
181 | if rows.Err() != nil { | ||
182 | logger.Log("hotload rset error: %v\n", rows.Err()) | ||
183 | time.Sleep(time.Duration(n) * time.Second) | ||
184 | continue | ||
185 | } | ||
186 | |||
187 | if len(toRefresh) > 0 && !firstCheck { | ||
188 | mu.Lock() | ||
189 | refreshMetadata(toRefresh) | ||
190 | mu.Unlock() | ||
191 | } | ||
192 | if firstCheck { | ||
193 | firstCheck = false | ||
194 | } | ||
195 | } | ||
196 | } | ||
197 | |||
198 | func refreshMetadata(entities []string) { | ||
199 | for _, e := range entities { | ||
200 | fmt.Printf("refreshing %s\n", e) | ||
201 | rows, err := metadataDB.Query(`select | ||
202 | metadata | ||
203 | from entities | ||
204 | where projekat = ` + fmt.Sprintf("'%s'", activeProject) + | ||
205 | ` and entity_type = ` + fmt.Sprintf("'%s'", e)) | ||
206 | |||
207 | if err != nil { | ||
208 | logger.Log("webutility: refresh: prep: %v\n", err) | ||
209 | rows.Close() | ||
210 | continue | ||
211 | } | ||
212 | |||
213 | for rows.Next() { | ||
214 | var load string | ||
215 | rows.Scan(&load) | ||
216 | p := Payload{} | ||
217 | err := json.Unmarshal([]byte(load), &p) | ||
218 | if err != nil { | ||
219 | logger.Log("couldn't refresh: '%s' metadata: %s\n%s\n", e, err.Error(), load) | ||
220 | } else { | ||
221 | metadata[e] = p | ||
222 | } | ||
223 | } | ||
224 | rows.Close() | ||
225 | } | ||
226 | } | ||
227 | |||
228 | /* | ||
106 | func UpdateEntityModels(command string) (total, upd, add int, err error) { | 229 | func UpdateEntityModels(command string) (total, upd, add int, err error) { |
107 | if command != "force" && command != "missing" { | 230 | if command != "force" && command != "missing" { |
108 | return total, 0, 0, errors.New("uknown command: " + command) | 231 | return total, 0, 0, errors.New("uknown command: " + command) |
109 | } | 232 | } |
110 | 233 | ||
111 | if !inited { | 234 | if !inited { |
112 | return 0, 0, 0, errors.New("webutil: metadata not initialized but update was tried.") | 235 | return 0, 0, 0, errors.New("webutil: metadata not initialized but update was tried.") |
113 | } | 236 | } |
114 | 237 | ||
115 | total = len(updateQue) | 238 | total = len(updateQue) |
116 | 239 | ||
117 | forUpdate := make([]string, 0) | 240 | forUpdate := make([]string, 0) |
118 | forAdd := make([]string, 0) | 241 | forAdd := make([]string, 0) |
119 | 242 | ||
120 | for k, _ := range updateQue { | 243 | for k, _ := range updateQue { |
121 | if _, exists := metadata[k]; exists { | 244 | if _, exists := metadata[k]; exists { |
122 | if command == "force" { | 245 | if command == "force" { |
123 | forUpdate = append(forUpdate, k) | 246 | forUpdate = append(forUpdate, k) |
124 | } | 247 | } |
125 | } else { | 248 | } else { |
126 | forAdd = append(forAdd, k) | 249 | forAdd = append(forAdd, k) |
127 | } | 250 | } |
128 | } | 251 | } |
129 | 252 | ||
130 | for _, k := range forUpdate { | 253 | for _, k := range forUpdate { |
131 | _, err := metadataDB.PrepAndExe(`update entities set | 254 | _, err := metadataDB.PrepAndExe(`update entities set |
132 | entity_model = :1 | 255 | entity_model = :1 |
133 | where entity_type = :2`, | 256 | where entity_type = :2`, |
134 | string(updateQue[k]), | 257 | string(updateQue[k]), |
135 | k) | 258 | k) |
136 | 259 | ||
137 | if err != nil { | 260 | if err != nil { |
138 | logger.Log("webutility: update metadata: prep and exe: %v\n", err) | 261 | logger.Log("webutility: update metadata: prep and exe: %v\n", err) |
139 | continue | 262 | continue |
140 | } | 263 | } |
141 | upd++ | 264 | upd++ |
142 | logger.Log("webutility: updated %s payload model\n", k) | 265 | logger.Log("webutility: updated %s payload model\n", k) |
143 | } | 266 | } |
144 | 267 | ||
145 | blankPayload, _ := json.Marshal(Payload{}) | 268 | blankPayload, _ := json.Marshal(Payload{}) |
146 | for _, k := range forAdd { | 269 | for _, k := range forAdd { |
147 | _, err := metadataDB.PrepAndExe(`insert into entities | 270 | _, err := metadataDB.PrepAndExe(`insert into entities |
148 | (projekat, metadata, entity_type, entity_model) | 271 | (projekat, metadata, entity_type, entity_model) |
149 | values(:1, :2, :3, :4)`, | 272 | values(:1, :2, :3, :4)`, |
150 | activeProject, | 273 | activeProject, |
151 | string(blankPayload), | 274 | string(blankPayload), |
152 | k, | 275 | k, |
153 | string(updateQue[k])) | 276 | string(updateQue[k])) |
154 | 277 | ||
155 | if err != nil { | 278 | if err != nil { |
156 | logger.Log("webutility: add metadata: prep and exe: %v\n", err) | 279 | logger.Log("webutility: add metadata: prep and exe: %v\n", err) |
157 | continue | 280 | continue |
158 | } | 281 | } |
159 | metadata[k] = Payload{} | 282 | metadata[k] = Payload{} |
160 | add++ | 283 | add++ |
161 | logger.Log("webutility: added %s to the payload models\n", k) | 284 | logger.Log("webutility: added %s to the payload models\n", k) |
162 | 285 | ||
163 | } | 286 | } |
164 | 287 | ||
165 | return total, upd, add, nil | 288 | return total, upd, add, nil |
166 | } | 289 | } |
167 | 290 | ||
168 | func ModifyMetadataForEntity(entityType string, p *Payload) error { | 291 | func ModifyMetadataForEntity(entityType string, p *Payload) error { |
169 | md, err := json.Marshal(*p) | 292 | md, err := json.Marshal(*p) |
170 | if err != nil { | 293 | if err != nil { |
171 | return err | 294 | return err |
172 | } | 295 | } |
173 | 296 | ||
174 | mu.Lock() | 297 | mu.Lock() |
175 | defer mu.Unlock() | 298 | defer mu.Unlock() |
176 | _, err = metadataDB.PrepAndExe(`update entities set | 299 | _, err = metadataDB.PrepAndExe(`update entities set |
177 | metadata = :1 | 300 | metadata = :1 |
178 | where projekat = :2 | 301 | where projekat = :2 |
179 | and entity_type = :3`, | 302 | and entity_type = :3`, |
180 | string(md), | 303 | string(md), |
181 | activeProject, | 304 | activeProject, |
182 | entityType) | 305 | entityType) |
183 | if err != nil { | 306 | if err != nil { |
184 | return err | 307 | return err |
185 | } | 308 | } |
186 | return nil | 309 | return nil |
187 | } | 310 | } |
188 | 311 | ||
189 | func DeleteEntityModel(entityType string) error { | 312 | func DeleteEntityModel(entityType string) error { |
190 | _, err := metadataDB.PrepAndExe("delete from entities where entity_type = :1", entityType) | 313 | _, err := metadataDB.PrepAndExe("delete from entities where entity_type = :1", entityType) |
191 | if err == nil { | 314 | if err == nil { |
192 | mu.Lock() | 315 | mu.Lock() |
193 | delete(metadata, entityType) | 316 | delete(metadata, entityType) |
194 | mu.Unlock() | 317 | mu.Unlock() |
195 | } | 318 | } |
196 | return err | 319 | return err |
197 | } | 320 | } |
198 | 321 | */ | |
199 | // NewPayload returs a payload sceleton for entity described with etype. | ||
200 | func NewPayload(r *http.Request, etype string) Payload { | ||
201 | pload := metadata[etype] | ||
202 | pload.Method = r.Method + " " + r.RequestURI | ||
203 | return pload | ||
204 | } | ||
205 | |||
206 | // DecodeJSON decodes JSON data from r to v. | ||
207 | // Returns an error if it fails. | ||
208 | func DecodeJSON(r io.Reader, v interface{}) error { | ||
209 | return json.NewDecoder(r).Decode(v) | ||
210 | } | ||
211 | |||
212 | func initMetadata(project string) error { | ||
213 | metadataDB.SetCfg(metadataDB.Cfg().SetClob(ora.S)) | ||
214 | stmt, err := metadataDB.Prep(`select | ||
215 | entity_type, | ||
216 | metadata | ||
217 | from entities | ||
218 | where projekat = `+fmt.Sprintf("'%s'", project), | ||
219 | ora.S, | ||
220 | ora.S) |
list_config.go
1 | package webutility | 1 | package webutility |
2 | 2 | ||
3 | import "gopkg.in/rana/ora.v4" | 3 | import ( |
4 | "database/sql" | ||
5 | "fmt" | ||
6 | ) | ||
4 | 7 | ||
5 | type ListOptions struct { | 8 | type ListOptions struct { |
6 | GlobalFilter bool `json:"globalFilter"` | 9 | GlobalFilter bool `json:"globalFilter"` |
7 | LocalFilters bool `json:"localFilters"` | 10 | LocalFilters bool `json:"localFilters"` |
8 | RemoteFilters bool `json:"remoteFilters"` | 11 | RemoteFilters bool `json:"remoteFilters"` |
9 | Pagination bool `json:"pagination"` | 12 | Pagination bool `json:"pagination"` |
10 | PageSize uint64 `json:"pageSize"` | 13 | PageSize uint32 `json:"pageSize"` |
11 | Pivot bool `json:"pivot"` | 14 | Pivot bool `json:"pivot"` |
12 | Detail bool `json:"detail"` | 15 | Detail bool `json:"detail"` |
13 | Total bool `json:"total"` | 16 | Total bool `json:"total"` |
14 | } | 17 | } |
15 | 18 | ||
16 | type ListFilter struct { | 19 | type ListFilter struct { |
17 | Position uint32 `json:"-"` | 20 | Position uint32 `json:"-"` |
18 | ObjectType string `json:"-"` | 21 | ObjectType string `json:"-"` |
19 | FiltersField string `json:"filtersField"` | 22 | FiltersField string `json:"filtersField"` |
20 | DefaultValues string `json:"defaultValues"` | 23 | DefaultValues string `json:"defaultValues"` |
21 | FiltersType string `json:"filtersType"` | 24 | FiltersType string `json:"filtersType"` |
22 | FiltersLabel string `json:"filtersLabel"` | 25 | FiltersLabel string `json:"filtersLabel"` |
23 | DropdownConfig Dropdown `json:"dropdownConfig"` | 26 | DropdownConfig Dropdown `json:"dropdownConfig"` |
24 | } | 27 | } |
25 | 28 | ||
26 | type Dropdown struct { | 29 | type Dropdown struct { |
27 | ObjectType string `json:"objectType"` | 30 | ObjectType string `json:"objectType"` |
28 | FiltersField string `json:"filtersField"` | 31 | FiltersField string `json:"filtersField"` |
29 | IDField string `json:"idField"` | 32 | IDField string `json:"idField"` |
30 | LabelField string `json:"labelField"` | 33 | LabelField string `json:"labelField"` |
31 | } | 34 | } |
32 | 35 | ||
33 | type ListGraph struct { | 36 | type ListGraph struct { |
34 | ObjectType string `json:"objectType"` | 37 | ObjectType string `json:"objectType"` |
35 | X string `json:"xField"` | 38 | X string `json:"xField"` |
36 | Y string `json:"yField"` | 39 | Y string `json:"yField"` |
37 | GroupField string `json:"groupField"` | 40 | GroupField string `json:"groupField"` |
38 | Label string `json:"label"` | 41 | Label string `json:"label"` |
39 | } | 42 | } |
40 | 43 | ||
41 | type ListActions struct { | 44 | type ListActions struct { |
42 | Create bool `json:"create"` | 45 | Create bool `json:"create"` |
43 | Update bool `json:"update"` | 46 | Update bool `json:"update"` |
44 | Delete bool `json:"delete"` | 47 | Delete bool `json:"delete"` |
45 | Export bool `json:"export"` | 48 | Export bool `json:"export"` |
46 | Print bool `json:"print"` | 49 | Print bool `json:"print"` |
47 | Graph bool `json:"graph"` | 50 | Graph bool `json:"graph"` |
48 | } | 51 | } |
49 | 52 | ||
50 | type ListNavNode struct { | 53 | type ListNavNode struct { |
51 | ObjectType string `json:"objectType"` | 54 | ObjectType string `json:"objectType"` |
52 | LabelField string `json:"label"` | 55 | LabelField string `json:"label"` |
53 | Icon string `json:"icon"` | 56 | Icon string `json:"icon"` |
54 | ParentObjectType string `json:"parentObjectType"` | 57 | ParentObjectType string `json:"parentObjectType"` |
55 | ParentIDField string `json:"parentIdField"` | 58 | ParentIDField string `json:"parentIdField"` |
56 | ParentFilterField string `json:"parentFilterField"` | 59 | ParentFilterField string `json:"parentFilterField"` |
57 | } | 60 | } |
58 | 61 | ||
59 | type ListParentNode struct { | 62 | type ListParentNode struct { |
60 | ObjectType string `json:"objectType"` | 63 | ObjectType string `json:"objectType"` |
61 | LabelField string `json:"labelField"` | 64 | LabelField string `json:"labelField"` |
62 | FilterField string `json:"filterField"` | 65 | FilterField string `json:"filterField"` |
63 | } | 66 | } |
64 | 67 | ||
65 | type ListPivot struct { | 68 | type ListPivot struct { |
66 | ObjectType string `json:"objectType"` | 69 | ObjectType string `json:"objectType"` |
67 | GroupField string `json:"groupField"` | 70 | GroupField string `json:"groupField"` |
68 | DistinctField string `json:"distinctField"` | 71 | DistinctField string `json:"distinctField"` |
69 | Value string `json:"valueField"` | 72 | Value string `json:"valueField"` |
70 | } | 73 | } |
71 | 74 | ||
72 | type ListDetails struct { | 75 | type ListDetails struct { |
73 | ObjectType string `json:"objectType"` | 76 | ObjectType string `json:"objectType"` |
74 | ParentObjectType string `json:"parentObjectType"` | 77 | ParentObjectType string `json:"parentObjectType"` |
75 | ParentFilterField string `json:"parentFilterField"` | 78 | ParentFilterField string `json:"parentFilterField"` |
76 | SingleDetail bool `json:"singleDetail"` | 79 | SingleDetail bool `json:"singleDetail"` |
77 | } | 80 | } |
78 | 81 | ||
79 | type ListConfig struct { | 82 | type ListConfig struct { |
80 | ObjectType string `json:"objectType"` | 83 | ObjectType string `json:"objectType"` |
81 | Title string `json:"title"` | 84 | Title string `json:"title"` |
82 | LazyLoad bool `json:"lazyLoad"` | 85 | LazyLoad bool `json:"lazyLoad"` |
83 | InlineEdit bool `json:"inlineEdit"` | 86 | InlineEdit bool `json:"inlineEdit"` |
84 | Options ListOptions `json:"options"` | 87 | Options ListOptions `json:"options"` |
85 | Filters []ListFilter `json:"defaultFilters"` | 88 | Filters []ListFilter `json:"defaultFilters"` |
86 | Graphs []ListGraph `json:"graphs"` | 89 | Graphs []ListGraph `json:"graphs"` |
87 | Actions ListActions `json:"actions"` | 90 | Actions ListActions `json:"actions"` |
88 | Parent []ListParentNode `json:"parent"` | 91 | Parent []ListParentNode `json:"parent"` |
89 | Navigation []ListNavNode `json:"navigation"` | 92 | Navigation []ListNavNode `json:"navigation"` |
90 | Pivots []ListPivot `json:"pivots"` | 93 | Pivots []ListPivot `json:"pivots"` |
91 | Details ListDetails `json:"details"` | 94 | Details ListDetails `json:"details"` |
92 | } | 95 | } |
93 | 96 | ||
94 | // GetListConfig returns list configuration for the provided object type for the front-end application | 97 | // GetListConfig returns list configuration for the provided object type for the front-end application |
95 | // or an error if it fails. | 98 | // or an error if it fails. |
96 | func GetListConfig(db *ora.Ses, objType string) (ListConfig, error) { | 99 | func GetListConfig(db *sql.DB, objType string) (ListConfig, error) { |
97 | resp := newDefaultList(objType) | 100 | resp := newDefaultList(objType) |
98 | var err error | 101 | var err error |
99 | 102 | ||
100 | err = setListParams(db, &resp, objType) | 103 | err = setListParams(db, &resp, objType) |
101 | resp.Navigation, err = getListNavigation(db, objType) | 104 | resp.Navigation, err = getListNavigation(db, objType) |
102 | resp.Actions, err = getListActions(db, objType) | 105 | resp.Actions, err = getListActions(db, objType) |
103 | resp.Filters, err = getListFilters(db, objType) | 106 | resp.Filters, err = getListFilters(db, objType) |
104 | resp.Options, err = getListOptions(db, objType) | 107 | resp.Options, err = getListOptions(db, objType) |
105 | resp.Parent, err = getListParent(db, objType) | 108 | resp.Parent, err = getListParent(db, objType) |
106 | resp.Graphs, err = getListGraph(db, objType) | 109 | resp.Graphs, err = getListGraph(db, objType) |
107 | resp.Pivots, err = getListPivot(db, objType) | 110 | resp.Pivots, err = getListPivot(db, objType) |
108 | resp.Details, err = getListDetails(db, objType) | 111 | resp.Details, err = getListDetails(db, objType) |
109 | 112 | ||
110 | if err != nil { | 113 | if err != nil { |
111 | return ListConfig{}, err | 114 | return ListConfig{}, err |
112 | } | 115 | } |
113 | 116 | ||
114 | return resp, nil | 117 | return resp, nil |
115 | } | 118 | } |
116 | 119 | ||
117 | // GetListConfigObjectIDField takes in database connection and an object type and it returns the | 120 | // GetListConfigObjectIDField takes in database connection and an object type and it returns the |
118 | // ID field name for the provided object type. | 121 | // ID field name for the provided object type. |
119 | func GetListConfigObjectIDField(db *ora.Ses, otype string) string { | 122 | func GetListConfigObjectIDField(db *sql.DB, otype string) string { |
120 | var resp string | 123 | var resp string |
121 | var err error | ||
122 | var stmt *ora.Stmt | ||
123 | 124 | ||
124 | stmt, err = db.Prep(`SELECT | 125 | rows, err := db.Query(`SELECT |
125 | ID_FIELD | 126 | ID_FIELD |
126 | FROM LIST_CONFIG_ID_FIELD | 127 | FROM LIST_CONFIG_ID_FIELD |
127 | WHERE OBJECT_TYPE = '`+otype+`'`, | 128 | WHERE OBJECT_TYPE = ` + fmt.Sprintf("'%s'", otype)) |
128 | ora.S) | ||
129 | |||
130 | defer stmt.Close() | ||
131 | |||
132 | if err != nil { | 129 | if err != nil { |
133 | return "" | 130 | return "" |
134 | } | 131 | } |
132 | defer rows.Close() | ||
135 | 133 | ||
136 | rset, err := stmt.Qry() | 134 | if rows.Next() { |
137 | if rset.Next() { | 135 | rows.Scan(&resp) |
138 | resp = rset.Row[0].(string) | ||
139 | } | 136 | } |
140 | 137 | ||
141 | if rset.Err() != nil { | 138 | if rows.Err() != nil { |
142 | return "" | 139 | return "" |
143 | } | 140 | } |
144 | 141 | ||
145 | return resp | 142 | return resp |
146 | } | 143 | } |
147 | 144 | ||
148 | // newDefaultList returns default configuration for the provided object type. | 145 | // newDefaultList returns default configuration for the provided object type. |
149 | func newDefaultList(objType string) ListConfig { | 146 | func newDefaultList(objType string) ListConfig { |
150 | list := ListConfig{ | 147 | list := ListConfig{ |
151 | ObjectType: objType, | 148 | ObjectType: objType, |
152 | Title: objType, | 149 | Title: objType, |
153 | LazyLoad: false, | 150 | LazyLoad: false, |
154 | Options: ListOptions{ | 151 | Options: ListOptions{ |
155 | GlobalFilter: true, | 152 | GlobalFilter: true, |
156 | LocalFilters: true, | 153 | LocalFilters: true, |
157 | RemoteFilters: false, | 154 | RemoteFilters: false, |
158 | Pagination: true, | 155 | Pagination: true, |
159 | PageSize: 20, | 156 | PageSize: 20, |
160 | }, | 157 | }, |
161 | Filters: nil, | 158 | Filters: nil, |
162 | Actions: ListActions{ | 159 | Actions: ListActions{ |
163 | Create: false, | 160 | Create: false, |
164 | Update: false, | 161 | Update: false, |
165 | Delete: false, | 162 | Delete: false, |
166 | Export: false, | 163 | Export: false, |
167 | Print: false, | 164 | Print: false, |
168 | Graph: false, | 165 | Graph: false, |
169 | }, | 166 | }, |
170 | Parent: nil, | 167 | Parent: nil, |
171 | Navigation: nil, | 168 | Navigation: nil, |
172 | } | 169 | } |
173 | 170 | ||
174 | return list | 171 | return list |
175 | } | 172 | } |
176 | 173 | ||
177 | // setListParams sets the default parameters of the provided configuration list for the provided object type. | 174 | // setListParams sets the default parameters of the provided configuration list for the provided object type. |
178 | func setListParams(db *ora.Ses, list *ListConfig, objType string) error { | 175 | func setListParams(db *sql.DB, list *ListConfig, objType string) error { |
179 | var err error | 176 | rows, err := db.Query(`SELECT |
180 | var stmt *ora.Stmt | ||
181 | query := `SELECT | ||
182 | OBJECT_TYPE, TITLE, LAZY_LOAD, INLINE_EDIT | 177 | OBJECT_TYPE, TITLE, LAZY_LOAD, INLINE_EDIT |
183 | FROM LIST_CONFIG | 178 | FROM LIST_CONFIG |
184 | WHERE OBJECT_TYPE = '` + objType + `'` | 179 | WHERE OBJECT_TYPE = ` + fmt.Sprintf("'%s'", objType)) |
185 | |||
186 | stmt, err = db.Prep(query, ora.S, ora.S, ora.U32, ora.U32) | ||
187 | if err != nil { | 180 | if err != nil { |
188 | return err | 181 | return err |
189 | } | 182 | } |
190 | defer stmt.Close() | 183 | defer rows.Close() |
184 | if rows.Next() { | ||
185 | otype, title := "", "" | ||
186 | lazyLoad, inlineEdit := 0, 0 | ||
187 | rows.Scan(&otype, &title, &lazyLoad, &inlineEdit) | ||
191 | 188 | ||
192 | rset, err := stmt.Qry() | ||
193 | if err != nil { | ||
194 | return err | ||
195 | } | ||
196 | if rset.Next() { | ||
197 | otype := rset.Row[0].(string) | ||
198 | if otype != "" { | 189 | if otype != "" { |
199 | list.ObjectType = otype | 190 | list.ObjectType = otype |
200 | } | 191 | } |
201 | |||
202 | title := rset.Row[1].(string) | ||
203 | if title != "" { | 192 | if title != "" { |
204 | list.Title = title | 193 | list.Title = title |
205 | } | 194 | } |
206 | list.LazyLoad = rset.Row[2].(uint32) != 0 | 195 | list.LazyLoad = lazyLoad != 0 |
207 | list.InlineEdit = rset.Row[3].(uint32) != 0 | 196 | list.InlineEdit = inlineEdit != 0 |
208 | } | 197 | } |
209 | if rset.Err() != nil { | 198 | if rows.Err() != nil { |
210 | return rset.Err() | 199 | return rows.Err() |
211 | } | 200 | } |
212 | return nil | 201 | return nil |
213 | } | 202 | } |
214 | 203 | ||
215 | // getListNavigation returns list navigation node slice for the provided objectType. | 204 | // getListNavigation returns list navigation node slice for the provided objectType. |
216 | func getListNavigation(db *ora.Ses, listObjType string) ([]ListNavNode, error) { | 205 | func getListNavigation(db *sql.DB, listObjType string) ([]ListNavNode, error) { |
217 | resp := make([]ListNavNode, 0) | 206 | resp := make([]ListNavNode, 0) |
218 | var err error | 207 | rows, err := db.Query(`SELECT |
219 | var stmt *ora.Stmt | 208 | a.OBJECT_TYPE, a.PARENT_OBJECT_TYPE, a.LABEL, a.ICON, a.PARENT_FILTER_FIELD, b.PARENT_ID_FIELD |
220 | query := `SELECT | ||
221 | a.OBJECT_TYPE, a.PARENT_OBJECT_TYPE, a.LABEL, a.ICON, a.PARENT_FILTER_FIELD, b.PARENT_ID_FIELD, b.RB | ||
222 | FROM LIST_CONFIG_NAVIGATION b | 209 | FROM LIST_CONFIG_NAVIGATION b |
223 | JOIN LIST_CONFIG_CHILD a ON b.PARENT_CHILD_ID = a.PARENT_CHILD_ID | 210 | JOIN LIST_CONFIG_CHILD a ON b.PARENT_CHILD_ID = a.PARENT_CHILD_ID |
224 | WHERE b.LIST_OBJECT_TYPE = '` + listObjType + `' | 211 | WHERE b.LIST_OBJECT_TYPE = ` + fmt.Sprintf("'%s'", listObjType) + |
225 | ORDER BY b.RB ASC` | 212 | ` ORDER BY b.RB ASC`) |
226 | |||
227 | stmt, err = db.Prep(query, ora.S, ora.S, ora.S, ora.S, ora.S) | ||
228 | if err != nil { | 213 | if err != nil { |
229 | return resp, err | 214 | return resp, err |
230 | } | 215 | } |
231 | defer stmt.Close() | 216 | defer rows.Close() |
232 | 217 | ||
233 | rset, err := stmt.Qry() | 218 | var node ListNavNode |
234 | if err != nil { | 219 | for rows.Next() { |
235 | return resp, err | 220 | rows.Scan(&node.ObjectType, &node.ParentObjectType, &node.LabelField, &node.Icon, |
236 | } | 221 | &node.ParentFilterField, &node.ParentIDField) |
237 | for rset.Next() { | 222 | resp = append(resp, node) |
238 | resp = append(resp, ListNavNode{ | ||
239 | ObjectType: rset.Row[0].(string), | ||
240 | ParentObjectType: rset.Row[1].(string), | ||
241 | LabelField: rset.Row[2].(string), | ||
242 | Icon: rset.Row[3].(string), | ||
243 | ParentFilterField: rset.Row[4].(string), | ||
244 | ParentIDField: rset.Row[5].(string), | ||
245 | // RB is ignored | ||
246 | }) | ||
247 | } | 223 | } |
248 | if rset.Err() != nil { | 224 | if rows.Err() != nil { |
249 | return nil, rset.Err() | 225 | return nil, rows.Err() |
250 | } | 226 | } |
251 | 227 | ||
252 | return resp, nil | 228 | return resp, nil |
253 | } | 229 | } |
254 | 230 | ||
255 | // getListActions returns list actions for the provided object type. | 231 | // getListActions returns list actions for the provided object type. |
256 | func getListActions(db *ora.Ses, objType string) (ListActions, error) { | 232 | func getListActions(db *sql.DB, objType string) (ListActions, error) { |
257 | var resp ListActions | 233 | var resp ListActions |
258 | var err error | 234 | rows, err := db.Query(`SELECT |
259 | var stmt *ora.Stmt | ||
260 | query := `SELECT | ||
261 | ACTION_CREATE, ACTION_UPDATE, ACTION_DELETE, ACTION_EXPORT, | 235 | ACTION_CREATE, ACTION_UPDATE, ACTION_DELETE, ACTION_EXPORT, |
262 | ACTION_PRINT, ACTION_GRAPH | 236 | ACTION_PRINT, ACTION_GRAPH |
263 | FROM LIST_CONFIG | 237 | FROM LIST_CONFIG |
264 | WHERE OBJECT_TYPE = '` + objType + `'` | 238 | WHERE OBJECT_TYPE = ` + fmt.Sprintf("'%s'", objType)) |
265 | |||
266 | stmt, err = db.Prep(query, ora.U32, ora.U32, ora.U32, ora.U32, | ||
267 | ora.U32, ora.U32) | ||
268 | if err != nil { | 239 | if err != nil { |
269 | return ListActions{}, err | 240 | return ListActions{}, err |
270 | } | 241 | } |
271 | defer stmt.Close() | 242 | defer rows.Close() |
272 | 243 | ||
273 | rset, err := stmt.Qry() | 244 | var create, update, delete, export, print, graph uint32 |
274 | if err != nil { | 245 | if rows.Next() { |
275 | return ListActions{}, err | 246 | rows.Scan(&create, &update, &delete, &export, &print, &graph) |
247 | resp.Create = create != 0 | ||
248 | resp.Update = update != 0 | ||
249 | resp.Delete = delete != 0 | ||
250 | resp.Export = export != 0 | ||
251 | resp.Print = print != 0 | ||
252 | resp.Graph = graph != 0 | ||
276 | } | 253 | } |
277 | if rset.Next() { | 254 | if rows.Err() != nil { |
278 | resp.Create = rset.Row[0].(uint32) != 0 | 255 | return ListActions{}, rows.Err() |
279 | resp.Update = rset.Row[1].(uint32) != 0 | ||
280 | resp.Delete = rset.Row[2].(uint32) != 0 | ||
281 | resp.Export = rset.Row[3].(uint32) != 0 | ||
282 | resp.Print = rset.Row[4].(uint32) != 0 | ||
283 | resp.Graph = rset.Row[5].(uint32) != 0 | ||
284 | } | ||
285 | if rset.Err() != nil { | ||
286 | return ListActions{}, rset.Err() | ||
287 | } | 256 | } |
288 | return resp, nil | 257 | return resp, nil |
289 | } | 258 | } |
290 | 259 | ||
291 | // getListFiters returns list filter slice for the provided object type. | 260 | // getListFiters returns list filter slice for the provided object type. |
292 | func getListFilters(db *ora.Ses, objType string) ([]ListFilter, error) { | 261 | func getListFilters(db *sql.DB, objType string) ([]ListFilter, error) { |
293 | resp := make([]ListFilter, 0) | 262 | resp := make([]ListFilter, 0) |
294 | filtersFields, err := getFilterFieldsAndPosition(db, objType) | 263 | filtersFields, err := getFilterFieldsAndPosition(db, objType) |
295 | if err != nil { | 264 | if err != nil { |
296 | return nil, err | 265 | return nil, err |
297 | } | 266 | } |
298 | for field, pos := range filtersFields { | 267 | for field, pos := range filtersFields { |
299 | filters, _ := getFiltersByFilterField(db, field) | 268 | filters, _ := getFiltersByFilterField(db, field) |
300 | for _, filter := range filters { | 269 | for _, filter := range filters { |
301 | var f ListFilter | 270 | var f ListFilter |
302 | f.Position = pos | 271 | f.Position = pos |
303 | f.ObjectType = objType | 272 | f.ObjectType = objType |
304 | f.FiltersField = field | 273 | f.FiltersField = field |
305 | f.DefaultValues = filter.DefaultValues | 274 | f.DefaultValues = filter.DefaultValues |
306 | f.FiltersLabel = filter.Label | 275 | f.FiltersLabel = filter.Label |
307 | f.FiltersType = filter.Type | 276 | f.FiltersType = filter.Type |
308 | if filter.Type == "dropdown" { | 277 | if filter.Type == "dropdown" { |
309 | f.DropdownConfig, err = getFilterDropdownConfig(db, field) | 278 | f.DropdownConfig, err = getFilterDropdownConfig(db, field) |
310 | if err != nil { | 279 | if err != nil { |
311 | return nil, err | 280 | return nil, err |
312 | } | 281 | } |
313 | } | 282 | } |
314 | resp = append(resp, f) | 283 | resp = append(resp, f) |
315 | } | 284 | } |
316 | } | 285 | } |
317 | 286 | ||
318 | sortFilters(resp) | 287 | sortFilters(resp) |
319 | 288 | ||
320 | return resp, nil | 289 | return resp, nil |
321 | } | 290 | } |
322 | 291 | ||
323 | // getFilterFieldsAndPosition returns a map of filter fields and their respective position in the menu. | 292 | // getFilterFieldsAndPosition returns a map of filter fields and their respective position in the menu. |
324 | func getFilterFieldsAndPosition(db *ora.Ses, objType string) (map[string]uint32, error) { | 293 | func getFilterFieldsAndPosition(db *sql.DB, objType string) (map[string]uint32, error) { |
325 | filtersField := make(map[string]uint32, 0) | 294 | filtersField := make(map[string]uint32, 0) |
326 | var err error | 295 | rows, err := db.Query(`SELECT |
327 | var stmt *ora.Stmt | ||
328 | query := `SELECT | ||
329 | FILTERS_FIELD, RB | 296 | FILTERS_FIELD, RB |
330 | FROM LIST_CONFIG_FILTERS | 297 | FROM LIST_CONFIG_FILTERS |
331 | WHERE OBJECT_TYPE = '` + objType + `'` | 298 | WHERE OBJECT_TYPE = ` + fmt.Sprintf("'%s'", objType)) |
332 | |||
333 | stmt, err = db.Prep(query, ora.S, ora.U32) | ||
334 | if err != nil { | 299 | if err != nil { |
335 | return nil, err | 300 | return nil, err |
336 | } | 301 | } |
337 | defer stmt.Close() | 302 | defer rows.Close() |
338 | 303 | ||
339 | rset, err := stmt.Qry() | 304 | for rows.Next() { |
340 | if err != nil { | 305 | var field string |
341 | return nil, err | 306 | var rb uint32 |
342 | } | 307 | rows.Scan(&field, &rb) |
343 | for rset.Next() { | 308 | filtersField[field] = rb |
344 | filtersField[rset.Row[0].(string)] = rset.Row[1].(uint32) | ||
345 | } | 309 | } |
346 | if rset.Err() != nil { | 310 | if rows.Err() != nil { |
347 | return nil, rset.Err() | 311 | return nil, rows.Err() |
348 | } | 312 | } |
349 | return filtersField, nil | 313 | return filtersField, nil |
350 | } | 314 | } |
351 | 315 | ||
352 | type _filter struct { | 316 | type _filter struct { |
353 | DefaultValues string | 317 | DefaultValues string |
354 | Label string | 318 | Label string |
355 | Type string | 319 | Type string |
356 | } | 320 | } |
357 | 321 | ||
358 | // getFiltersByFilterField returns filter slice for the provided filter field. | 322 | // getFiltersByFilterField returns filter slice for the provided filter field. |
359 | func getFiltersByFilterField(db *ora.Ses, filtersField string) ([]_filter, error) { | 323 | func getFiltersByFilterField(db *sql.DB, filtersField string) ([]_filter, error) { |
360 | resp := make([]_filter, 0) | 324 | resp := make([]_filter, 0) |
361 | var err error | 325 | rows, err := db.Query(`SELECT |
362 | var stmt *ora.Stmt | ||
363 | query := `SELECT | ||
364 | FILTERS_TYPE, FILTERS_LABEL, DEFAULT_VALUES | 326 | FILTERS_TYPE, FILTERS_LABEL, DEFAULT_VALUES |
365 | FROM LIST_FILTERS_FIELD | 327 | FROM LIST_FILTERS_FIELD |
366 | WHERE FILTERS_FIELD = '` + filtersField + `'` | 328 | WHERE FILTERS_FIELD = ` + fmt.Sprintf("'%s'", filtersField)) |
367 | |||
368 | stmt, err = db.Prep(query, ora.S, ora.S, ora.S) | ||
369 | if err != nil { | 329 | if err != nil { |
370 | return resp, err | 330 | return resp, err |
371 | } | 331 | } |
372 | defer stmt.Close() | 332 | defer rows.Close() |
373 | 333 | ||
374 | rset, err := stmt.Qry() | 334 | var f _filter |
375 | if err != nil { | 335 | for rows.Next() { |
376 | return resp, err | 336 | rows.Scan(&f.Type, &f.Label, &f.DefaultValues) |
337 | resp = append(resp, f) | ||
377 | } | 338 | } |
378 | for rset.Next() { | 339 | if rows.Err() != nil { |
379 | resp = append(resp, _filter{ | 340 | return resp, rows.Err() |
380 | Type: rset.Row[0].(string), | ||
381 | Label: rset.Row[1].(string), | ||
382 | DefaultValues: rset.Row[2].(string), | ||
383 | }) | ||
384 | } | ||
385 | if rset.Err() != nil { | ||
386 | return resp, rset.Err() | ||
387 | } | 341 | } |
388 | return resp, nil | 342 | return resp, nil |
389 | } | 343 | } |
390 | 344 | ||
391 | // getFilterDropdownConfig returns dropdown menu for the provided filter field. | 345 | // getFilterDropdownConfig returns dropdown menu for the provided filter field. |
392 | func getFilterDropdownConfig(db *ora.Ses, filtersField string) (Dropdown, error) { | 346 | func getFilterDropdownConfig(db *sql.DB, filtersField string) (Dropdown, error) { |
393 | var resp Dropdown | 347 | var resp Dropdown |
394 | var err error | 348 | rows, err := db.Query(`SELECT |
395 | var stmt *ora.Stmt | ||
396 | query := `SELECT | ||
397 | FILTERS_FIELD, OBJECT_TYPE, ID_FIELD, LABEL_FIELD | 349 | FILTERS_FIELD, OBJECT_TYPE, ID_FIELD, LABEL_FIELD |
398 | FROM LIST_DROPDOWN_FILTER | 350 | FROM LIST_DROPDOWN_FILTER |
399 | WHERE FILTERS_FIELD = '` + filtersField + `'` | 351 | WHERE FILTERS_FIELD = ` + fmt.Sprintf("'%s'", filtersField)) |
400 | |||
401 | stmt, err = db.Prep(query, ora.S, ora.S, ora.S, ora.S) | ||
402 | if err != nil { | 352 | if err != nil { |
403 | return resp, err | 353 | return resp, err |
404 | } | 354 | } |
405 | defer stmt.Close() | 355 | defer rows.Close() |
406 | 356 | if rows.Next() { | |
407 | rset, err := stmt.Qry() | 357 | rows.Scan(&resp.FiltersField, &resp.ObjectType, &resp.IDField, &resp.LabelField) |
408 | if err != nil { | ||
409 | return resp, err | ||
410 | } | 358 | } |
411 | if rset.Next() { | 359 | if rows.Err() != nil { |
412 | resp.FiltersField = rset.Row[0].(string) | 360 | return resp, rows.Err() |
413 | resp.ObjectType = rset.Row[1].(string) | ||
414 | resp.IDField = rset.Row[2].(string) | ||
415 | resp.LabelField = rset.Row[3].(string) | ||
416 | } | ||
417 | if rset.Err() != nil { | ||
418 | return resp, rset.Err() | ||
419 | } | 361 | } |
420 | return resp, nil | 362 | return resp, nil |
421 | } | 363 | } |
422 | 364 | ||
423 | // sortFilters bubble sorts provided filters slice by position field. | 365 | // sortFilters bubble sorts provided filters slice by position field. |
424 | func sortFilters(filters []ListFilter) { | 366 | func sortFilters(filters []ListFilter) { |
425 | done := false | 367 | done := false |
426 | var temp ListFilter | 368 | var temp ListFilter |
427 | for !done { | 369 | for !done { |
428 | done = true | 370 | done = true |
429 | for i := 0; i < len(filters)-1; i++ { | 371 | for i := 0; i < len(filters)-1; i++ { |
430 | if filters[i].Position > filters[i+1].Position { | 372 | if filters[i].Position > filters[i+1].Position { |
431 | done = false | 373 | done = false |
432 | temp = filters[i] | 374 | temp = filters[i] |
433 | filters[i] = filters[i+1] | 375 | filters[i] = filters[i+1] |
434 | filters[i+1] = temp | 376 | filters[i+1] = temp |
435 | } | 377 | } |
436 | } | 378 | } |
437 | } | 379 | } |
438 | } | 380 | } |
439 | 381 | ||
440 | // getListGraph return list graph slice for the provided object type. | 382 | // getListGraph return list graph slice for the provided object type. |
441 | func getListGraph(db *ora.Ses, objType string) ([]ListGraph, error) { | 383 | func getListGraph(db *sql.DB, objType string) ([]ListGraph, error) { |
442 | resp := make([]ListGraph, 0) | 384 | resp := make([]ListGraph, 0) |
443 | var err error | 385 | rows, err := db.Query(`SELECT |
444 | var stmt *ora.Stmt | ||
445 | query := `SELECT | ||
446 | OBJECT_TYPE, X_FIELD, Y_FIELD, GROUP_FIELD, LABEL | 386 | OBJECT_TYPE, X_FIELD, Y_FIELD, GROUP_FIELD, LABEL |
447 | FROM LIST_GRAPHS | 387 | FROM LIST_GRAPHS |
448 | WHERE OBJECT_TYPE = '` + objType + `'` | 388 | WHERE OBJECT_TYPE = ` + fmt.Sprintf("'%s'", objType)) |
449 | |||
450 | stmt, err = db.Prep(query, ora.S, ora.S, ora.S, ora.S) | ||
451 | if err != nil { | 389 | if err != nil { |
452 | return resp, err | 390 | return resp, err |
453 | } | 391 | } |
454 | defer stmt.Close() | 392 | defer rows.Close() |
455 | 393 | ||
456 | rset, err := stmt.Qry() | 394 | var lg ListGraph |
457 | if err != nil { | 395 | for rows.Next() { |
458 | return resp, err | 396 | rows.Scan(&lg.ObjectType, &lg.X, &lg.Y, &lg.GroupField, &lg.Label) |
459 | } | 397 | resp = append(resp, lg) |
460 | for rset.Next() { | ||
461 | resp = append(resp, ListGraph{ | ||
462 | ObjectType: rset.Row[0].(string), | ||
463 | X: rset.Row[1].(string), | ||
464 | Y: rset.Row[2].(string), | ||
465 | GroupField: rset.Row[3].(string), | ||
466 | Label: rset.Row[4].(string), | ||
467 | }) | ||
468 | } | 398 | } |
469 | if rset.Err() != nil { | 399 | if rows.Err() != nil { |
470 | return resp, rset.Err() | 400 | return resp, rows.Err() |
471 | } | 401 | } |
472 | return resp, nil | 402 | return resp, nil |
473 | } | 403 | } |
474 | 404 | ||
475 | // getListOptions returns list options for the provided object type. | 405 | // getListOptions returns list options for the provided object type. |
476 | func getListOptions(db *ora.Ses, objType string) (ListOptions, error) { | 406 | func getListOptions(db *sql.DB, objType string) (ListOptions, error) { |
477 | var resp ListOptions | 407 | var resp ListOptions |
478 | var err error | 408 | rows, err := db.Query(`SELECT |
479 | var stmt *ora.Stmt | ||
480 | query := `SELECT | ||
481 | GLOBAL_FILTER, LOCAL_FILTER, REMOTE_FILTER, PAGINATION, | 409 | GLOBAL_FILTER, LOCAL_FILTER, REMOTE_FILTER, PAGINATION, |
482 | PAGE_SIZE, PIVOT, DETAIL, TOTAL | 410 | PAGE_SIZE, PIVOT, DETAIL, TOTAL |
483 | FROM LIST_CONFIG | 411 | FROM LIST_CONFIG |
484 | WHERE OBJECT_TYPE = '` + objType + `'` | 412 | WHERE OBJECT_TYPE = ` + fmt.Sprintf("'%s'", objType)) |
485 | |||
486 | stmt, err = db.Prep(query, ora.U32, ora.U32, ora.U32, ora.U32, | ||
487 | ora.U64, ora.U64, ora.U32, ora.U32) | ||
488 | if err != nil { | ||
489 | return ListOptions{}, err | ||
490 | } | ||
491 | defer stmt.Close() | ||
492 | |||
493 | rset, err := stmt.Qry() | ||
494 | if err != nil { | 413 | if err != nil { |
495 | return ListOptions{}, err | 414 | return ListOptions{}, err |
496 | } | 415 | } |
497 | if rset.Next() { | 416 | defer rows.Close() |
498 | resp.GlobalFilter = rset.Row[0].(uint32) != 0 | 417 | if rows.Next() { |
499 | resp.LocalFilters = rset.Row[1].(uint32) != 0 | 418 | var gfilter, lfilters, rfilters, pagination, pageSize, pivot, detail, total uint32 |
500 | resp.RemoteFilters = rset.Row[2].(uint32) != 0 | 419 | rows.Scan(&gfilter, &lfilters, &rfilters, &pagination, &pageSize, &pivot, &detail, &total) |
501 | resp.Pagination = rset.Row[3].(uint32) != 0 | 420 | resp.GlobalFilter = gfilter != 0 |
502 | resp.PageSize = rset.Row[4].(uint64) | 421 | resp.LocalFilters = lfilters != 0 |
503 | resp.Pivot = rset.Row[5].(uint64) != 0 | 422 | resp.RemoteFilters = rfilters != 0 |
504 | resp.Detail = rset.Row[6].(uint32) != 0 | 423 | resp.Pagination = pagination != 0 |
505 | resp.Total = rset.Row[7].(uint32) != 0 | 424 | resp.PageSize = pageSize |
506 | } | 425 | resp.Pivot = pivot != 0 |
507 | if rset.Err() != nil { | 426 | resp.Detail = detail != 0 |
508 | return ListOptions{}, rset.Err() | 427 | resp.Total = total != 0 |
428 | } | ||
429 | if rows.Err() != nil { | ||
430 | return ListOptions{}, rows.Err() | ||
509 | } | 431 | } |
510 | return resp, nil | 432 | return resp, nil |
511 | } | 433 | } |
512 | 434 | ||
513 | // getListParent returns list parent node slice for the provided object type. | 435 | // getListParent returns list parent node slice for the provided object type. |
514 | func getListParent(db *ora.Ses, objType string) ([]ListParentNode, error) { | 436 | func getListParent(db *sql.DB, objType string) ([]ListParentNode, error) { |
515 | resp := make([]ListParentNode, 0) | 437 | resp := make([]ListParentNode, 0) |
516 | var err error | 438 | rows, err := db.Query(`SELECT |
517 | var stmt *ora.Stmt | ||
518 | query := `SELECT | ||
519 | PARENT_OBJECT_TYPE, PARENT_LABEL_FIELD, PARENT_FILTER_FIELD | 439 | PARENT_OBJECT_TYPE, PARENT_LABEL_FIELD, PARENT_FILTER_FIELD |
520 | FROM LIST_CONFIG_CHILD | 440 | FROM LIST_CONFIG_CHILD |
521 | WHERE OBJECT_TYPE = '` + objType + `'` | 441 | WHERE OBJECT_TYPE = ` + fmt.Sprintf("'%s'", objType)) |
522 | |||
523 | stmt, err = db.Prep(query, ora.S, ora.S, ora.S) | ||
524 | if err != nil { | 442 | if err != nil { |
525 | return resp, err | 443 | return resp, err |
526 | } | 444 | } |
527 | defer stmt.Close() | 445 | defer rows.Close() |
528 | 446 | ||
529 | rset, err := stmt.Qry() | 447 | var pnode ListParentNode |
530 | if err != nil { | 448 | for rows.Next() { |
531 | return resp, err | 449 | rows.Scan(&pnode.ObjectType, &pnode.LabelField, &pnode.FilterField) |
532 | } | 450 | resp = append(resp, pnode) |
533 | for rset.Next() { | ||
534 | resp = append(resp, ListParentNode{ | ||
535 | ObjectType: rset.Row[0].(string), | ||
536 | LabelField: rset.Row[1].(string), | ||
537 | FilterField: rset.Row[2].(string), | ||
538 | }) | ||
539 | } | 451 | } |
540 | if rset.Err() != nil { | 452 | if rows.Err() != nil { |
541 | return nil, rset.Err() | 453 | return nil, rows.Err() |
542 | } | 454 | } |
543 | 455 | ||
544 | return resp, nil | 456 | return resp, nil |
545 | } | 457 | } |
546 | 458 | ||
547 | // getListPivot list pivot slice for the provided object type. | 459 | // getListPivot list pivot slice for the provided object type. |
548 | func getListPivot(db *ora.Ses, objType string) ([]ListPivot, error) { | 460 | func getListPivot(db *sql.DB, objType string) ([]ListPivot, error) { |
549 | resp := make([]ListPivot, 0) | 461 | resp := make([]ListPivot, 0) |
550 | var err error | 462 | rows, err := db.Query(`SELECT |
551 | var stmt *ora.Stmt | ||
552 | query := `SELECT | ||
553 | OBJECT_TYPE, GROUP_FIELD, DISTINCT_FIELD, VALUE_FIELD | 463 | OBJECT_TYPE, GROUP_FIELD, DISTINCT_FIELD, VALUE_FIELD |
554 | FROM LIST_PIVOTS | 464 | FROM LIST_PIVOTS |
555 | WHERE OBJECT_TYPE = '` + objType + `'` | 465 | WHERE OBJECT_TYPE = ` + fmt.Sprintf("'%s'", objType)) |
556 | |||
557 | stmt, err = db.Prep(query, ora.S, ora.S, ora.S, ora.S) | ||
558 | if err != nil { | 466 | if err != nil { |
559 | return resp, err | 467 | return resp, err |
560 | } | 468 | } |
561 | defer stmt.Close() | 469 | defer rows.Close() |
562 | 470 | ||
563 | rset, err := stmt.Qry() | 471 | var p ListPivot |
564 | if err != nil { | 472 | for rows.Next() { |
565 | return resp, err | 473 | rows.Scan(&p.ObjectType, &p.GroupField, &p.DistinctField, &p.Value) |
474 | resp = append(resp, p) | ||
566 | } | 475 | } |
567 | for rset.Next() { | 476 | if rows.Err() != nil { |
568 | resp = append(resp, ListPivot{ | 477 | return nil, rows.Err() |
569 | ObjectType: rset.Row[0].(string), | ||
570 | GroupField: rset.Row[1].(string), | ||
571 | DistinctField: rset.Row[2].(string), | ||
572 | Value: rset.Row[3].(string), | ||
573 | }) | ||
574 | } | ||
575 | if rset.Err() != nil { | ||
576 | return nil, rset.Err() | ||
577 | } | 478 | } |
578 | 479 | ||
579 | return resp, nil | 480 | return resp, nil |
580 | } | 481 | } |
581 | 482 | ||
582 | // getListDetails returns list details for the provided object type. | 483 | // getListDetails returns list details for the provided object type. |
583 | func getListDetails(db *ora.Ses, objType string) (ListDetails, error) { | 484 | func getListDetails(db *sql.DB, objType string) (ListDetails, error) { |
584 | var resp ListDetails | 485 | var resp ListDetails |
585 | var err error | 486 | rows, err := db.Query(`SELECT |
586 | var stmt *ora.Stmt | ||
587 | query := `SELECT | ||
588 | OBJECT_TYPE, PARENT_OBJECT_TYPE, PARENT_FILTER_FIELD, SINGLE_DETAIL | 487 | OBJECT_TYPE, PARENT_OBJECT_TYPE, PARENT_FILTER_FIELD, SINGLE_DETAIL |
589 | FROM LIST_CONFIG_DETAIL | 488 | FROM LIST_CONFIG_DETAIL |
590 | WHERE PARENT_OBJECT_TYPE = '` + objType + `'` | 489 | WHERE PARENT_OBJECT_TYPE = ` + fmt.Sprintf("'%s'", objType)) |
591 | |||
592 | stmt, err = db.Prep(query, ora.S, ora.S, ora.S, ora.U32) | ||
593 | if err != nil { | ||
594 | return resp, err | ||
595 | } |
select_config.go
1 | package webutility | 1 | package webutility |
2 | 2 | ||
3 | import "gopkg.in/rana/ora.v4" | 3 | import "database/sql" |
4 | 4 | ||
5 | type SelectConfig struct { | 5 | type SelectConfig struct { |
6 | ListObjType string `json:"listObjectType"` | 6 | ListObjType string `json:"listObjectType"` |
7 | ObjType string `json:"objectType"` | 7 | ObjType string `json:"objectType"` |
8 | Type string `json:"type"` | 8 | Type string `json:"type"` |
9 | IdField string `json:"idField"` | 9 | IdField string `json:"idField"` |
10 | LabelField string `json:"labelField"` | 10 | LabelField string `json:"labelField"` |
11 | ValueField string `json:"valueField"` | 11 | ValueField string `json:"valueField"` |
12 | } | 12 | } |
13 | 13 | ||
14 | // GetSelectConfig returns select configuration slice for the given object type. | 14 | // GetSelectConfig returns select configuration slice for the given object type. |
15 | func GetSelectConfig(db *ora.Ses, otype string) ([]SelectConfig, error) { | 15 | func GetSelectConfig(db *sql.DB, otype string) ([]SelectConfig, error) { |
16 | resp := make([]SelectConfig, 0) | 16 | resp := make([]SelectConfig, 0) |
17 | var err error | 17 | rows, err := db.Query(`SELECT |
18 | var stmt *ora.Stmt | ||
19 | query := `SELECT | ||
20 | a.LIST_OBJECT_TYPE, | 18 | a.LIST_OBJECT_TYPE, |
21 | a.OBJECT_TYPE, | 19 | a.OBJECT_TYPE, |
22 | a.ID_FIELD, | 20 | a.ID_FIELD, |
23 | a.LABEL_FIELD, | 21 | a.LABEL_FIELD, |
24 | a.TYPE, | 22 | a.TYPE, |
25 | b.FIELD | 23 | b.FIELD |
26 | FROM LIST_SELECT_CONFIG a, LIST_VALUE_FIELD b | 24 | FROM LIST_SELECT_CONFIG a, LIST_VALUE_FIELD b |
27 | WHERE a.LIST_OBJECT_TYPE` + otype + ` | 25 | WHERE a.LIST_OBJECT_TYPE` + otype + ` |
28 | AND b.LIST_TYPE = a.LIST_OBJECT_TYPE | 26 | AND b.LIST_TYPE = a.LIST_OBJECT_TYPE |
29 | AND b.OBJECT_TYPE = a.OBJECT_TYPE` | 27 | AND b.OBJECT_TYPE = a.OBJECT_TYPE`) |
30 | |||
31 | stmt, err = db.Prep(query, ora.S, ora.S, ora.S, ora.S, ora.S, ora.S) | ||
32 | defer stmt.Close() | ||
33 | if err != nil { | 28 | if err != nil { |
34 | return nil, err | 29 | return nil, err |
35 | } | 30 | } |
31 | defer rows.Close() | ||
36 | 32 | ||
37 | rset, err := stmt.Qry() | 33 | var sc SelectConfig |
38 | if err != nil { | 34 | for rows.Next() { |
39 | return nil, err | 35 | rows.Scan(&sc.ListObjType, &sc.ObjType, &sc.IdField, &sc.LabelField, &sc.Type, &sc.ValueField) |
40 | } | 36 | resp = append(resp, sc) |
41 | for rset.Next() { | ||
42 | resp = append(resp, SelectConfig{ | ||
43 | ListObjType: rset.Row[0].(string), | ||
44 | ObjType: rset.Row[1].(string), | ||
45 | IdField: rset.Row[2].(string), | ||
46 | LabelField: rset.Row[3].(string), | ||
47 | Type: rset.Row[4].(string), | ||
48 | ValueField: rset.Row[5].(string), | ||
49 | }) | ||
50 | } | 37 | } |
51 | if rset.Err() != nil { | 38 | if rows.Err() != nil { |
52 | return nil, rset.Err() | 39 | return nil, rows.Err() |
53 | } | 40 | } |
54 | 41 | ||
55 | return resp, nil | 42 | return resp, nil |
56 | } | 43 | } |