json_utility.go 4.18 KB
package webutility

import (
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"
	"sync"

	"gopkg.in/rana/ora.v4"
)

var mu = &sync.Mutex{}
var payloads []Payload

type LangMap map[string]map[string]string

type Field struct {
	Parameter string `json:"param"`
	Type      string `json:"type"`
	Visible   bool   `json:"visible"`
	Editable  bool   `json:"editable"`
}

type CorrelationField struct {
	Result   string   `json:"result"`
	Elements []string `json:"elements"`
	Type     string   `json:"type"`
}

type Translation struct {
	Language     string            `json:"language"`
	FieldsLabels map[string]string `json:"fieldsLabels"`
}

type Payload struct {
	Type         string             `json:"type"`
	Method       string             `json:"method"`
	Params       map[string]string  `json:"params"`
	Lang         []Translation      `json:"lang"`
	Fields       []Field            `json:"fields"`
	Correlations []CorrelationField `json:"correlationFields"`
	IdField      string             `json:"idField"`

	// Data holds JSON payload. It can't be used for itteration.
	Data interface{} `json:"data"`
}

// InitTables loads all payloads in the payloads variable.
// Returns an error if it fails.
func InitTables(db *ora.Ses, project string) error {
	jsonbuf, err := fetchJSON(db, project)
	if err != nil {
		return err
	}

	mu.Lock()
	defer mu.Unlock()
	json.Unmarshal(jsonbuf, &payloads)
	if len(payloads) == 0 {
		return errors.New("tables config is corrupt")
	}
	return nil
}

// ReloadTables reloads all payloads in the payloads variable.
// Returns an error if it fails.
func ReloadTables(db *ora.Ses, project string) error {
	payloads = make([]Payload, 0)
	return InitTables(db, project)
}

// DecodeJSON decodes JSON data from r to v.
// Returns an error if it fails.
func DecodeJSON(r io.Reader, v interface{}) error {
	return json.NewDecoder(r).Decode(v)
}

// NewPayload returs a payload sceleton for provided table.
func NewPayload(r *http.Request, table string) Payload {
	var pload Payload

	pload.Method = r.Method + " " + r.RequestURI
	pload.Type = table
	if table != "" {
		pload.Params = make(map[string]string, 0)
		pload.Lang = translations(table)
		pload.Fields = fields(table)
		pload.IdField = id(table)
		pload.Correlations = correlations(table)
	}
	return pload
}

// DeliverPayload encodes payload to w.
func DeliverPayload(w http.ResponseWriter, payload Payload) {
	json.NewEncoder(w).Encode(payload)
	payload.Data = nil
}

// translations returns a slice of translations for a payload/table of ptype type.
func translations(ptype string) []Translation {
	var translations []Translation

	for _, pload := range payloads {
		if pload.Type == ptype {
			for _, t := range pload.Lang {
				translations = append(translations, Translation{
					Language:     t.Language,
					FieldsLabels: t.FieldsLabels,
				})
			}
		}
	}

	return translations
}

// fields returns a slice of fields for a payload/table of ptype type.
func fields(ptype string) []Field {
	var fields []Field

	for _, pload := range payloads {
		if pload.Type == ptype {
			for _, f := range pload.Fields {
				fields = append(fields, f)
			}
		}
	}

	return fields
}

// id returns the name of ID field of a payload/table of ptype type.
func id(ptype string) string {
	for _, pload := range payloads {
		if pload.Type == ptype {
			return pload.IdField
		}
	}
	return ""
}

// correlations returns a slice of correlation fields for a payload/table of ptype type.
func correlations(ptype string) []CorrelationField {
	var corr []CorrelationField

	for _, pload := range payloads {
		if pload.Type == ptype {
			for _, c := range pload.Correlations {
				corr = append(corr, c)
			}
		}
	}

	return corr
}

// fetchJSON returns a byte slice of JSON configuration file from TABLES_CONFIG table.
// Returns an error if it fails.
func fetchJSON(db *ora.Ses, project string) ([]byte, error) {
	db.SetCfg(db.Cfg().SetClob(ora.S))
	stmt, err := db.Prep(`SELECT JSON_NCLOB FROM TABLES_CONFIG WHERE PROJEKAT = `+fmt.Sprintf("'%s'", project), ora.S)
	defer stmt.Close()
	if err != nil {
		return nil, err
	}

	rset, err := stmt.Qry()
	if err != nil {
		return nil, err
	}

	var data string
	if rset.Next() {
		data = rset.Row[0].(string)
	}

	//fmt.Println(data)
	return []byte(data), nil
}