[add] widget table bind table support

This commit is contained in:
Max 2022-10-07 11:47:59 +08:00
parent 5d32073ffc
commit 48d3ec8bfa
9 changed files with 270 additions and 63 deletions

View file

@ -6,6 +6,20 @@ import (
"github.com/yaoapp/gou"
)
// CopyBefore copy a before hook
func CopyBefore(hook *Before, new *Before) {
if hook != nil {
*hook = *new
}
}
// CopyAfter copy a after hook
func CopyAfter(hook *After, new *After) {
if hook != nil {
*hook = *new
}
}
// Exec execute the hook
func (hook *Before) Exec(args []interface{}, sid string, global map[string]interface{}) ([]interface{}, error) {

View file

@ -8,6 +8,7 @@ import (
"github.com/yaoapp/kun/log"
"github.com/yaoapp/kun/maps"
"github.com/yaoapp/yao/widgets/action"
"github.com/yaoapp/yao/widgets/hook"
)
var processActionDefaults = map[string]*action.Process{
@ -159,7 +160,7 @@ func (act *ActionDSL) SetDefaultProcess() {
}
// BindModel bind model
func (act *ActionDSL) BindModel(m *gou.Model) {
func (act *ActionDSL) BindModel(m *gou.Model) error {
name := m.ID
act.Search.Bind(fmt.Sprintf("models.%s.Paginate", name))
@ -181,6 +182,54 @@ func (act *ActionDSL) BindModel(m *gou.Model) {
act.Get.DefaultMerge([]interface{}{act.Bind.Option})
act.Find.DefaultMerge([]interface{}{nil, act.Bind.Option})
}
return nil
}
// BindTable bind table
func (act *ActionDSL) BindTable(tab *DSL) error {
// Copy Hooks
hook.CopyBefore(act.BeforeSearch, tab.Action.BeforeSearch)
hook.CopyBefore(act.BeforeGet, tab.Action.BeforeGet)
hook.CopyBefore(act.BeforeFind, tab.Action.BeforeFind)
hook.CopyBefore(act.BeforeSave, tab.Action.BeforeSave)
hook.CopyBefore(act.BeforeCreate, tab.Action.BeforeCreate)
hook.CopyBefore(act.BeforeInsert, tab.Action.BeforeInsert)
hook.CopyBefore(act.BeforeUpdate, tab.Action.BeforeUpdate)
hook.CopyBefore(act.BeforeUpdateWhere, tab.Action.BeforeUpdateWhere)
hook.CopyBefore(act.BeforeUpdateIn, tab.Action.BeforeUpdateIn)
hook.CopyBefore(act.BeforeDelete, tab.Action.BeforeDelete)
hook.CopyBefore(act.BeforeDeleteWhere, tab.Action.BeforeDeleteWhere)
hook.CopyBefore(act.BeforeDeleteIn, tab.Action.BeforeDeleteIn)
hook.CopyAfter(act.AfterSearch, tab.Action.AfterSearch)
hook.CopyAfter(act.AfterGet, tab.Action.AfterGet)
hook.CopyAfter(act.AfterFind, tab.Action.AfterFind)
hook.CopyAfter(act.AfterSave, tab.Action.AfterSave)
hook.CopyAfter(act.AfterCreate, tab.Action.AfterCreate)
hook.CopyAfter(act.AfterInsert, tab.Action.AfterInsert)
hook.CopyAfter(act.AfterUpdate, tab.Action.AfterUpdate)
hook.CopyAfter(act.AfterUpdateWhere, tab.Action.AfterUpdateWhere)
hook.CopyAfter(act.AfterUpdateIn, tab.Action.AfterUpdateIn)
hook.CopyAfter(act.AfterDelete, tab.Action.AfterDelete)
hook.CopyAfter(act.AfterDeleteWhere, tab.Action.AfterDeleteWhere)
hook.CopyAfter(act.AfterDeleteIn, tab.Action.AfterDeleteIn)
// Merge Actions
act.Search.Merge(tab.Action.Search)
act.Get.Merge(tab.Action.Get)
act.Find.Merge(tab.Action.Find)
act.Save.Merge(tab.Action.Save)
act.Create.Merge(tab.Action.Create)
act.Insert.Merge(tab.Action.Insert)
act.Update.Merge(tab.Action.Update)
act.UpdateWhere.Merge(tab.Action.UpdateWhere)
act.UpdateIn.Merge(tab.Action.UpdateIn)
act.Delete.Merge(tab.Action.Delete)
act.DeleteWhere.Merge(tab.Action.DeleteWhere)
act.DeleteIn.Merge(tab.Action.DeleteIn)
return nil
}
func processHandler(p *action.Process, process *gou.Process) (interface{}, error) {

View file

@ -41,8 +41,57 @@ func (dsl *DSL) bindModel() error {
return err
}
dsl.Action.BindModel(m)
dsl.Layout.BindModel(m, dsl.Fields)
err = dsl.Action.BindModel(m)
if err != nil {
return err
}
err = dsl.Layout.BindModel(m, dsl.Fields)
if err != nil {
return err
}
return nil
}
func (dsl *DSL) bindTable() error {
// Bind ID
id := dsl.Action.Bind.Table
if id == dsl.ID {
return fmt.Errorf("bind.table %s can't bind self table", id)
}
// Load table
if _, has := Tables[id]; !has {
if err := LoadID(id, dsl.Root); err != nil {
return err
}
}
tab, err := Get(id)
if err != nil {
return err
}
// Bind Fields
err = dsl.Fields.BindTable(tab)
if err != nil {
return err
}
// Bind Actions
err = dsl.Action.BindTable(tab)
if err != nil {
return err
}
// Bind Layout
err = dsl.Layout.BindTable(tab, dsl.Fields)
if err != nil {
return err
}
return nil
}
@ -50,8 +99,3 @@ func (dsl *DSL) bindStore() error {
id := dsl.Action.Bind.Store
return fmt.Errorf("bind.store %s does not support yet", id)
}
func (dsl *DSL) bindTable() error {
id := dsl.Action.Bind.Table
return fmt.Errorf("bind.table %s does not support yet", id)
}

View file

@ -41,6 +41,36 @@ func (fields *FieldsDSL) BindModel(m *gou.Model) error {
return nil
}
// BindTable bind table
func (fields *FieldsDSL) BindTable(tab *DSL) error {
// Bind filter
if fields.Filter == nil || len(fields.Filter) == 0 {
fields.Filter = tab.Fields.Filter
} else if tab.Fields.Filter != nil {
for key, filter := range tab.Fields.Filter {
if _, has := fields.Filter[key]; !has {
fields.Filter[key] = filter
}
}
}
// Bind Table
if fields.Table == nil || len(fields.Table) == 0 {
fields.Table = tab.Fields.Table
} else if tab.Fields.Table != nil {
for key, table := range tab.Fields.Table {
if _, has := fields.Table[key]; !has {
fields.Table[key] = table
}
}
}
return nil
}
// Xgen trans to xgen setting
func (fields *FieldsDSL) Xgen(layout *LayoutDSL) (map[string]interface{}, error) {
res := map[string]interface{}{}

View file

@ -9,7 +9,7 @@ import (
)
// BindModel bind model
func (layout *LayoutDSL) BindModel(m *gou.Model, fields *FieldsDSL) {
func (layout *LayoutDSL) BindModel(m *gou.Model, fields *FieldsDSL) error {
if layout.Primary == "" {
layout.Primary = m.PrimaryKey
@ -50,6 +50,28 @@ func (layout *LayoutDSL) BindModel(m *gou.Model, fields *FieldsDSL) {
}
}
return nil
}
// BindTable bind table
func (layout *LayoutDSL) BindTable(tab *DSL, fields *FieldsDSL) error {
if layout.Primary == "" {
layout.Primary = tab.Layout.Primary
}
if layout.Filter == nil && tab.Layout.Filter != nil {
layout.Filter = &FilterLayoutDSL{}
*layout.Filter = *tab.Layout.Filter
}
if layout.Table == nil && tab.Layout.Table != nil {
layout.Table = &ViewLayoutDSL{}
*layout.Table = *tab.Layout.Table
}
return nil
}
// Xgen trans to Xgen setting

View file

@ -91,11 +91,11 @@ func New(id string) *DSL {
// LoadAndExport load table
func LoadAndExport(cfg config.Config) error {
err := Load(cfg)
err := Export()
if err != nil {
return err
}
return Export()
return Load(cfg)
}
// Load load table
@ -104,6 +104,21 @@ func Load(cfg config.Config) error {
return LoadFrom(root, "")
}
// LoadID load by id
func LoadID(id string, root string) error {
dirs := strings.Split(id, ".")
name := fmt.Sprintf("%s.tab.json", dirs[len(dirs)-1])
elems := []string{root}
elems = append(elems, dirs[0:len(dirs)-1]...)
elems = append(elems, name)
filename := filepath.Join(elems...)
data, err := environment.ReadFile(filename)
if err != nil {
return fmt.Errorf("[%s] root=%s %s", id, root, err.Error())
}
return LoadData(data, id, root)
}
// LoadFrom load from dir
func LoadFrom(dir string, prefix string) error {
@ -115,58 +130,16 @@ func LoadFrom(dir string, prefix string) error {
err := share.Walk(dir, ".json", func(root, filename string) {
id := prefix + share.ID(root, filename)
data, err := environment.ReadFile(filename)
dsl := New(id)
err = jsoniter.Unmarshal(data, dsl)
if err != nil {
messages = append(messages, fmt.Sprintf("[%s] %s", id, err.Error()))
return
}
if dsl.Action == nil {
dsl.Action = &ActionDSL{}
}
dsl.Action.SetDefaultProcess()
if dsl.Layout == nil {
dsl.Layout = &LayoutDSL{
Header: &HeaderLayoutDSL{
Preset: &PresetHeaderDSL{},
Actions: []component.ActionDSL{},
},
}
}
if dsl.Fields == nil {
dsl.Fields = &FieldsDSL{}
}
// Bind model / store / table / ...
err = dsl.Bind()
err = LoadData(data, id, root)
if err != nil {
messages = append(messages, fmt.Sprintf("[%s] %s", id, err.Error()))
return
}
// Parse
err = dsl.Parse()
if err != nil {
messages = append(messages, fmt.Sprintf("[%s] %s", id, err.Error()))
return
}
// Validate
err = dsl.Validate()
if err != nil {
messages = append(messages, fmt.Sprintf("[%s] %s", id, err.Error()))
return
}
// Apply a language pack
if lang.Default != nil {
lang.Default.Apply(dsl)
}
Tables[id] = dsl
})
if len(messages) > 0 {
@ -176,6 +149,61 @@ func LoadFrom(dir string, prefix string) error {
return err
}
// LoadData load table from source
func LoadData(data []byte, id string, root string) error {
dsl := New(id)
dsl.Root = root
err := jsoniter.Unmarshal(data, dsl)
if err != nil {
return fmt.Errorf("[%s] %s", id, err.Error())
}
if dsl.Action == nil {
dsl.Action = &ActionDSL{}
}
dsl.Action.SetDefaultProcess()
if dsl.Layout == nil {
dsl.Layout = &LayoutDSL{
Header: &HeaderLayoutDSL{
Preset: &PresetHeaderDSL{},
Actions: []component.ActionDSL{},
},
}
}
if dsl.Fields == nil {
dsl.Fields = &FieldsDSL{}
}
// Bind model / store / table / ...
err = dsl.Bind()
if err != nil {
return fmt.Errorf("[%s] %s", id, err.Error())
}
// Parse
err = dsl.Parse()
if err != nil {
return fmt.Errorf("[%s] %s", id, err.Error())
}
// Validate
err = dsl.Validate()
if err != nil {
return fmt.Errorf("[%s] %s", id, err.Error())
}
// Apply a language pack
if lang.Default != nil {
lang.Default.Apply(dsl)
}
Tables[id] = dsl
return nil
}
// Get table via process or id
func Get(table interface{}) (*DSL, error) {
id := ""

View file

@ -1,6 +1,7 @@
package table
import (
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
@ -17,12 +18,19 @@ import (
func TestLoad(t *testing.T) {
prepare(t)
err := Load(config.Conf)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, 4, len(Tables))
assert.Equal(t, 5, len(Tables))
}
func TestLoadID(t *testing.T) {
prepare(t)
err := LoadID("pet", filepath.Join(config.Conf.Root, "tables"))
if err != nil {
t.Fatal(err)
}
}
func prepare(t *testing.T, language ...string) {

View file

@ -9,6 +9,7 @@ import (
// DSL the table DSL
type DSL struct {
Root string `json:"-"`
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Action *ActionDSL `json:"action"`
@ -67,6 +68,7 @@ type BindActionDSL struct {
Model string `json:"model,omitempty"` // bind model
Store string `json:"store,omitempty"` // bind store
Table string `json:"table,omitempty"` // bind table
Form string `json:"form,omitempty"` // bind form
Option map[string]interface{} `json:"option,omitempty"` // bind option
}

View file

@ -1,6 +1,9 @@
package widgets
import (
"fmt"
"strings"
"github.com/yaoapp/yao/config"
"github.com/yaoapp/yao/widgets/app"
"github.com/yaoapp/yao/widgets/chart"
@ -15,51 +18,58 @@ import (
// Load the widgets
func Load(cfg config.Config) error {
messages := []string{}
// load expression
err := expression.Export()
if err != nil {
return err
messages = append(messages, err.Error())
}
// load component
err = component.Export()
if err != nil {
return err
messages = append(messages, err.Error())
}
// load field transform
err = field.LoadAndExport(config.Conf)
if err != nil {
return err
messages = append(messages, err.Error())
}
// login widget
err = login.LoadAndExport(cfg)
if err != nil {
return err
messages = append(messages, err.Error())
}
// app widget
err = app.LoadAndExport(cfg)
if err != nil {
return err
messages = append(messages, err.Error())
}
// table widget
err = table.LoadAndExport(cfg)
if err != nil {
return err
messages = append(messages, err.Error())
}
// form widget
err = form.LoadAndExport(cfg)
if err != nil {
return err
messages = append(messages, err.Error())
}
// chart widget
err = chart.LoadAndExport(cfg)
if err != nil {
messages = append(messages, err.Error())
}
if len(messages) > 0 {
err = fmt.Errorf(strings.Join(messages, ";\n"))
return err
}