yao/widgets/component/props.go

217 lines
5.4 KiB
Go

package component
import (
"fmt"
"net/url"
"strings"
jsoniter "github.com/json-iterator/go"
gouProcess "github.com/yaoapp/gou/process"
"github.com/yaoapp/gou/types"
"github.com/yaoapp/kun/log"
)
// CloudProps parse CloudProps
func (p PropsDSL) CloudProps(xpath, component string) (map[string]CloudPropsDSL, error) {
if p == nil {
return nil, fmt.Errorf("props is required")
}
return p.parseCloudProps(xpath, component, p, p)
}
// Path api path
func (cProp CloudPropsDSL) Path() string {
return fmt.Sprintf("/component/%s/%s", url.QueryEscape(cProp.Xpath), url.QueryEscape(cProp.Name))
}
// UploadPath api UploadPath
func (cProp CloudPropsDSL) UploadPath() string {
return fmt.Sprintf("/upload/%s/%s", url.QueryEscape(cProp.Xpath), url.QueryEscape(cProp.Name))
}
// ExecUpload execute upload
func (cProp CloudPropsDSL) ExecUpload(process *gouProcess.Process, upload types.UploadFile) (interface{}, error) {
if upload.TempFile == "" {
log.Error("[component] %s.$%s upload file is required", cProp.Xpath, cProp.Name)
return nil, fmt.Errorf("[component] %s.$%s upload file is required", cProp.Xpath, cProp.Name)
}
// Process
name := cProp.Process
if name == "" {
log.Error("[component] %s.$%s process is required", cProp.Xpath, cProp.Name)
return nil, fmt.Errorf("[component] %s.$%s process is required", cProp.Xpath, cProp.Name)
}
// Create process
p, err := gouProcess.Of(name, upload, cProp.Props)
if err != nil {
log.Error("[component] %s.$%s %s", cProp.Xpath, cProp.Name, err.Error())
return nil, fmt.Errorf("[component] %s.$%s %s", cProp.Xpath, cProp.Name, err.Error())
}
// Excute process
err = p.WithGlobal(process.Global).WithSID(process.Sid).Execute()
if err != nil {
log.Error("[component] %s.$%s %s", cProp.Xpath, cProp.Name, err.Error())
return nil, fmt.Errorf("[component] %s.$%s %s", cProp.Xpath, cProp.Name, err.Error())
}
defer p.Release()
res := p.Value()
return res, nil
}
// ExecQuery execute query
func (cProp CloudPropsDSL) ExecQuery(process *gouProcess.Process, query map[string]interface{}) (interface{}, error) {
if query == nil {
query = map[string]interface{}{}
}
// filter array
for key, value := range query {
if strings.HasSuffix(key, "[]") {
query[strings.TrimSuffix(key, "[]")] = value
delete(query, key)
}
}
// Process
name := cProp.Process
if name == "" {
log.Error("[component] %s.$%s process is required", cProp.Xpath, cProp.Name)
return nil, fmt.Errorf("[component] %s.$%s process is required", cProp.Xpath, cProp.Name)
}
// Create process
p, err := gouProcess.Of(name, query, cProp.Props)
if err != nil {
log.Error("[component] %s.$%s %s", cProp.Xpath, cProp.Name, err.Error())
return nil, fmt.Errorf("[component] %s.$%s %s", cProp.Xpath, cProp.Name, err.Error())
}
// Excute process
err = p.WithGlobal(process.Global).WithSID(process.Sid).Execute()
if err != nil {
log.Error("[component] %s.$%s %s", cProp.Xpath, cProp.Name, err.Error())
return nil, fmt.Errorf("[component] %s.$%s %s", cProp.Xpath, cProp.Name, err.Error())
}
defer p.Release()
res := p.Value()
return res, nil
}
// Replace xpath
func (cProp CloudPropsDSL) Replace(data interface{}, replace func(cProp CloudPropsDSL) interface{}) error {
return cProp.replaceAny(data, "", replace)
}
func (cProp CloudPropsDSL) replaceAny(data interface{}, root string, replace func(cProp CloudPropsDSL) interface{}) error {
switch data.(type) {
case map[string]interface{}:
return cProp.replaceMap(data.(map[string]interface{}), root, replace)
}
return nil
}
func (cProp CloudPropsDSL) replaceMap(data map[string]interface{}, root string, replace func(cProp CloudPropsDSL) interface{}) error {
xpath := fmt.Sprintf(".%s.$%s", cProp.Xpath, cProp.Name)
// get keys
keys := []string{}
for key := range data {
keys = append(keys, key)
}
for _, key := range keys {
path := fmt.Sprintf("%s.%s", root, key)
if !strings.HasPrefix(xpath, path) {
continue
}
// Replace field
if path == xpath {
data[cProp.Name] = replace(cProp)
delete(data, fmt.Sprintf("$%s", cProp.Name))
continue
}
err := cProp.replaceAny(data[key], path, replace)
if err != nil {
return err
}
}
return nil
}
func (p PropsDSL) parseCloudProps(xpath string, component string, props map[string]interface{}, root map[string]interface{}) (map[string]CloudPropsDSL, error) {
res := map[string]CloudPropsDSL{}
for name, prop := range props {
fullname := fmt.Sprintf("%s.%s", xpath, name)
if sub, ok := prop.(map[string]interface{}); ok {
cProps, err := p.parseCloudProps(fullname, component, sub, root)
if err != nil {
return nil, err
}
for k, v := range cProps {
res[k] = v
}
}
if !strings.HasPrefix(name, "$") {
continue
}
cProp := &CloudPropsDSL{
Name: strings.TrimPrefix(name, "$"),
Type: component,
Xpath: xpath,
Props: root,
}
err := cProp.Parse(prop)
if err != nil {
return nil, fmt.Errorf("%s %s", fullname, err.Error())
}
cProp.Xpath = xpath
res[fullname] = *cProp
}
return res, nil
}
// Has check if the prop exists in the props
func (p PropsDSL) Has(name string) bool {
_, has := p[name]
if has {
return has
}
// check if the prop is a cloud prop
_, has = p[fmt.Sprintf("$%s", name)]
return has
}
// Parse parse cloud props
func (cProp *CloudPropsDSL) Parse(v interface{}) error {
bytes, err := jsoniter.Marshal(v)
if err != nil {
return err
}
err = jsoniter.Unmarshal(bytes, cProp)
if err != nil {
return err
}
return nil
}