From 7fa01c437ccd16b48a2e5f82e8a56b1268a7bf82 Mon Sep 17 00:00:00 2001 From: ZhengYang Date: Tue, 5 Aug 2014 14:31:19 +0800 Subject: [PATCH 1/8] addAll now supports: filter(query), fields, sortby, order, limit, offset --- g_models.go | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 90 insertions(+), 5 deletions(-) diff --git a/g_models.go b/g_models.go index ee1b04c..bf09d88 100644 --- a/g_models.go +++ b/g_models.go @@ -626,11 +626,55 @@ func Get{{modelName}}ById(id int) (v *{{modelName}}, err error) { // GetAll{{modelName}} retrieves all {{modelName}} matches certain condition. Returns empty list if // no records exist -func GetAll{{modelName}}() (l []{{modelName}}, err error) { +func GetAll{{modelName}}(query map[string]string, fields []string, sortby []string, order []string, + offset int64, limit int64) (l []{{modelName}}, err error) { o := orm.NewOrm() - t := new({{modelName}}) - qs := o.QueryTable(t) - if _, err := qs.All(&l); err == nil { + qs := o.QueryTable(new({{modelName}})) + // query k=v + for k, v := range query { + qs = qs.Filter(k, v) + } + // order by: + var sortFields []string + if len(sortby) != 0 { + if len(sortby) == len(order) { + // 1) for each sort field, there is an associated order + for i, v := range sortby { + orderby := "" + if order[i] == "desc" { + orderby = "-" + v + } else if order[i] == "asc" { + orderby = v + } else { + return nil, errors.New("Error: Invalid order. Must be either [asc|desc]") + } + sortFields = append(sortFields, orderby) + } + qs = qs.OrderBy(sortFields...) + } else if len(sortby) != len(order) && len(order) == 1 { + // 2) there is exactly one order, all the sorted fields will be sorted by this order + for _, v := range sortby { + orderby := "" + if order[0] == "desc" { + orderby = "-" + v + } else if order[0] == "asc" { + orderby = v + } else { + return nil, errors.New("Error: Invalid order. Must be either [asc|desc]") + } + sortFields = append(sortFields, orderby) + } + } else if len(sortby) != len(order) && len(order) != 1 { + return nil, errors.New("Error: 'sortby', 'order' sizes mismatch or 'order' size is not 1") + } + } else { + if len(order) != 0 { + return nil, errors.New("Error: unused 'order' fields") + } + } + + qs = qs.OrderBy(sortFields...) + if _, err := qs.Limit(limit, offset).All(&l, fields...); err == nil { return l, nil } return nil, err @@ -715,7 +759,48 @@ func (this *{{ctrlName}}Controller) GetOne() { // @Failure 403 // @router / [get] func (this *{{ctrlName}}Controller) GetAll() { - l, err := models.GetAll{{ctrlName}}() + var fields []string + var sortby []string + var order []string + var query map[string]string = make(map[string]string) + var limit int64 = 10 + var offset int64 = 0 + + // fields: col1,col2,entity.col3 + if v := this.GetString("fields"); v != "" { + fields = strings.Split(v, ",") + } + // limit: 10 (default is 10) + if v, err := this.GetInt("limit"); err == nil { + limit = v + } + // offset: 0 (default is 0) + if v, err := this.GetInt("offset"); err == nil { + offset = v + } + // sortby: col1,col2 + if v := this.GetString("sortby"); v != "" { + sortby = strings.Split(v, ",") + } + // order: desc,asc + if v := this.GetString("order"); v != "" { + order = strings.Split(v, ",") + } + // query: k:v,k:v + if v := this.GetString("query"); v != "" { + for _, cond := range strings.Split(v, ",") { + kv := strings.Split(cond, ":") + if len(kv) != 2 { + this.Data["json"] = errors.New("Error: invalid query key/value pair") + this.ServeJson() + return + } + k, v := kv[0], kv[1] + query[k] = v + } + } + + l, err := models.GetAll{{ctrlName}}(query, fields, sortby, order, offset, limit) if err != nil { this.Data["json"] = err.Error() } else { From 932e73a9a2ebae934d155602419bc08d35b337b0 Mon Sep 17 00:00:00 2001 From: ZhengYang Date: Tue, 5 Aug 2014 14:53:27 +0800 Subject: [PATCH 2/8] added doc for GetAll template --- g_models.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/g_models.go b/g_models.go index bf09d88..7119b09 100644 --- a/g_models.go +++ b/g_models.go @@ -754,7 +754,12 @@ func (this *{{ctrlName}}Controller) GetOne() { // @Title Get All // @Description get {{ctrlName}} -// @Param id path string true "get all records matches certain condition" +// @Param query query string false "Filter. e.g. col1:v1,col2:v2 ..." +// @Param fields query string false "Fields returned. e.g. col1,col2 ..." +// @Param sortby query string false "Sorted-by fields. e.g. col1,col2 ..." +// @Param order query string false "Order corresponding to each sortby field, if single value, apply to all sortby fields. e.g. desc,asc ..." +// @Param limit query string false "Limit the size of result set. Must be an integer" +// @Param offset query string false "Start position of result set. Must be an integer" // @Success 200 {object} models.{{ctrlName}} // @Failure 403 // @router / [get] From 337bd38b73734c585f0da631edeb227e0bbab4ac Mon Sep 17 00:00:00 2001 From: ZhengYang Date: Tue, 5 Aug 2014 15:04:51 +0800 Subject: [PATCH 3/8] minor cosmetic changes --- g_models.go | 1 + 1 file changed, 1 insertion(+) diff --git a/g_models.go b/g_models.go index 7119b09..15abb34 100644 --- a/g_models.go +++ b/g_models.go @@ -873,6 +873,7 @@ func init() { &controllers.ObjectController{}, ), ), + beego.NSNamespace("/user", beego.NSInclude( &controllers.UserController{}, From 06f2e2cca9a6ffb8e16c4d7c3c50b29dd25a29c9 Mon Sep 17 00:00:00 2001 From: ZhengYang Date: Tue, 5 Aug 2014 15:27:05 +0800 Subject: [PATCH 4/8] allow dot notation in query field --- g_models.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/g_models.go b/g_models.go index 15abb34..843166d 100644 --- a/g_models.go +++ b/g_models.go @@ -632,6 +632,8 @@ func GetAll{{modelName}}(query map[string]string, fields []string, sortby []stri qs := o.QueryTable(new({{modelName}})) // query k=v for k, v := range query { + // rewrite dot-notation to Object__Attribute + k = strings.Replace(k, ".", "__", -1) qs = qs.Filter(k, v) } // order by: From d02a552a59634d239436f472c980b463d132728f Mon Sep 17 00:00:00 2001 From: ZhengYang Date: Tue, 5 Aug 2014 16:13:40 +0800 Subject: [PATCH 5/8] fix doc format bug, use only 1 tab in between fields --- g_models.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/g_models.go b/g_models.go index 843166d..ed04bd6 100644 --- a/g_models.go +++ b/g_models.go @@ -756,12 +756,12 @@ func (this *{{ctrlName}}Controller) GetOne() { // @Title Get All // @Description get {{ctrlName}} -// @Param query query string false "Filter. e.g. col1:v1,col2:v2 ..." -// @Param fields query string false "Fields returned. e.g. col1,col2 ..." -// @Param sortby query string false "Sorted-by fields. e.g. col1,col2 ..." -// @Param order query string false "Order corresponding to each sortby field, if single value, apply to all sortby fields. e.g. desc,asc ..." -// @Param limit query string false "Limit the size of result set. Must be an integer" -// @Param offset query string false "Start position of result set. Must be an integer" +// @Param query query string false "Filter. e.g. col1:v1,col2:v2 ..." +// @Param fields query string false "Fields returned. e.g. col1,col2 ..." +// @Param sortby query string false "Sorted-by fields. e.g. col1,col2 ..." +// @Param order query string false "Order corresponding to each sortby field, if single value, apply to all sortby fields. e.g. desc,asc ..." +// @Param limit query string false "Limit the size of result set. Must be an integer" +// @Param offset query string false "Start position of result set. Must be an integer" // @Success 200 {object} models.{{ctrlName}} // @Failure 403 // @router / [get] From b057b16a8016dccb50dd4076d7861f34a5ae3574 Mon Sep 17 00:00:00 2001 From: ZhengYang Date: Tue, 5 Aug 2014 17:49:36 +0800 Subject: [PATCH 6/8] trim unused fields in result json --- g_models.go | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/g_models.go b/g_models.go index ed04bd6..4d0c70d 100644 --- a/g_models.go +++ b/g_models.go @@ -627,7 +627,7 @@ func Get{{modelName}}ById(id int) (v *{{modelName}}, err error) { // GetAll{{modelName}} retrieves all {{modelName}} matches certain condition. Returns empty list if // no records exist func GetAll{{modelName}}(query map[string]string, fields []string, sortby []string, order []string, - offset int64, limit int64) (l []{{modelName}}, err error) { + offset int64, limit int64) (ml []interface{}, err error) { o := orm.NewOrm() qs := o.QueryTable(new({{modelName}})) // query k=v @@ -675,9 +675,26 @@ func GetAll{{modelName}}(query map[string]string, fields []string, sortby []stri } } + var l []{{modelName}} qs = qs.OrderBy(sortFields...) if _, err := qs.Limit(limit, offset).All(&l, fields...); err == nil { - return l, nil + // trim unused fields + fieldMap := make(map[string]interface{}) + for _, v := range fields { + fieldMap[v] = true + } + for _, v := range l { + s := reflect.Indirect(reflect.ValueOf(v)) + typeOfS := s.Type() + for i := 0; i < s.NumField(); i++ { + f := s.Field(i) + if _, ok := fieldMap[typeOfS.Field(i).Name]; ok { + fieldMap[typeOfS.Field(i).Name] = f.Interface() + } + } + } + ml = append(ml, fieldMap) + return ml, nil } return nil, err } From 6a7428b3aa37d65e57a95530cb02c73478b7396a Mon Sep 17 00:00:00 2001 From: ZhengYang Date: Wed, 6 Aug 2014 10:26:54 +0800 Subject: [PATCH 7/8] when field list is empty, no need to reflect --- g_models.go | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/g_models.go b/g_models.go index 4d0c70d..a221899 100644 --- a/g_models.go +++ b/g_models.go @@ -678,22 +678,29 @@ func GetAll{{modelName}}(query map[string]string, fields []string, sortby []stri var l []{{modelName}} qs = qs.OrderBy(sortFields...) if _, err := qs.Limit(limit, offset).All(&l, fields...); err == nil { - // trim unused fields - fieldMap := make(map[string]interface{}) - for _, v := range fields { - fieldMap[v] = true - } - for _, v := range l { - s := reflect.Indirect(reflect.ValueOf(v)) - typeOfS := s.Type() - for i := 0; i < s.NumField(); i++ { - f := s.Field(i) - if _, ok := fieldMap[typeOfS.Field(i).Name]; ok { - fieldMap[typeOfS.Field(i).Name] = f.Interface() + if len(fields) == 0 { + for _, v := range l { + ml = append(ml, v) + } + } else { + // trim unused fields + fieldMap := make(map[string]interface{}) + for _, v := range fields { + fieldMap[v] = true + } + for _, v := range l { + m := make(map[string]interface{}) + s := reflect.Indirect(reflect.ValueOf(v)) + typeOfS := s.Type() + for i := 0; i < s.NumField(); i++ { + f := s.Field(i) + if _, ok := fieldMap[typeOfS.Field(i).Name]; ok { + m[typeOfS.Field(i).Name] = f.Interface() + } } + ml = append(ml, m) } } - ml = append(ml, fieldMap) return ml, nil } return nil, err From f879d728c8fc14ac4e9341161352763d21c1b968 Mon Sep 17 00:00:00 2001 From: ZhengYang Date: Wed, 6 Aug 2014 10:49:26 +0800 Subject: [PATCH 8/8] refactor reflection template for models --- g_models.go | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/g_models.go b/g_models.go index a221899..f7f4a79 100644 --- a/g_models.go +++ b/g_models.go @@ -684,19 +684,11 @@ func GetAll{{modelName}}(query map[string]string, fields []string, sortby []stri } } else { // trim unused fields - fieldMap := make(map[string]interface{}) - for _, v := range fields { - fieldMap[v] = true - } for _, v := range l { m := make(map[string]interface{}) - s := reflect.Indirect(reflect.ValueOf(v)) - typeOfS := s.Type() - for i := 0; i < s.NumField(); i++ { - f := s.Field(i) - if _, ok := fieldMap[typeOfS.Field(i).Name]; ok { - m[typeOfS.Field(i).Name] = f.Interface() - } + val := reflect.ValueOf(v) + for _, fname := range fields { + m[fname] = val.FieldByName(fname).Interface() } ml = append(ml, m) }