Merge pull request #771 from trheyi/main
Add yao.component.GetOptions process
This commit is contained in:
commit
de630d8ecf
3 changed files with 100 additions and 24 deletions
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 ]]",
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue