Commit 1257b237add893d84a7fb973eab6506de75fb161

Authored by Marko Tikvić
1 parent f38e87cf4c
Exists in master

todo

Showing 1 changed file with 1 additions and 0 deletions   Show diff stats
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 "os" 10 "os"
11 "strings" 11 "strings"
12 "sync" 12 "sync"
13 "time" 13 "time"
14 14
15 "git.to-net.rs/marko.tikvic/gologger" 15 "git.to-net.rs/marko.tikvic/gologger"
16 ) 16 )
17 17
18 var ( 18 var (
19 mu = &sync.Mutex{} 19 mu = &sync.Mutex{}
20 metadata = make(map[string]Payload) 20 metadata = make(map[string]Payload)
21 21
22 updateQue = make(map[string][]byte) 22 updateQue = make(map[string][]byte)
23 23
24 metadataDB *sql.DB 24 metadataDB *sql.DB
25 activeProject string 25 activeProject string
26 26
27 inited bool 27 inited bool
28 driver string 28 driver string
29 logger *gologger.Logger 29 logger *gologger.Logger
30 ) 30 )
31 31
32 type LangMap map[string]map[string]string 32 type LangMap map[string]map[string]string
33 33
34 type Field struct { 34 type Field struct {
35 Parameter string `json:"param"` 35 Parameter string `json:"param"`
36 Type string `json:"type"` 36 Type string `json:"type"`
37 Visible bool `json:"visible"` 37 Visible bool `json:"visible"`
38 Editable bool `json:"editable"` 38 Editable bool `json:"editable"`
39 } 39 }
40 40
41 type CorrelationField struct { 41 type CorrelationField struct {
42 Result string `json:"result"` 42 Result string `json:"result"`
43 Elements []string `json:"elements"` 43 Elements []string `json:"elements"`
44 Type string `json:"type"` 44 Type string `json:"type"`
45 } 45 }
46 46
47 type Translation struct { 47 type Translation struct {
48 Language string `json:"language"` 48 Language string `json:"language"`
49 FieldsLabels map[string]string `json:"fieldsLabels"` 49 FieldsLabels map[string]string `json:"fieldsLabels"`
50 } 50 }
51 51
52 // output 52 // output
53 type PaginationLinks struct { 53 type PaginationLinks struct {
54 Base string `json:"base"` 54 Base string `json:"base"`
55 Next string `json:"next"` 55 Next string `json:"next"`
56 Prev string `json:"prev"` 56 Prev string `json:"prev"`
57 Self string `json:"self"` 57 Self string `json:"self"`
58 } 58 }
59 59
60 // input 60 // input
61 type PaginationParameters struct { 61 type PaginationParameters struct {
62 URL string `json:"-"` 62 URL string `json:"-"`
63 Offset int64 `json:"offset"` 63 Offset int64 `json:"offset"`
64 Limit int64 `json:"limit"` 64 Limit int64 `json:"limit"`
65 SortBy string `json:"sortBy"` 65 SortBy string `json:"sortBy"`
66 Order string `json:"order"` 66 Order string `json:"order"`
67 } 67 }
68 68
69 // TODO(marko) 69 // TODO(marko)
70 func GetPaginationParameters(req *http.Request) (p PaginationParameters) { 70 func GetPaginationParameters(req *http.Request) (p PaginationParameters) {
71 return p 71 return p
72 } 72 }
73 73
74 // TODO(marko) 74 // TODO(marko)
75 func (p *PaginationParameters) paginationLinks() (links PaginationLinks) { 75 func (p *PaginationParameters) paginationLinks() (links PaginationLinks) {
76 return links 76 return links
77 } 77 }
78 78
79 type Payload struct { 79 type Payload struct {
80 Method string `json:"method"` 80 Method string `json:"method"`
81 Params map[string]string `json:"params"` 81 Params map[string]string `json:"params"`
82 Lang []Translation `json:"lang"` 82 Lang []Translation `json:"lang"`
83 Fields []Field `json:"fields"` 83 Fields []Field `json:"fields"`
84 Correlations []CorrelationField `json:"correlationFields"` 84 Correlations []CorrelationField `json:"correlationFields"`
85 IdField string `json:"idField"` 85 IdField string `json:"idField"`
86 86
87 // Pagination 87 // Pagination
88 Count int64 `json:"count"` 88 Count int64 `json:"count"`
89 Total int64 `json:"total"` 89 Total int64 `json:"total"`
90 Links PaginationLinks `json:"_links"` 90 Links PaginationLinks `json:"_links"`
91 91
92 // Data holds JSON payload. It can't be used for itteration. 92 // Data holds JSON payload. It can't be used for itteration.
93 Data interface{} `json:"data"` 93 Data interface{} `json:"data"`
94 } 94 }
95 95
96 func (p *Payload) addLang(code string, labels map[string]string) { 96 func (p *Payload) addLang(code string, labels map[string]string) {
97 t := Translation{ 97 t := Translation{
98 Language: code, 98 Language: code,
99 FieldsLabels: labels, 99 FieldsLabels: labels,
100 } 100 }
101 p.Lang = append(p.Lang, t) 101 p.Lang = append(p.Lang, t)
102 } 102 }
103 103
104 func (p *Payload) SetData(data interface{}) { 104 func (p *Payload) SetData(data interface{}) {
105 p.Data = data 105 p.Data = data
106 } 106 }
107 107
108 func (p *Payload) SetPaginationInfo(count, total int64, params PaginationParameters) { 108 func (p *Payload) SetPaginationInfo(count, total int64, params PaginationParameters) {
109 p.Count = count 109 p.Count = count
110 p.Total = total 110 p.Total = total
111 p.Links = params.paginationLinks() 111 p.Links = params.paginationLinks()
112 } 112 }
113 113
114 // NewPayload returs a payload sceleton for entity described with key. 114 // NewPayload returs a payload sceleton for entity described with key.
115 func NewPayload(r *http.Request, key string) Payload { 115 func NewPayload(r *http.Request, key string) Payload {
116 p := metadata[key] 116 p := metadata[key]
117 p.Method = r.Method + " " + r.RequestURI 117 p.Method = r.Method + " " + r.RequestURI
118 return p 118 return p
119 } 119 }
120 120
121 // DecodeJSON decodes JSON data from r to v. 121 // DecodeJSON decodes JSON data from r to v.
122 // Returns an error if it fails. 122 // Returns an error if it fails.
123 func DecodeJSON(r io.Reader, v interface{}) error { 123 func DecodeJSON(r io.Reader, v interface{}) error {
124 return json.NewDecoder(r).Decode(v) 124 return json.NewDecoder(r).Decode(v)
125 } 125 }
126 126
127 // InitPayloadsMetadata loads all payloads' information into 'metadata' variable. 127 // InitPayloadsMetadata loads all payloads' information into 'metadata' variable.
128 func InitPayloadsMetadata(drv string, db *sql.DB, project string) error { 128 func InitPayloadsMetadata(drv string, db *sql.DB, project string) error {
129 var err error 129 var err error
130 if drv != "ora" && drv != "mysql" { 130 if drv != "ora" && drv != "mysql" {
131 err = errors.New("driver not supported") 131 err = errors.New("driver not supported")
132 return err 132 return err
133 } 133 }
134 134
135 driver = drv 135 driver = drv
136 metadataDB = db 136 metadataDB = db
137 activeProject = project 137 activeProject = project
138 138
139 logger, err = gologger.New("metadata", gologger.MaxLogSize100KB) 139 logger, err = gologger.New("metadata", gologger.MaxLogSize100KB)
140 if err != nil { 140 if err != nil {
141 fmt.Printf("webutility: %s\n", err.Error()) 141 fmt.Printf("webutility: %s\n", err.Error())
142 } 142 }
143 143
144 mu.Lock() 144 mu.Lock()
145 defer mu.Unlock() 145 defer mu.Unlock()
146 err = initMetadata(project) 146 err = initMetadata(project)
147 if err != nil { 147 if err != nil {
148 return err 148 return err
149 } 149 }
150 inited = true 150 inited = true
151 151
152 return nil 152 return nil
153 } 153 }
154 154
155 func EnableHotloading(interval int) { 155 func EnableHotloading(interval int) {
156 if interval > 0 { 156 if interval > 0 {
157 go hotload(interval) 157 go hotload(interval)
158 } 158 }
159 } 159 }
160 160
161 func GetMetadataForAllEntities() map[string]Payload { 161 func GetMetadataForAllEntities() map[string]Payload {
162 return metadata 162 return metadata
163 } 163 }
164 164
165 func GetMetadataForEntity(t string) (Payload, bool) { 165 func GetMetadataForEntity(t string) (Payload, bool) {
166 p, ok := metadata[t] 166 p, ok := metadata[t]
167 return p, ok 167 return p, ok
168 } 168 }
169 169
170 func QueEntityModelUpdate(entityType string, v interface{}) { 170 func QueEntityModelUpdate(entityType string, v interface{}) {
171 updateQue[entityType], _ = json.Marshal(v) 171 updateQue[entityType], _ = json.Marshal(v)
172 } 172 }
173 173
174 func UpdateEntityModels(command string) (total, upd, add int, err error) { 174 func UpdateEntityModels(command string) (total, upd, add int, err error) {
175 if command != "force" && command != "missing" { 175 if command != "force" && command != "missing" {
176 return total, 0, 0, errors.New("webutility: unknown command: " + command) 176 return total, 0, 0, errors.New("webutility: unknown command: " + command)
177 } 177 }
178 178
179 if !inited { 179 if !inited {
180 return 0, 0, 0, errors.New("webutility: metadata not initialized but update was tried.") 180 return 0, 0, 0, errors.New("webutility: metadata not initialized but update was tried.")
181 } 181 }
182 182
183 total = len(updateQue) 183 total = len(updateQue)
184 184
185 toUpdate := make([]string, 0) 185 toUpdate := make([]string, 0)
186 toAdd := make([]string, 0) 186 toAdd := make([]string, 0)
187 187
188 for k, _ := range updateQue { 188 for k, _ := range updateQue {
189 if _, exists := metadata[k]; exists { 189 if _, exists := metadata[k]; exists {
190 if command == "force" { 190 if command == "force" {
191 toUpdate = append(toUpdate, k) 191 toUpdate = append(toUpdate, k)
192 } 192 }
193 } else { 193 } else {
194 toAdd = append(toAdd, k) 194 toAdd = append(toAdd, k)
195 } 195 }
196 } 196 }
197 197
198 var uStmt *sql.Stmt 198 var uStmt *sql.Stmt
199 if driver == "ora" { 199 if driver == "ora" {
200 uStmt, err = metadataDB.Prepare("update entities set entity_model = :1 where entity_type = :2") 200 uStmt, err = metadataDB.Prepare("update entities set entity_model = :1 where entity_type = :2")
201 if err != nil { 201 if err != nil {
202 logger.Trace(err.Error()) 202 logger.Trace(err.Error())
203 return 203 return
204 } 204 }
205 } else if driver == "mysql" { 205 } else if driver == "mysql" {
206 uStmt, err = metadataDB.Prepare("update entities set entity_model = ? where entity_type = ?") 206 uStmt, err = metadataDB.Prepare("update entities set entity_model = ? where entity_type = ?")
207 if err != nil { 207 if err != nil {
208 logger.Trace(err.Error()) 208 logger.Trace(err.Error())
209 return 209 return
210 } 210 }
211 } 211 }
212 for _, k := range toUpdate { 212 for _, k := range toUpdate {
213 _, err = uStmt.Exec(string(updateQue[k]), k) 213 _, err = uStmt.Exec(string(updateQue[k]), k)
214 if err != nil { 214 if err != nil {
215 logger.Trace(err.Error()) 215 logger.Trace(err.Error())
216 return 216 return
217 } 217 }
218 upd++ 218 upd++
219 } 219 }
220 220
221 blankPayload, _ := json.Marshal(Payload{}) 221 blankPayload, _ := json.Marshal(Payload{})
222 var iStmt *sql.Stmt 222 var iStmt *sql.Stmt
223 if driver == "ora" { 223 if driver == "ora" {
224 iStmt, err = metadataDB.Prepare("insert into entities(projekat, metadata, entity_type, entity_model) values(:1, :2, :3, :4)") 224 iStmt, err = metadataDB.Prepare("insert into entities(projekat, metadata, entity_type, entity_model) values(:1, :2, :3, :4)")
225 if err != nil { 225 if err != nil {
226 logger.Trace(err.Error()) 226 logger.Trace(err.Error())
227 return 227 return
228 } 228 }
229 } else if driver == "mysql" { 229 } else if driver == "mysql" {
230 iStmt, err = metadataDB.Prepare("insert into entities(projekat, metadata, entity_type, entity_model) values(?, ?, ?, ?)") 230 iStmt, err = metadataDB.Prepare("insert into entities(projekat, metadata, entity_type, entity_model) values(?, ?, ?, ?)")
231 if err != nil { 231 if err != nil {
232 logger.Trace(err.Error()) 232 logger.Trace(err.Error())
233 return 233 return
234 } 234 }
235 } 235 }
236 for _, k := range toAdd { 236 for _, k := range toAdd {
237 _, err = iStmt.Exec(activeProject, string(blankPayload), k, string(updateQue[k])) 237 _, err = iStmt.Exec(activeProject, string(blankPayload), k, string(updateQue[k]))
238 if err != nil { 238 if err != nil {
239 logger.Trace(err.Error()) 239 logger.Trace(err.Error())
240 return 240 return
241 } 241 }
242 metadata[k] = Payload{} 242 metadata[k] = Payload{}
243 add++ 243 add++
244 } 244 }
245 245
246 return total, upd, add, nil 246 return total, upd, add, nil
247 } 247 }
248 248
249 func initMetadata(project string) error { 249 func initMetadata(project string) error {
250 rows, err := metadataDB.Query(`select 250 rows, err := metadataDB.Query(`select
251 entity_type, 251 entity_type,
252 metadata 252 metadata
253 from entities 253 from entities
254 where projekat = ` + fmt.Sprintf("'%s'", project)) 254 where projekat = ` + fmt.Sprintf("'%s'", project))
255 if err != nil { 255 if err != nil {
256 return err 256 return err
257 } 257 }
258 defer rows.Close() 258 defer rows.Close()
259 259
260 if len(metadata) > 0 { 260 if len(metadata) > 0 {
261 metadata = nil 261 metadata = nil
262 } 262 }
263 metadata = make(map[string]Payload) 263 metadata = make(map[string]Payload)
264 for rows.Next() { 264 for rows.Next() {
265 var name, load string 265 var name, load string
266 rows.Scan(&name, &load) 266 rows.Scan(&name, &load)
267 267
268 p := Payload{} 268 p := Payload{}
269 err := json.Unmarshal([]byte(load), &p) 269 err := json.Unmarshal([]byte(load), &p)
270 if err != nil { 270 if err != nil {
271 logger.Log("webutility: couldn't init: '%s' metadata: %s:\n%s\n", name, err.Error(), load) 271 logger.Log("webutility: couldn't init: '%s' metadata: %s:\n%s\n", name, err.Error(), load)
272 } else { 272 } else {
273 metadata[name] = p 273 metadata[name] = p
274 } 274 }
275 } 275 }
276 276
277 return nil 277 return nil
278 } 278 }
279 279
280 // TODO(marko): 280 // TODO(marko):
281 // 281 //
282 // Currently supports only one hardcoded language... 282 // Currently supports only one hardcoded language...
283 // 283 //
284 // 284 //
285 // 285 //
286 // 286 //
287 // 287 //
288 // Metadata file ecpected format: 288 // Metadata file ecpected format:
289 // 289 //
290 // [ payload A identifier ] 290 // [ payload A identifier ]
291 // key1 : value1 291 // key1 : value1
292 // key2 : value2 292 // key2 : value2
293 // ... 293 // ...
294 // [ payload B identifier ] 294 // [ payload B identifier ]
295 // key1 : value1 295 // key1 : value1
296 // key2 : value2 296 // key2 : value2
297 // ... 297 // ...
298 func LoadMetadataFromFile(path string) error { 298 func LoadMetadataFromFile(path string) error {
299 lines, err := ReadFileLines(path) 299 lines, err := ReadFileLines(path)
300 if err != nil { 300 if err != nil {
301 return err 301 return err
302 } 302 }
303 303
304 metadata = make(map[string]Payload) 304 metadata = make(map[string]Payload)
305 305
306 var name string 306 var name string
307 for i, l := range lines { 307 for i, l := range lines {
308 // skip empty lines 308 // skip empty lines
309 if l = trimSpaces(l); len(l) == 0 { 309 if l = trimSpaces(l); len(l) == 0 {
310 continue 310 continue
311 } 311 }
312 312
313 if isWrappedWith(l, "[", "]") { 313 if isWrappedWith(l, "[", "]") {
314 name = strings.Trim(l, "[]") 314 name = strings.Trim(l, "[]")
315 p := Payload{} 315 p := Payload{}
316 p.addLang("sr", make(map[string]string)) 316 p.addLang("sr", make(map[string]string))
317 metadata[name] = p 317 metadata[name] = p
318 continue 318 continue
319 } 319 }
320 320
321 if name == "" { 321 if name == "" {
322 return fmt.Errorf("webutility: LoadMetadataFromFile: error on line %d: [no header] [%s]\n", i+1, l) 322 return fmt.Errorf("webutility: LoadMetadataFromFile: error on line %d: [no header] [%s]\n", i+1, l)
323 } 323 }
324 324
325 parts := strings.Split(l, ":") 325 parts := strings.Split(l, ":")
326 if len(parts) != 2 { 326 if len(parts) != 2 {
327 return fmt.Errorf("webutility: LoadMetadataFromFile: error on line %d: [invalid format] [%s]\n", i+1, l) 327 return fmt.Errorf("webutility: LoadMetadataFromFile: error on line %d: [invalid format] [%s]\n", i+1, l)
328 } 328 }
329 329
330 k := trimSpaces(parts[0]) 330 k := trimSpaces(parts[0])
331 v := trimSpaces(parts[1]) 331 v := trimSpaces(parts[1])
332 if v != "-" { 332 if v != "-" {
333 metadata[name].Lang[0].FieldsLabels[k] = v 333 metadata[name].Lang[0].FieldsLabels[k] = v
334 } 334 }
335 } 335 }
336 336
337 return nil 337 return nil
338 } 338 }
339 339
340 func isWrappedWith(src, begin, end string) bool { 340 func isWrappedWith(src, begin, end string) bool {
341 return strings.HasPrefix(src, begin) && strings.HasSuffix(src, end) 341 return strings.HasPrefix(src, begin) && strings.HasSuffix(src, end)
342 } 342 }
343 343
344 func trimSpaces(s string) string { 344 func trimSpaces(s string) string {
345 return strings.TrimSpace(s) 345 return strings.TrimSpace(s)
346 } 346 }
347 347
348 // TODO(marko): Move to separate package
348 func ReadFileLines(path string) ([]string, error) { 349 func ReadFileLines(path string) ([]string, error) {
349 f, err := os.Open(path) 350 f, err := os.Open(path)
350 if err != nil { 351 if err != nil {
351 return nil, err 352 return nil, err
352 } 353 }
353 defer f.Close() 354 defer f.Close()
354 355
355 var s strings.Builder 356 var s strings.Builder
356 357
357 if _, err = io.Copy(&s, f); err != nil { 358 if _, err = io.Copy(&s, f); err != nil {
358 return nil, err 359 return nil, err
359 } 360 }
360 361
361 lines := strings.Split(s.String(), "\n") 362 lines := strings.Split(s.String(), "\n")
362 363
363 return lines, nil 364 return lines, nil
364 } 365 }
365 366
366 func hotload(n int) { 367 func hotload(n int) {
367 entityScan := make(map[string]int64) 368 entityScan := make(map[string]int64)
368 firstCheck := true 369 firstCheck := true
369 for { 370 for {
370 time.Sleep(time.Duration(n) * time.Second) 371 time.Sleep(time.Duration(n) * time.Second)
371 rows, err := metadataDB.Query(`select 372 rows, err := metadataDB.Query(`select
372 ora_rowscn, 373 ora_rowscn,
373 entity_type 374 entity_type
374 from entities where projekat = ` + fmt.Sprintf("'%s'", activeProject)) 375 from entities where projekat = ` + fmt.Sprintf("'%s'", activeProject))
375 if err != nil { 376 if err != nil {
376 logger.Log("webutility: hotload failed: %v\n", err) 377 logger.Log("webutility: hotload failed: %v\n", err)
377 time.Sleep(time.Duration(n) * time.Second) 378 time.Sleep(time.Duration(n) * time.Second)
378 continue 379 continue
379 } 380 }
380 381
381 var toRefresh []string 382 var toRefresh []string
382 for rows.Next() { 383 for rows.Next() {
383 var scanID int64 384 var scanID int64
384 var entity string 385 var entity string
385 rows.Scan(&scanID, &entity) 386 rows.Scan(&scanID, &entity)
386 oldID, ok := entityScan[entity] 387 oldID, ok := entityScan[entity]
387 if !ok || oldID != scanID { 388 if !ok || oldID != scanID {
388 entityScan[entity] = scanID 389 entityScan[entity] = scanID
389 toRefresh = append(toRefresh, entity) 390 toRefresh = append(toRefresh, entity)
390 } 391 }
391 } 392 }
392 rows.Close() 393 rows.Close()
393 394
394 if rows.Err() != nil { 395 if rows.Err() != nil {
395 logger.Log("webutility: hotload rset error: %v\n", rows.Err()) 396 logger.Log("webutility: hotload rset error: %v\n", rows.Err())
396 time.Sleep(time.Duration(n) * time.Second) 397 time.Sleep(time.Duration(n) * time.Second)
397 continue 398 continue
398 } 399 }
399 400
400 if len(toRefresh) > 0 && !firstCheck { 401 if len(toRefresh) > 0 && !firstCheck {
401 mu.Lock() 402 mu.Lock()
402 refreshMetadata(toRefresh) 403 refreshMetadata(toRefresh)
403 mu.Unlock() 404 mu.Unlock()
404 } 405 }
405 if firstCheck { 406 if firstCheck {
406 firstCheck = false 407 firstCheck = false
407 } 408 }
408 } 409 }
409 } 410 }
410 411
411 func refreshMetadata(entities []string) { 412 func refreshMetadata(entities []string) {
412 for _, e := range entities { 413 for _, e := range entities {
413 fmt.Printf("refreshing %s\n", e) 414 fmt.Printf("refreshing %s\n", e)
414 rows, err := metadataDB.Query(`select 415 rows, err := metadataDB.Query(`select
415 metadata 416 metadata
416 from entities 417 from entities
417 where projekat = ` + fmt.Sprintf("'%s'", activeProject) + 418 where projekat = ` + fmt.Sprintf("'%s'", activeProject) +
418 ` and entity_type = ` + fmt.Sprintf("'%s'", e)) 419 ` and entity_type = ` + fmt.Sprintf("'%s'", e))
419 420
420 if err != nil { 421 if err != nil {
421 logger.Log("webutility: refresh: prep: %v\n", err) 422 logger.Log("webutility: refresh: prep: %v\n", err)
422 rows.Close() 423 rows.Close()
423 continue 424 continue
424 } 425 }
425 426
426 for rows.Next() { 427 for rows.Next() {
427 var load string 428 var load string
428 rows.Scan(&load) 429 rows.Scan(&load)
429 p := Payload{} 430 p := Payload{}
430 err := json.Unmarshal([]byte(load), &p) 431 err := json.Unmarshal([]byte(load), &p)
431 if err != nil { 432 if err != nil {
432 logger.Log("webutility: couldn't refresh: '%s' metadata: %s\n%s\n", e, err.Error(), load) 433 logger.Log("webutility: couldn't refresh: '%s' metadata: %s\n%s\n", e, err.Error(), load)
433 } else { 434 } else {
434 metadata[e] = p 435 metadata[e] = p
435 } 436 }
436 } 437 }
437 rows.Close() 438 rows.Close()
438 } 439 }
439 } 440 }
440 441
441 /* 442 /*
442 func ModifyMetadataForEntity(entityType string, p *Payload) error { 443 func ModifyMetadataForEntity(entityType string, p *Payload) error {
443 md, err := json.Marshal(*p) 444 md, err := json.Marshal(*p)
444 if err != nil { 445 if err != nil {
445 return err 446 return err
446 } 447 }
447 448
448 mu.Lock() 449 mu.Lock()
449 defer mu.Unlock() 450 defer mu.Unlock()
450 _, err = metadataDB.PrepAndExe(`update entities set 451 _, err = metadataDB.PrepAndExe(`update entities set
451 metadata = :1 452 metadata = :1
452 where projekat = :2 453 where projekat = :2
453 and entity_type = :3`, 454 and entity_type = :3`,
454 string(md), 455 string(md),
455 activeProject, 456 activeProject,
456 entityType) 457 entityType)
457 if err != nil { 458 if err != nil {
458 return err 459 return err
459 } 460 }
460 return nil 461 return nil
461 } 462 }
462 463
463 func DeleteEntityModel(entityType string) error { 464 func DeleteEntityModel(entityType string) error {
464 _, err := metadataDB.PrepAndExe("delete from entities where entity_type = :1", entityType) 465 _, err := metadataDB.PrepAndExe("delete from entities where entity_type = :1", entityType)
465 if err == nil { 466 if err == nil {
466 mu.Lock() 467 mu.Lock()
467 delete(metadata, entityType) 468 delete(metadata, entityType)
468 mu.Unlock() 469 mu.Unlock()
469 } 470 }
470 return err 471 return err
471 } 472 }
472 */ 473 */
473 474