Merge pull request #771 from trheyi/main

Add yao.component.GetOptions process
This commit is contained in:
Max 2024-11-03 12:09:00 +08:00 committed by GitHub
commit de630d8ecf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 100 additions and 24 deletions

View file

@ -106,6 +106,27 @@ func (dsl *DSL) Parse() {
if dsl.Props.Has(key) { if dsl.Props.Has(key) {
for k, v := range val { for k, v := range val {
dsl.Props[k] = dsl.copy(v) dsl.Props[k] = dsl.copy(v)
dsl.setRemoteParams(dsl.Props[k], key)
}
}
}
}
}
// This function is used to set the query parameters for the remote request
func (dsl *DSL) setRemoteParams(props interface{}, key string) {
if dsl.Props == nil {
return
}
if xProps, ok := dsl.Props["xProps"].(map[string]interface{}); ok {
if _, ok := xProps["$remote"].(map[string]interface{}); ok {
if keyProps, ok := dsl.Props[key].(map[string]interface{}); ok {
if params, ok := keyProps["params"]; ok {
if _, ok := props.(map[string]interface{}); ok {
if _, ok := props.(map[string]interface{})["$remote"].(map[string]interface{}); ok {
props.(map[string]interface{})["$remote"].(map[string]interface{})["query"] = params
}
}
} }
} }
} }

View file

@ -10,12 +10,14 @@ import (
"github.com/yaoapp/gou/process" "github.com/yaoapp/gou/process"
"github.com/yaoapp/gou/query" "github.com/yaoapp/gou/query"
"github.com/yaoapp/kun/exception" "github.com/yaoapp/kun/exception"
"github.com/yaoapp/kun/utils"
) )
var varRe = regexp.MustCompile(`\[\[\s*\$([A-Za-z0-9_\-]+)\s*\]\]`) var varRe = regexp.MustCompile(`\[\[\s*\$([A-Za-z0-9_\-]+)\s*\]\]`)
// QueryProp query prop // QueryProp query prop
type QueryProp struct { type QueryProp struct {
Debug bool `json:"debug,omitempty"`
Engine string `json:"engine"` Engine string `json:"engine"`
From string `json:"from"` From string `json:"from"`
LabelField string `json:"labelField,omitempty"` LabelField string `json:"labelField,omitempty"`
@ -56,7 +58,7 @@ func processGetOptions(process *process.Process) interface{} {
exception.New(err.Error(), 400).Throw() exception.New(err.Error(), 400).Throw()
} }
// Query the data // Using the query DSL
options := []Option{} options := []Option{}
if p.Engine != "" { if p.Engine != "" {
engine, err := query.Select(p.Engine) engine, err := query.Select(p.Engine)
@ -64,20 +66,52 @@ func processGetOptions(process *process.Process) interface{} {
exception.New(err.Error(), 400).Throw() exception.New(err.Error(), 400).Throw()
} }
if p.Debug {
fmt.Println("")
fmt.Println("-- yao.Component.GetOptions Debug ----------------------")
fmt.Println("Params: ")
utils.Dump(params)
fmt.Println("Engine: ", p.Engine)
fmt.Println("QueryDSL: ")
utils.Dump(p.dsl)
}
qb, err := engine.Load(p.dsl) qb, err := engine.Load(p.dsl)
if err != nil { if err != nil {
exception.New(err.Error(), 400).Throw() exception.New(err.Error(), 400).Throw()
} }
// Query the data // Query the data
data := qb.Get(nil) data := qb.Get(params)
if p.Debug {
fmt.Println("Query Result: ")
utils.Dump(data)
}
for _, row := range data { for _, row := range data {
p.format(&options, row) p.format(&options, row)
} }
if p.Debug {
fmt.Println("Options: ")
utils.Dump(options)
fmt.Println("-------------------------------------------------------")
}
return options return options
} }
// Using the QueryParam
if p.Debug {
fmt.Println("")
fmt.Println("-- yao.Component.GetOptions Debug ----------------------")
fmt.Println("Params: ")
utils.Dump(params)
fmt.Println("QueryParam: ")
utils.Dump(p.param)
}
// Query param // Query param
m := model.Select(p.From) m := model.Select(p.From)
data, err := m.Get(p.param) data, err := m.Get(p.param)
@ -85,16 +119,27 @@ func processGetOptions(process *process.Process) interface{} {
exception.New(err.Error(), 500).Throw() exception.New(err.Error(), 500).Throw()
} }
if p.Debug {
fmt.Println("Query Result: ")
utils.Dump(data)
}
// Format the data // Format the data
for _, row := range data { for _, row := range data {
p.format(&options, row) p.format(&options, row)
} }
if p.Debug {
fmt.Println("Options: ")
utils.Dump(options)
fmt.Println("-------------------------------------------------------")
}
return options return options
} }
// parseOptionsProps parse options props // parseOptionsProps parse options props
func parseOptionsProps(query, props map[string]interface{}) (*QueryProp, error) { func parseOptionsProps(params, props map[string]interface{}) (*QueryProp, error) {
if props["query"] == nil { if props["query"] == nil {
exception.New("props.query is required", 400).Throw() exception.New("props.query is required", 400).Throw()
} }
@ -104,16 +149,6 @@ func parseOptionsProps(query, props map[string]interface{}) (*QueryProp, error)
props = v props = v
} }
// Read query condition
var keywords string = ""
var selected interface{} = nil
if v, ok := query["keywords"].(string); ok {
keywords = v
}
if v, ok := query["selected"]; ok {
selected = v
}
raw, err := jsoniter.Marshal(props) raw, err := jsoniter.Marshal(props)
if err != nil { if err != nil {
return nil, err return nil, err
@ -126,7 +161,7 @@ func parseOptionsProps(query, props map[string]interface{}) (*QueryProp, error)
} }
qprops.props = props qprops.props = props
err = qprops.parse(keywords, selected) err = qprops.parse(params)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -158,11 +193,15 @@ func (q *QueryProp) format(options *[]Option, row map[string]interface{}) {
*options = append(*options, option) *options = append(*options, option)
} }
func (q *QueryProp) parse(keywords string, selected interface{}) error { func (q *QueryProp) parse(query map[string]interface{}) error {
if q.Wheres == nil { if q.Wheres == nil {
q.Wheres = []map[string]interface{}{} q.Wheres = []map[string]interface{}{}
} }
if query == nil {
query = map[string]interface{}{}
}
// Validate the query param required fields // Validate the query param required fields
if q.Engine == "" { if q.Engine == "" {
if q.From == "" { if q.From == "" {
@ -179,7 +218,7 @@ func (q *QueryProp) parse(keywords string, selected interface{}) error {
// Parse wheres // Parse wheres
wheres := []map[string]interface{}{} wheres := []map[string]interface{}{}
for _, where := range q.Wheres { for _, where := range q.Wheres {
if q.replaceWhere(where, map[string]interface{}{"KEYWORDS": keywords, "SELECTED": selected}) { if q.replaceWhere(where, query) {
wheres = append(wheres, where) wheres = append(wheres, where)
} }
} }
@ -263,6 +302,7 @@ func (q *QueryProp) replaceWhere(where map[string]interface{}, data map[string]i
if v, ok := value.(string); ok { if v, ok := value.(string); ok {
matches := varRe.FindAllStringSubmatch(v, -1) matches := varRe.FindAllStringSubmatch(v, -1)
if len(matches) > 0 { if len(matches) > 0 {
orignal := matches[0][0]
name := matches[0][1] name := matches[0][1]
if val, ok := data[name]; ok { if val, ok := data[name]; ok {
@ -271,8 +311,23 @@ func (q *QueryProp) replaceWhere(where map[string]interface{}, data map[string]i
return false return false
} }
if q.Engine == "" {
where[key] = val
// Replace the value
if v, ok := val.(string); ok {
where[key] = strings.Replace(v, orignal, fmt.Sprintf("%v", val), 1)
}
return true
}
// Where in condition for the query dsl
if where["in"] != nil {
where[key] = val
return true
}
// Replace the value // Replace the value
where[key] = val where[key] = strings.Replace(v, orignal, fmt.Sprintf("?:%v", name), 1) // SQL injection protection
return true return true
} }
return false return false

View file

@ -46,7 +46,7 @@ func TestProcessGetOptions(t *testing.T) {
assert.Equal(t, "1", res[0].Value) assert.Equal(t, "1", res[0].Value)
assert.Equal(t, "active-1", res[0].Icon) assert.Equal(t, "active-1", res[0].Icon)
// With KEYWORDS // With keywords
args = []interface{}{ args = []interface{}{
map[string]interface{}{"keywords": "dog"}, map[string]interface{}{"keywords": "dog"},
map[string]interface{}{"query": queryParam}, map[string]interface{}{"query": queryParam},
@ -75,7 +75,7 @@ func TestProcessGetOptions(t *testing.T) {
assert.Equal(t, "7", res[0].Value) assert.Equal(t, "7", res[0].Value)
assert.Equal(t, "active-7", res[0].Icon) assert.Equal(t, "active-7", res[0].Icon)
// With SELECTED // With selected
args = []interface{}{ args = []interface{}{
map[string]interface{}{"selected": []interface{}{1}}, map[string]interface{}{"selected": []interface{}{1}},
map[string]interface{}{"query": queryParam}, map[string]interface{}{"query": queryParam},
@ -103,7 +103,7 @@ func TestProcessGetOptions(t *testing.T) {
assert.Equal(t, "1", res[0].Value) assert.Equal(t, "1", res[0].Value)
assert.Equal(t, "active-1", res[0].Icon) assert.Equal(t, "active-1", res[0].Icon)
// With KEYWORDS and SELECTED // With keywords and selected
args = []interface{}{ args = []interface{}{
map[string]interface{}{"keywords": "dog", "selected": []interface{}{1, 2}}, map[string]interface{}{"keywords": "dog", "selected": []interface{}{1, 2}},
map[string]interface{}{"query": queryParam}, map[string]interface{}{"query": queryParam},
@ -183,12 +183,12 @@ func prepare(t *testing.T) map[string]map[string]interface{} {
"iconField": "status", "iconField": "status",
"from": "category", "from": "category",
"wheres": [ "wheres": [
{ "column": "name", "value": "[[ $KEYWORDS ]]", "op": "match" }, { "column": "name", "value": "[[ $keywords ]]", "op": "match" },
{ {
"method": "orwhere", "method": "orwhere",
"column": "id", "column": "id",
"op": "in", "op": "in",
"value": "[[ $SELECTED ]]" "value": "[[ $selected ]]"
} }
], ],
"limit": 20, "limit": 20,
@ -206,8 +206,8 @@ func prepare(t *testing.T) map[string]map[string]interface{} {
"select": ["name as label", "id as value", "status as icon"], "select": ["name as label", "id as value", "status as icon"],
"from": "category", "from": "category",
"wheres": [ "wheres": [
{ "field": "name", "match": "[[ $KEYWORDS ]]" }, { "field": "name", "match": "[[ $keywords ]]" },
{ "or": true, "field":"id", "in":"[[ $SELECTED ]]" } { "or": true, "field":"id", "in":"[[ $selected ]]" }
], ],
"limit": 20, "limit": 20,
"labelFormat": "[[ $label ]]-[[ $icon ]]", "labelFormat": "[[ $label ]]-[[ $icon ]]",