-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdynql.go
150 lines (128 loc) · 3.35 KB
/
dynql.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package dynql
import (
"encoding/json"
"io/ioutil"
"net/http"
"reflect"
"sort"
"sync"
"github.com/yalp/jsonpath"
)
type Handler func(name string, i interface{}, r *http.Request, payload interface{}, parent interface{}) interface{}
type DQL struct {
handlers map[string]Handler
parameters map[string]interface{}
}
type ParamQuery struct {
Method string `json:"method"`
Hidden bool
Name string
Input interface{}
Output map[string]string
Fork map[string]ParamQuery
}
func NewDQL() *DQL {
return &DQL{handlers: make(map[string]Handler), parameters: make(map[string]interface{})}
}
func (dql DQL) Put(name string, handler Handler, param interface{}) {
dql.handlers[name] = handler
dql.parameters[name] = param
}
func (dql DQL) Get(name string) Handler {
return dql.handlers[name]
}
func (dql DQL) run(pMapQuery *map[string]ParamQuery, r *http.Request, prevElement interface{}, parent interface{}) (interface{}, error) {
keys := []string{}
mapQuery := *pMapQuery
mapQueryReturn := make(map[string]interface{})
for k, _ := range mapQuery {
keys = append(keys, k)
}
sort.Strings(keys)
var m sync.Mutex
for _, k := range keys {
func() {
m.Lock()
defer func() { m.Unlock() }()
paramQuery := mapQuery[k]
realMethod := paramQuery.Method
if dql.handlers[paramQuery.Method] == nil {
paramQuery.Method = "default"
}
paramByte, _ := json.Marshal(paramQuery.Input)
param := reflect.New(reflect.TypeOf(dql.parameters[paramQuery.Method])).Interface()
json.Unmarshal(paramByte, param)
elem := dql.handlers[paramQuery.Method](realMethod, param, r, prevElement, parent)
prevElement = elem
if paramQuery.Fork != nil {
item := make(map[string]interface{})
for k, v := range elem.(map[string]interface{}) {
item[k] = v
}
result, err := dql.run(¶mQuery.Fork, r, prevElement, prevElement)
if err != nil {
item["error"] = err
} else {
if result != nil {
for k, v := range result.(map[string]interface{}) {
item[k] = v
}
}
}
elem = item
prevElement = elem
}
keyReport := k
if paramQuery.Name != "" {
keyReport = paramQuery.Name
}
if paramQuery.Output == nil {
if !paramQuery.Hidden {
mapQueryReturn[keyReport] = elem
}
return
}
if !paramQuery.Hidden {
result := make(map[string]interface{})
for k, v := range paramQuery.Output {
var payload interface{}
var sample []byte
sample, _ = json.Marshal(elem)
_ = json.Unmarshal(sample, &payload)
var err error
result[k], err = jsonpath.Read(payload, v)
if err != nil {
result[k] = err
}
}
mapQueryReturn[keyReport] = result
}
}()
}
var payload interface{}
var sample []byte
sample, _ = json.Marshal(mapQueryReturn)
_ = json.Unmarshal(sample, &payload)
return payload, nil
}
// Run execute query
func (dql DQL) Run(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
body, err := ioutil.ReadAll(r.Body)
mapQuery := make(map[string]ParamQuery)
if err != nil {
_ = json.NewEncoder(w).Encode(err)
}
_ = json.Unmarshal(body, &mapQuery)
payload, err := dql.run(&mapQuery, r, nil, nil)
q := r.URL.Query().Get("q")
if q == "" {
q = "$"
}
result, err := jsonpath.Read(payload, q)
if err != nil {
json.NewEncoder(w).Encode(err)
return
}
json.NewEncoder(w).Encode(result)
}