diff --git a/widgets/component/component.go b/widgets/component/component.go index 686177234..118174936 100644 --- a/widgets/component/component.go +++ b/widgets/component/component.go @@ -106,6 +106,27 @@ func (dsl *DSL) Parse() { if dsl.Props.Has(key) { for k, v := range val { 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 + } + } } } } diff --git a/widgets/component/process.go b/widgets/component/process.go index 2216d9140..5032566f7 100644 --- a/widgets/component/process.go +++ b/widgets/component/process.go @@ -10,12 +10,14 @@ import ( "github.com/yaoapp/gou/process" "github.com/yaoapp/gou/query" "github.com/yaoapp/kun/exception" + "github.com/yaoapp/kun/utils" ) var varRe = regexp.MustCompile(`\[\[\s*\$([A-Za-z0-9_\-]+)\s*\]\]`) // QueryProp query prop type QueryProp struct { + Debug bool `json:"debug,omitempty"` Engine string `json:"engine"` From string `json:"from"` LabelField string `json:"labelField,omitempty"` @@ -56,7 +58,7 @@ func processGetOptions(process *process.Process) interface{} { exception.New(err.Error(), 400).Throw() } - // Query the data + // Using the query DSL options := []Option{} if p.Engine != "" { engine, err := query.Select(p.Engine) @@ -64,20 +66,52 @@ func processGetOptions(process *process.Process) interface{} { 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) if err != nil { exception.New(err.Error(), 400).Throw() } // 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 { p.format(&options, row) } + if p.Debug { + fmt.Println("Options: ") + utils.Dump(options) + fmt.Println("-------------------------------------------------------") + } + 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 m := model.Select(p.From) data, err := m.Get(p.param) @@ -85,16 +119,27 @@ func processGetOptions(process *process.Process) interface{} { exception.New(err.Error(), 500).Throw() } + if p.Debug { + fmt.Println("Query Result: ") + utils.Dump(data) + } + // Format the data for _, row := range data { p.format(&options, row) } + if p.Debug { + fmt.Println("Options: ") + utils.Dump(options) + fmt.Println("-------------------------------------------------------") + } + return options } // 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 { exception.New("props.query is required", 400).Throw() } @@ -104,16 +149,6 @@ func parseOptionsProps(query, props map[string]interface{}) (*QueryProp, error) 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) if err != nil { return nil, err @@ -126,7 +161,7 @@ func parseOptionsProps(query, props map[string]interface{}) (*QueryProp, error) } qprops.props = props - err = qprops.parse(keywords, selected) + err = qprops.parse(params) if err != nil { return nil, err } @@ -158,11 +193,15 @@ func (q *QueryProp) format(options *[]Option, row map[string]interface{}) { *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 { q.Wheres = []map[string]interface{}{} } + if query == nil { + query = map[string]interface{}{} + } + // Validate the query param required fields if q.Engine == "" { if q.From == "" { @@ -179,7 +218,7 @@ func (q *QueryProp) parse(keywords string, selected interface{}) error { // Parse wheres wheres := []map[string]interface{}{} 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) } } @@ -263,6 +302,7 @@ func (q *QueryProp) replaceWhere(where map[string]interface{}, data map[string]i if v, ok := value.(string); ok { matches := varRe.FindAllStringSubmatch(v, -1) if len(matches) > 0 { + orignal := matches[0][0] name := matches[0][1] if val, ok := data[name]; ok { @@ -271,8 +311,23 @@ func (q *QueryProp) replaceWhere(where map[string]interface{}, data map[string]i 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 - where[key] = val + where[key] = strings.Replace(v, orignal, fmt.Sprintf("?:%v", name), 1) // SQL injection protection return true } return false diff --git a/widgets/component/process_test.go b/widgets/component/process_test.go index 5506cc258..64d83969d 100644 --- a/widgets/component/process_test.go +++ b/widgets/component/process_test.go @@ -46,7 +46,7 @@ func TestProcessGetOptions(t *testing.T) { assert.Equal(t, "1", res[0].Value) assert.Equal(t, "active-1", res[0].Icon) - // With KEYWORDS + // With keywords args = []interface{}{ map[string]interface{}{"keywords": "dog"}, map[string]interface{}{"query": queryParam}, @@ -75,7 +75,7 @@ func TestProcessGetOptions(t *testing.T) { assert.Equal(t, "7", res[0].Value) assert.Equal(t, "active-7", res[0].Icon) - // With SELECTED + // With selected args = []interface{}{ map[string]interface{}{"selected": []interface{}{1}}, map[string]interface{}{"query": queryParam}, @@ -103,7 +103,7 @@ func TestProcessGetOptions(t *testing.T) { assert.Equal(t, "1", res[0].Value) assert.Equal(t, "active-1", res[0].Icon) - // With KEYWORDS and SELECTED + // With keywords and selected args = []interface{}{ map[string]interface{}{"keywords": "dog", "selected": []interface{}{1, 2}}, map[string]interface{}{"query": queryParam}, @@ -183,12 +183,12 @@ func prepare(t *testing.T) map[string]map[string]interface{} { "iconField": "status", "from": "category", "wheres": [ - { "column": "name", "value": "[[ $KEYWORDS ]]", "op": "match" }, + { "column": "name", "value": "[[ $keywords ]]", "op": "match" }, { "method": "orwhere", "column": "id", "op": "in", - "value": "[[ $SELECTED ]]" + "value": "[[ $selected ]]" } ], "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"], "from": "category", "wheres": [ - { "field": "name", "match": "[[ $KEYWORDS ]]" }, - { "or": true, "field":"id", "in":"[[ $SELECTED ]]" } + { "field": "name", "match": "[[ $keywords ]]" }, + { "or": true, "field":"id", "in":"[[ $selected ]]" } ], "limit": 20, "labelFormat": "[[ $label ]]-[[ $icon ]]",