From 48d3ec8bfa8eecde2bc70d5c06d596c7dd8cbe8e Mon Sep 17 00:00:00 2001 From: Max Date: Fri, 7 Oct 2022 11:47:59 +0800 Subject: [PATCH] [add] widget table bind table support --- widgets/hook/hook.go | 14 +++++ widgets/table/action.go | 51 +++++++++++++++- widgets/table/bind.go | 58 +++++++++++++++--- widgets/table/fields.go | 30 +++++++++ widgets/table/layout.go | 24 +++++++- widgets/table/table.go | 118 ++++++++++++++++++++++-------------- widgets/table/table_test.go | 12 +++- widgets/table/types.go | 2 + widgets/widgets.go | 24 +++++--- 9 files changed, 270 insertions(+), 63 deletions(-) diff --git a/widgets/hook/hook.go b/widgets/hook/hook.go index fc9fb2d2..97d6055d 100644 --- a/widgets/hook/hook.go +++ b/widgets/hook/hook.go @@ -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) { diff --git a/widgets/table/action.go b/widgets/table/action.go index fafdbec7..44303fad 100644 --- a/widgets/table/action.go +++ b/widgets/table/action.go @@ -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) { diff --git a/widgets/table/bind.go b/widgets/table/bind.go index af4f644d..ddb555a6 100644 --- a/widgets/table/bind.go +++ b/widgets/table/bind.go @@ -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) -} diff --git a/widgets/table/fields.go b/widgets/table/fields.go index 17433123..f2464910 100644 --- a/widgets/table/fields.go +++ b/widgets/table/fields.go @@ -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{}{} diff --git a/widgets/table/layout.go b/widgets/table/layout.go index 8bcdb9a4..a9bba15a 100644 --- a/widgets/table/layout.go +++ b/widgets/table/layout.go @@ -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 diff --git a/widgets/table/table.go b/widgets/table/table.go index 5bf9d88d..d6a6f89f 100644 --- a/widgets/table/table.go +++ b/widgets/table/table.go @@ -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 := "" diff --git a/widgets/table/table_test.go b/widgets/table/table_test.go index 793b7a1f..fb90ee40 100644 --- a/widgets/table/table_test.go +++ b/widgets/table/table_test.go @@ -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) { diff --git a/widgets/table/types.go b/widgets/table/types.go index 678c2caa..28d05ddf 100644 --- a/widgets/table/types.go +++ b/widgets/table/types.go @@ -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 } diff --git a/widgets/widgets.go b/widgets/widgets.go index 0164beea..783d04de 100644 --- a/widgets/widgets.go +++ b/widgets/widgets.go @@ -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 }