Commit 31a4e13027906b008bb3cb3469d1f09738875288

Authored by Marko Tikvić
1 parent 685dd6223d
Exists in master

started work on pagination

Showing 2 changed files with 363 additions and 339 deletions   Show diff stats
... ... @@ -1,339 +0,0 @@
1   -package webutility
2   -
3   -import (
4   - "database/sql"
5   - "encoding/json"
6   - "errors"
7   - "fmt"
8   - "io"
9   - "net/http"
10   - "sync"
11   - "time"
12   -
13   - "git.to-net.rs/marko.tikvic/gologger"
14   -)
15   -
16   -var (
17   - mu = &sync.Mutex{}
18   - metadata = make(map[string]Payload)
19   -
20   - updateQue = make(map[string][]byte)
21   -
22   - metadataDB *sql.DB
23   - activeProject string
24   -
25   - inited bool
26   - driver string
27   - logger *gologger.Logger
28   -)
29   -
30   -type LangMap map[string]map[string]string
31   -
32   -type Field struct {
33   - Parameter string `json:"param"`
34   - Type string `json:"type"`
35   - Visible bool `json:"visible"`
36   - Editable bool `json:"editable"`
37   -}
38   -
39   -type CorrelationField struct {
40   - Result string `json:"result"`
41   - Elements []string `json:"elements"`
42   - Type string `json:"type"`
43   -}
44   -
45   -type Translation struct {
46   - Language string `json:"language"`
47   - FieldsLabels map[string]string `json:"fieldsLabels"`
48   -}
49   -
50   -type Payload struct {
51   - Method string `json:"method"`
52   - Params map[string]string `json:"params"`
53   - Lang []Translation `json:"lang"`
54   - Fields []Field `json:"fields"`
55   - Correlations []CorrelationField `json:"correlationFields"`
56   - IdField string `json:"idField"`
57   -
58   - // Data holds JSON payload.
59   - // It can't be used for itteration.
60   - Data interface{} `json:"data"`
61   -}
62   -
63   -func (p *Payload) SetData(data interface{}) {
64   - p.Data = data
65   -}
66   -
67   -// NewPayload returs a payload sceleton for entity described with etype.
68   -func NewPayload(r *http.Request, etype string) Payload {
69   - pload := metadata[etype]
70   - pload.Method = r.Method + " " + r.RequestURI
71   - return pload
72   -}
73   -
74   -// DecodeJSON decodes JSON data from r to v.
75   -// Returns an error if it fails.
76   -func DecodeJSON(r io.Reader, v interface{}) error {
77   - return json.NewDecoder(r).Decode(v)
78   -}
79   -
80   -// InitPayloadsMetadata loads all payloads' information into 'metadata' variable.
81   -func InitPayloadsMetadata(drv string, db *sql.DB, project string) error {
82   - var err error
83   - if drv != "ora" && drv != "mysql" {
84   - err = errors.New("driver not supported")
85   - return err
86   - }
87   -
88   - driver = drv
89   - metadataDB = db
90   - activeProject = project
91   -
92   - logger, err = gologger.New("metadata", gologger.MaxLogSize100KB)
93   - if err != nil {
94   - fmt.Printf("webutility: %s\n", err.Error())
95   - }
96   -
97   - mu.Lock()
98   - defer mu.Unlock()
99   - err = initMetadata(project)
100   - if err != nil {
101   - return err
102   - }
103   - inited = true
104   -
105   - return nil
106   -}
107   -
108   -func EnableHotloading(interval int) {
109   - if interval > 0 {
110   - go hotload(interval)
111   - }
112   -}
113   -
114   -func GetMetadataForAllEntities() map[string]Payload {
115   - return metadata
116   -}
117   -
118   -func GetMetadataForEntity(t string) (Payload, bool) {
119   - p, ok := metadata[t]
120   - return p, ok
121   -}
122   -
123   -func QueEntityModelUpdate(entityType string, v interface{}) {
124   - updateQue[entityType], _ = json.Marshal(v)
125   -}
126   -
127   -func UpdateEntityModels(command string) (total, upd, add int, err error) {
128   - if command != "force" && command != "missing" {
129   - return total, 0, 0, errors.New("webutility: unknown command: " + command)
130   - }
131   -
132   - if !inited {
133   - return 0, 0, 0, errors.New("webutility: metadata not initialized but update was tried.")
134   - }
135   -
136   - total = len(updateQue)
137   -
138   - toUpdate := make([]string, 0)
139   - toAdd := make([]string, 0)
140   -
141   - for k, _ := range updateQue {
142   - if _, exists := metadata[k]; exists {
143   - if command == "force" {
144   - toUpdate = append(toUpdate, k)
145   - }
146   - } else {
147   - toAdd = append(toAdd, k)
148   - }
149   - }
150   -
151   - var uStmt *sql.Stmt
152   - if driver == "ora" {
153   - uStmt, err = metadataDB.Prepare("update entities set entity_model = :1 where entity_type = :2")
154   - if err != nil {
155   - logger.Trace(err.Error())
156   - return
157   - }
158   - } else if driver == "mysql" {
159   - uStmt, err = metadataDB.Prepare("update entities set entity_model = ? where entity_type = ?")
160   - if err != nil {
161   - logger.Trace(err.Error())
162   - return
163   - }
164   - }
165   - for _, k := range toUpdate {
166   - _, err = uStmt.Exec(string(updateQue[k]), k)
167   - if err != nil {
168   - logger.Trace(err.Error())
169   - return
170   - }
171   - upd++
172   - }
173   -
174   - blankPayload, _ := json.Marshal(Payload{})
175   - var iStmt *sql.Stmt
176   - if driver == "ora" {
177   - iStmt, err = metadataDB.Prepare("insert into entities(projekat, metadata, entity_type, entity_model) values(:1, :2, :3, :4)")
178   - if err != nil {
179   - logger.Trace(err.Error())
180   - return
181   - }
182   - } else if driver == "mysql" {
183   - iStmt, err = metadataDB.Prepare("insert into entities(projekat, metadata, entity_type, entity_model) values(?, ?, ?, ?)")
184   - if err != nil {
185   - logger.Trace(err.Error())
186   - return
187   - }
188   - }
189   - for _, k := range toAdd {
190   - _, err = iStmt.Exec(activeProject, string(blankPayload), k, string(updateQue[k]))
191   - if err != nil {
192   - logger.Trace(err.Error())
193   - return
194   - }
195   - metadata[k] = Payload{}
196   - add++
197   - }
198   -
199   - return total, upd, add, nil
200   -}
201   -
202   -func initMetadata(project string) error {
203   - rows, err := metadataDB.Query(`select
204   - entity_type,
205   - metadata
206   - from entities
207   - where projekat = ` + fmt.Sprintf("'%s'", project))
208   - if err != nil {
209   - return err
210   - }
211   - defer rows.Close()
212   -
213   - if len(metadata) > 0 {
214   - metadata = nil
215   - }
216   - metadata = make(map[string]Payload)
217   - for rows.Next() {
218   - var name, load string
219   - rows.Scan(&name, &load)
220   -
221   - p := Payload{}
222   - err := json.Unmarshal([]byte(load), &p)
223   - if err != nil {
224   - logger.Log("webutility: couldn't init: '%s' metadata: %s:\n%s\n", name, err.Error(), load)
225   - } else {
226   - metadata[name] = p
227   - }
228   - }
229   -
230   - return nil
231   -}
232   -
233   -func hotload(n int) {
234   - entityScan := make(map[string]int64)
235   - firstCheck := true
236   - for {
237   - time.Sleep(time.Duration(n) * time.Second)
238   - rows, err := metadataDB.Query(`select
239   - ora_rowscn,
240   - entity_type
241   - from entities where projekat = ` + fmt.Sprintf("'%s'", activeProject))
242   - if err != nil {
243   - logger.Log("webutility: hotload failed: %v\n", err)
244   - time.Sleep(time.Duration(n) * time.Second)
245   - continue
246   - }
247   -
248   - var toRefresh []string
249   - for rows.Next() {
250   - var scanID int64
251   - var entity string
252   - rows.Scan(&scanID, &entity)
253   - oldID, ok := entityScan[entity]
254   - if !ok || oldID != scanID {
255   - entityScan[entity] = scanID
256   - toRefresh = append(toRefresh, entity)
257   - }
258   - }
259   - rows.Close()
260   -
261   - if rows.Err() != nil {
262   - logger.Log("webutility: hotload rset error: %v\n", rows.Err())
263   - time.Sleep(time.Duration(n) * time.Second)
264   - continue
265   - }
266   -
267   - if len(toRefresh) > 0 && !firstCheck {
268   - mu.Lock()
269   - refreshMetadata(toRefresh)
270   - mu.Unlock()
271   - }
272   - if firstCheck {
273   - firstCheck = false
274   - }
275   - }
276   -}
277   -
278   -func refreshMetadata(entities []string) {
279   - for _, e := range entities {
280   - fmt.Printf("refreshing %s\n", e)
281   - rows, err := metadataDB.Query(`select
282   - metadata
283   - from entities
284   - where projekat = ` + fmt.Sprintf("'%s'", activeProject) +
285   - ` and entity_type = ` + fmt.Sprintf("'%s'", e))
286   -
287   - if err != nil {
288   - logger.Log("webutility: refresh: prep: %v\n", err)
289   - rows.Close()
290   - continue
291   - }
292   -
293   - for rows.Next() {
294   - var load string
295   - rows.Scan(&load)
296   - p := Payload{}
297   - err := json.Unmarshal([]byte(load), &p)
298   - if err != nil {
299   - logger.Log("webutility: couldn't refresh: '%s' metadata: %s\n%s\n", e, err.Error(), load)
300   - } else {
301   - metadata[e] = p
302   - }
303   - }
304   - rows.Close()
305   - }
306   -}
307   -
308   -/*
309   -func ModifyMetadataForEntity(entityType string, p *Payload) error {
310   - md, err := json.Marshal(*p)
311   - if err != nil {
312   - return err
313   - }
314   -
315   - mu.Lock()
316   - defer mu.Unlock()
317   - _, err = metadataDB.PrepAndExe(`update entities set
318   - metadata = :1
319   - where projekat = :2
320   - and entity_type = :3`,
321   - string(md),
322   - activeProject,
323   - entityType)
324   - if err != nil {
325   - return err
326   - }
327   - return nil
328   -}
329   -
330   -func DeleteEntityModel(entityType string) error {
331   - _, err := metadataDB.PrepAndExe("delete from entities where entity_type = :1", entityType)
332   - if err == nil {
333   - mu.Lock()
334   - delete(metadata, entityType)
335   - mu.Unlock()
336   - }
337   - return err
338   -}
339   -*/
... ... @@ -0,0 +1,363 @@
  1 +package webutility
  2 +
  3 +import (
  4 + "database/sql"
  5 + "encoding/json"
  6 + "errors"
  7 + "fmt"
  8 + "io"
  9 + "net/http"
  10 + "sync"
  11 + "time"
  12 +
  13 + "git.to-net.rs/marko.tikvic/gologger"
  14 +)
  15 +
  16 +var (
  17 + mu = &sync.Mutex{}
  18 + metadata = make(map[string]Payload)
  19 +
  20 + updateQue = make(map[string][]byte)
  21 +
  22 + metadataDB *sql.DB
  23 + activeProject string
  24 +
  25 + inited bool
  26 + driver string
  27 + logger *gologger.Logger
  28 +)
  29 +
  30 +type LangMap map[string]map[string]string
  31 +
  32 +type Field struct {
  33 + Parameter string `json:"param"`
  34 + Type string `json:"type"`
  35 + Visible bool `json:"visible"`
  36 + Editable bool `json:"editable"`
  37 +}
  38 +
  39 +type CorrelationField struct {
  40 + Result string `json:"result"`
  41 + Elements []string `json:"elements"`
  42 + Type string `json:"type"`
  43 +}
  44 +
  45 +type Translation struct {
  46 + Language string `json:"language"`
  47 + FieldsLabels map[string]string `json:"fieldsLabels"`
  48 +}
  49 +
  50 +type PaginationLinks struct {
  51 + Base string `json:"base"`
  52 + Next string `json:"next"`
  53 + Prev string `json:"prev"`
  54 + Self string `json:"self"`
  55 +}
  56 +
  57 +type PaginationParameters struct {
  58 + Offset int64 `json:"offset"`
  59 + Limit int64 `json:"limit"`
  60 + SortBy string `json:"sortBy"`
  61 + Order string `json:"order"`
  62 +}
  63 +
  64 +type Payload struct {
  65 + Method string `json:"method"`
  66 + Params map[string]string `json:"params"`
  67 + Lang []Translation `json:"lang"`
  68 + Fields []Field `json:"fields"`
  69 + Correlations []CorrelationField `json:"correlationFields"`
  70 + IdField string `json:"idField"`
  71 +
  72 + // Pagination
  73 + Count int64 `json:"count"`
  74 + Total int64 `json:"total"`
  75 + Links *PaginationLinks `json:"_links"`
  76 +
  77 + // Data holds JSON payload. It can't be used for itteration.
  78 + Data interface{} `json:"data"`
  79 +}
  80 +
  81 +func (p *Payload) SetData(data interface{}) {
  82 + p.Data = data
  83 +}
  84 +
  85 +func (p *Payload) SetPaginationInfo(reqUrl string, count, total int64, params PaginationParameters) {
  86 + p.Count = count
  87 + p.Total = total
  88 +
  89 +}
  90 +
  91 +// NewPayload returs a payload sceleton for entity described with etype.
  92 +func NewPayload(r *http.Request, etype string) Payload {
  93 + pload := metadata[etype]
  94 + pload.Method = r.Method + " " + r.RequestURI
  95 + return pload
  96 +}
  97 +
  98 +// DecodeJSON decodes JSON data from r to v.
  99 +// Returns an error if it fails.
  100 +func DecodeJSON(r io.Reader, v interface{}) error {
  101 + return json.NewDecoder(r).Decode(v)
  102 +}
  103 +
  104 +// InitPayloadsMetadata loads all payloads' information into 'metadata' variable.
  105 +func InitPayloadsMetadata(drv string, db *sql.DB, project string) error {
  106 + var err error
  107 + if drv != "ora" && drv != "mysql" {
  108 + err = errors.New("driver not supported")
  109 + return err
  110 + }
  111 +
  112 + driver = drv
  113 + metadataDB = db
  114 + activeProject = project
  115 +
  116 + logger, err = gologger.New("metadata", gologger.MaxLogSize100KB)
  117 + if err != nil {
  118 + fmt.Printf("webutility: %s\n", err.Error())
  119 + }
  120 +
  121 + mu.Lock()
  122 + defer mu.Unlock()
  123 + err = initMetadata(project)
  124 + if err != nil {
  125 + return err
  126 + }
  127 + inited = true
  128 +
  129 + return nil
  130 +}
  131 +
  132 +func EnableHotloading(interval int) {
  133 + if interval > 0 {
  134 + go hotload(interval)
  135 + }
  136 +}
  137 +
  138 +func GetMetadataForAllEntities() map[string]Payload {
  139 + return metadata
  140 +}
  141 +
  142 +func GetMetadataForEntity(t string) (Payload, bool) {
  143 + p, ok := metadata[t]
  144 + return p, ok
  145 +}
  146 +
  147 +func QueEntityModelUpdate(entityType string, v interface{}) {
  148 + updateQue[entityType], _ = json.Marshal(v)
  149 +}
  150 +
  151 +func UpdateEntityModels(command string) (total, upd, add int, err error) {
  152 + if command != "force" && command != "missing" {
  153 + return total, 0, 0, errors.New("webutility: unknown command: " + command)
  154 + }
  155 +
  156 + if !inited {
  157 + return 0, 0, 0, errors.New("webutility: metadata not initialized but update was tried.")
  158 + }
  159 +
  160 + total = len(updateQue)
  161 +
  162 + toUpdate := make([]string, 0)
  163 + toAdd := make([]string, 0)
  164 +
  165 + for k, _ := range updateQue {
  166 + if _, exists := metadata[k]; exists {
  167 + if command == "force" {
  168 + toUpdate = append(toUpdate, k)
  169 + }
  170 + } else {
  171 + toAdd = append(toAdd, k)
  172 + }
  173 + }
  174 +
  175 + var uStmt *sql.Stmt
  176 + if driver == "ora" {
  177 + uStmt, err = metadataDB.Prepare("update entities set entity_model = :1 where entity_type = :2")
  178 + if err != nil {
  179 + logger.Trace(err.Error())
  180 + return
  181 + }
  182 + } else if driver == "mysql" {
  183 + uStmt, err = metadataDB.Prepare("update entities set entity_model = ? where entity_type = ?")
  184 + if err != nil {
  185 + logger.Trace(err.Error())
  186 + return
  187 + }
  188 + }
  189 + for _, k := range toUpdate {
  190 + _, err = uStmt.Exec(string(updateQue[k]), k)
  191 + if err != nil {
  192 + logger.Trace(err.Error())
  193 + return
  194 + }
  195 + upd++
  196 + }
  197 +
  198 + blankPayload, _ := json.Marshal(Payload{})
  199 + var iStmt *sql.Stmt
  200 + if driver == "ora" {
  201 + iStmt, err = metadataDB.Prepare("insert into entities(projekat, metadata, entity_type, entity_model) values(:1, :2, :3, :4)")
  202 + if err != nil {
  203 + logger.Trace(err.Error())
  204 + return
  205 + }
  206 + } else if driver == "mysql" {
  207 + iStmt, err = metadataDB.Prepare("insert into entities(projekat, metadata, entity_type, entity_model) values(?, ?, ?, ?)")
  208 + if err != nil {
  209 + logger.Trace(err.Error())
  210 + return
  211 + }
  212 + }
  213 + for _, k := range toAdd {
  214 + _, err = iStmt.Exec(activeProject, string(blankPayload), k, string(updateQue[k]))
  215 + if err != nil {
  216 + logger.Trace(err.Error())
  217 + return
  218 + }
  219 + metadata[k] = Payload{}
  220 + add++
  221 + }
  222 +
  223 + return total, upd, add, nil
  224 +}
  225 +
  226 +func initMetadata(project string) error {
  227 + rows, err := metadataDB.Query(`select
  228 + entity_type,
  229 + metadata
  230 + from entities
  231 + where projekat = ` + fmt.Sprintf("'%s'", project))
  232 + if err != nil {
  233 + return err
  234 + }
  235 + defer rows.Close()
  236 +
  237 + if len(metadata) > 0 {
  238 + metadata = nil
  239 + }
  240 + metadata = make(map[string]Payload)
  241 + for rows.Next() {
  242 + var name, load string
  243 + rows.Scan(&name, &load)
  244 +
  245 + p := Payload{}
  246 + err := json.Unmarshal([]byte(load), &p)
  247 + if err != nil {
  248 + logger.Log("webutility: couldn't init: '%s' metadata: %s:\n%s\n", name, err.Error(), load)
  249 + } else {
  250 + metadata[name] = p
  251 + }
  252 + }
  253 +
  254 + return nil
  255 +}
  256 +
  257 +func hotload(n int) {
  258 + entityScan := make(map[string]int64)
  259 + firstCheck := true
  260 + for {
  261 + time.Sleep(time.Duration(n) * time.Second)
  262 + rows, err := metadataDB.Query(`select
  263 + ora_rowscn,
  264 + entity_type
  265 + from entities where projekat = ` + fmt.Sprintf("'%s'", activeProject))
  266 + if err != nil {
  267 + logger.Log("webutility: hotload failed: %v\n", err)
  268 + time.Sleep(time.Duration(n) * time.Second)
  269 + continue
  270 + }
  271 +
  272 + var toRefresh []string
  273 + for rows.Next() {
  274 + var scanID int64
  275 + var entity string
  276 + rows.Scan(&scanID, &entity)
  277 + oldID, ok := entityScan[entity]
  278 + if !ok || oldID != scanID {
  279 + entityScan[entity] = scanID
  280 + toRefresh = append(toRefresh, entity)
  281 + }
  282 + }
  283 + rows.Close()
  284 +
  285 + if rows.Err() != nil {
  286 + logger.Log("webutility: hotload rset error: %v\n", rows.Err())
  287 + time.Sleep(time.Duration(n) * time.Second)
  288 + continue
  289 + }
  290 +
  291 + if len(toRefresh) > 0 && !firstCheck {
  292 + mu.Lock()
  293 + refreshMetadata(toRefresh)
  294 + mu.Unlock()
  295 + }
  296 + if firstCheck {
  297 + firstCheck = false
  298 + }
  299 + }
  300 +}
  301 +
  302 +func refreshMetadata(entities []string) {
  303 + for _, e := range entities {
  304 + fmt.Printf("refreshing %s\n", e)
  305 + rows, err := metadataDB.Query(`select
  306 + metadata
  307 + from entities
  308 + where projekat = ` + fmt.Sprintf("'%s'", activeProject) +
  309 + ` and entity_type = ` + fmt.Sprintf("'%s'", e))
  310 +
  311 + if err != nil {
  312 + logger.Log("webutility: refresh: prep: %v\n", err)
  313 + rows.Close()
  314 + continue
  315 + }
  316 +
  317 + for rows.Next() {
  318 + var load string
  319 + rows.Scan(&load)
  320 + p := Payload{}
  321 + err := json.Unmarshal([]byte(load), &p)
  322 + if err != nil {
  323 + logger.Log("webutility: couldn't refresh: '%s' metadata: %s\n%s\n", e, err.Error(), load)
  324 + } else {
  325 + metadata[e] = p
  326 + }
  327 + }
  328 + rows.Close()
  329 + }
  330 +}
  331 +
  332 +/*
  333 +func ModifyMetadataForEntity(entityType string, p *Payload) error {
  334 + md, err := json.Marshal(*p)
  335 + if err != nil {
  336 + return err
  337 + }
  338 +
  339 + mu.Lock()
  340 + defer mu.Unlock()
  341 + _, err = metadataDB.PrepAndExe(`update entities set
  342 + metadata = :1
  343 + where projekat = :2
  344 + and entity_type = :3`,
  345 + string(md),
  346 + activeProject,
  347 + entityType)
  348 + if err != nil {
  349 + return err
  350 + }
  351 + return nil
  352 +}
  353 +
  354 +func DeleteEntityModel(entityType string) error {
  355 + _, err := metadataDB.PrepAndExe("delete from entities where entity_type = :1", entityType)
  356 + if err == nil {
  357 + mu.Lock()
  358 + delete(metadata, entityType)
  359 + mu.Unlock()
  360 + }
  361 + return err
  362 +}
  363 +*/
... ...