yao/widgets/table/compute.go
2022-10-22 10:52:00 +08:00

281 lines
7.1 KiB
Go

package table
import (
"fmt"
"reflect"
"strings"
"github.com/yaoapp/gou"
"github.com/yaoapp/kun/any"
"github.com/yaoapp/kun/maps"
)
var computeViews = map[string]bool{
"yao.table.find": true,
"yao.table.get": true,
"yao.table.search": true,
}
func (dsl *DSL) computeMapping() error {
if dsl.computes == nil {
dsl.computes = &computeMaps{
filter: map[string][]compute{},
edit: map[string][]compute{},
view: map[string][]compute{},
}
}
if dsl.Fields == nil {
return nil
}
// Filter
if dsl.Fields.Filter != nil && dsl.Layout.Filter != nil && dsl.Layout.Filter.Columns != nil {
for _, inst := range dsl.Layout.Filter.Columns {
if filter, has := dsl.Fields.Filter[inst.Name]; has {
if filter.Edit != nil && filter.Edit.Compute != nil {
bind := filter.FilterBind()
if _, has := dsl.computes.filter[bind]; !has {
dsl.computes.filter[bind] = []compute{}
}
dsl.computes.filter[bind] = append(dsl.computes.filter[bind], compute{name: inst.Name, kind: TypeFilter})
}
}
}
}
if dsl.Fields.Table != nil && dsl.Layout.Table != nil && dsl.Layout.Table.Columns != nil {
for _, inst := range dsl.Layout.Table.Columns {
if field, has := dsl.Fields.Table[inst.Name]; has {
// View
if field.View != nil && field.View.Compute != nil {
bind := field.ViewBind()
if _, has := dsl.computes.view[bind]; !has {
dsl.computes.view[bind] = []compute{}
}
dsl.computes.view[bind] = append(dsl.computes.view[bind], compute{name: inst.Name, kind: TypeView})
}
// Edit
if field.Edit != nil && field.Edit.Compute != nil {
bind := field.EditBind()
if _, has := dsl.computes.edit[bind]; !has {
dsl.computes.edit[bind] = []compute{}
}
dsl.computes.edit[bind] = append(dsl.computes.edit[bind], compute{name: inst.Name, kind: TypeEdit})
}
}
}
}
return nil
}
func (dsl *DSL) computeView(name string, process *gou.Process, res interface{}) error {
if _, has := computeViews[strings.ToLower(name)]; !has {
return nil
}
switch res.(type) {
case []maps.MapStrAny, []interface{}:
return dsl.computeViewRows(name, process, res)
case map[string]interface{}:
return dsl.computeViewRow(name, process, res.(map[string]interface{}))
case maps.MapStrAny:
return dsl.computeViewRow(name, process, res.(maps.MapStrAny))
}
return fmt.Errorf("res should be a map or array, but got a %s", reflect.ValueOf(res).Kind().String())
}
func (dsl *DSL) computeViewRows(name string, process *gou.Process, res interface{}) error {
switch res.(type) {
case []interface{}:
messages := []string{}
for i := range res.([]interface{}) {
err := dsl.computeView(name, process, res.([]interface{})[i])
if err != nil {
messages = append(messages, err.Error())
}
}
if len(messages) > 0 {
return fmt.Errorf("\n%s", strings.Join(messages, ";\n"))
}
return nil
case []maps.MapStrAny:
messages := []string{}
for i := range res.([]maps.MapStrAny) {
err := dsl.computeView(name, process, res.([]maps.MapStrAny)[i])
if err != nil {
messages = append(messages, fmt.Sprintf("%d %s", i, err.Error()))
}
}
if len(messages) > 0 {
return fmt.Errorf("\n%s", strings.Join(messages, ";\n"))
}
return nil
}
return nil
}
func (dsl *DSL) computeViewRow(name string, process *gou.Process, res map[string]interface{}) error {
messages := []string{}
row := maps.MapOf(res).Dot()
data := maps.StrAny{"row": row}.Dot()
// page
if row.Has("data") && row.Has("total") &&
row.Has("pagesize") && row.Has("pagecnt") &&
row.Has("prev") && row.Has("next") {
switch res["data"].(type) {
case []maps.MapStrAny:
return dsl.computeViewRows(name, process, res["data"].([]maps.MapStrAny))
case []interface{}:
return dsl.computeViewRows(name, process, res["data"].([]interface{}))
}
}
for key, computes := range dsl.computes.view {
c := computes[0]
field := dsl.Fields.Table[c.name]
data.Set("value", res[key])
data.Merge(any.MapOf(field.View.Map()).MapStrAny.Dot())
new, err := field.View.Compute.Value(data, process.Sid, process.Global)
if err != nil {
res[key] = nil
messages = append(messages, fmt.Sprintf("fields.table.%s bind: %s, value: %v error: %s", c.name, key, res[key], err.Error()))
continue
}
res[key] = new
}
if len(messages) > 0 {
return fmt.Errorf("\n%s", strings.Join(messages, ";\n"))
}
return nil
}
func (dsl *DSL) computeEdit(name string, process *gou.Process, args []interface{}) error {
name = strings.ToLower(name)
switch name {
case "yao.table.save", "yao.table.create":
if len(args) == 0 {
return nil
}
switch args[0].(type) {
case maps.MapStr:
return dsl.computeEditRow(name, process, args[0].(maps.MapStr))
case map[string]interface{}:
return dsl.computeEditRow(name, process, args[0].(map[string]interface{}))
}
return nil
case "yao.table.update", "yao.table.updatewhere", "yao.table.updatein":
if len(args) < 2 {
return nil
}
switch args[1].(type) {
case maps.MapStr:
return dsl.computeEditRow(name, process, args[1].(maps.MapStr))
case map[string]interface{}:
return dsl.computeEditRow(name, process, args[1].(map[string]interface{}))
}
return nil
case "yao.table.insert":
if len(args) < 2 {
return nil
}
if _, ok := args[0].([]string); !ok {
return fmt.Errorf("args[0] is not a []string %s", reflect.ValueOf(args[0]).Type().Name())
}
if _, ok := args[1].([][]interface{}); !ok {
return fmt.Errorf("args[1] is not a [][] %s", reflect.ValueOf(args[1]).Type().Name())
}
return dsl.computeEditRows(name, process, args[0].([]string), args[1].([][]interface{}))
}
return nil
}
func (dsl *DSL) computeEditRow(name string, process *gou.Process, res map[string]interface{}) error {
messages := []string{}
row := maps.MapOf(res).Dot()
data := maps.StrAny{"row": row}.Dot()
for key := range res {
if computes, has := dsl.computes.edit[key]; has {
c := computes[0]
field := dsl.Fields.Table[c.name]
data.Set("value", res[key])
data.Merge(any.MapOf(field.Edit.Map()).MapStrAny.Dot())
new, err := field.Edit.Compute.Value(data, process.Sid, process.Global)
if err != nil {
messages = append(messages, fmt.Sprintf("fields.table.%s bind: %s, value: %v error: %s", c.name, key, res[key], err.Error()))
continue
}
res[key] = new
}
}
if len(messages) > 0 {
return fmt.Errorf("\n%s", strings.Join(messages, ";\n"))
}
return nil
}
func (dsl *DSL) computeEditRows(name string, process *gou.Process, columns []string, res [][]interface{}) error {
messages := []string{}
keys := map[string]int{}
for i, name := range columns {
keys[name] = i
}
for i := range res {
if len(keys) != len(res[i]) {
continue
}
row := map[string]interface{}{}
for i, v := range res[i] {
row[columns[i]] = v
}
err := dsl.computeEditRow(name, process, row)
if err != nil {
messages = append(messages, err.Error())
}
for k, v := range row {
res[i][keys[k]] = v
}
}
if len(messages) > 0 {
return fmt.Errorf("\n%s", strings.Join(messages, ";\n"))
}
return nil
}
func (dsl *DSL) computeFilter(name string, process *gou.Process, args []interface{}) error {
return nil
}