From 364452f3bb40929c696af171590f6f99caf9fc02 Mon Sep 17 00:00:00 2001 From: John Date: Mon, 16 Dec 2019 20:50:27 +0800 Subject: [PATCH] improve gdb.Model --- .../frame/mvc/app/model/article/article.go | 3 + .../mvc/app/model/article/article_entity.go | 65 ++++ .../mvc/app/model/article/article_model.go | 321 ++++++++++++++++++ .example/frame/mvc/main.go | 9 +- .example/other/test.go | 7 +- database/gdb/gdb_func.go | 51 ++- database/gdb/gdb_model.go | 115 +++++-- 7 files changed, 535 insertions(+), 36 deletions(-) create mode 100644 .example/frame/mvc/app/model/article/article.go create mode 100644 .example/frame/mvc/app/model/article/article_entity.go create mode 100644 .example/frame/mvc/app/model/article/article_model.go diff --git a/.example/frame/mvc/app/model/article/article.go b/.example/frame/mvc/app/model/article/article.go new file mode 100644 index 000000000..ea00311c4 --- /dev/null +++ b/.example/frame/mvc/app/model/article/article.go @@ -0,0 +1,3 @@ +package article + +// Fill with you ideas below. \ No newline at end of file diff --git a/.example/frame/mvc/app/model/article/article_entity.go b/.example/frame/mvc/app/model/article/article_entity.go new file mode 100644 index 000000000..8b302e6e8 --- /dev/null +++ b/.example/frame/mvc/app/model/article/article_entity.go @@ -0,0 +1,65 @@ +// ========================================================================== +// This is auto-generated by gf cli tool. You may not really want to edit it. +// ========================================================================== + +package article + +import ( + "database/sql" + "github.com/gogf/gf/database/gdb" + "github.com/gogf/gf/os/gtime" +) + +// Entity is the golang structure for table gf_article. +type Entity struct { + Id int `orm:"id,primary" json:"id"` // + CatId int `orm:"cat_id" json:"cat_id"` // 分类ID + Uid int `orm:"uid" json:"uid"` // 用户ID + Title string `orm:"title" json:"title"` // 标题 + Content string `orm:"content" json:"content"` // 内容 + Order int `orm:"order" json:"order"` // 排序 + Brief string `orm:"brief" json:"brief"` // 摘要 + Thumb string `orm:"thumb" json:"thumb"` // 缩略图 + Tags string `orm:"tags" json:"tags"` // 标签 + Referer string `orm:"referer" json:"referer"` // 内容来源 + Status int `orm:"status" json:"status"` // 状态\n0: 禁用\n1: 正常 + CreateTime *gtime.Time `orm:"create_time" json:"create_time"` // 创建时间 + UpdateTime *gtime.Time `orm:"update_time" json:"update_time"` // 修改时间 +} + +// OmitEmpty sets OPTION_OMITEMPTY option for the model, which automatically filers +// the data and where attributes for empty values. +func (r *Entity) OmitEmpty() *arModel { + return Model.Data(r).OmitEmpty() +} + +// Inserts does "INSERT...INTO..." statement for inserting current object into table. +func (r *Entity) Insert() (result sql.Result, err error) { + return Model.Data(r).Insert() +} + +// Replace does "REPLACE...INTO..." statement for inserting current object into table. +// If there's already another same record in the table (it checks using primary key or unique index), +// it deletes it and insert this one. +func (r *Entity) Replace() (result sql.Result, err error) { + return Model.Data(r).Replace() +} + +// Save does "INSERT...INTO..." statement for inserting/updating current object into table. +// It updates the record if there's already another same record in the table +// (it checks using primary key or unique index). +func (r *Entity) Save() (result sql.Result, err error) { + return Model.Data(r).Save() +} + +// Update does "UPDATE...WHERE..." statement for updating current object from table. +// It updates the record if there's already another same record in the table +// (it checks using primary key or unique index). +func (r *Entity) Update() (result sql.Result, err error) { + return Model.Data(r).Where(gdb.GetWhereConditionOfStruct(r)).Update() +} + +// Delete does "DELETE FROM...WHERE..." statement for deleting current object from table. +func (r *Entity) Delete() (result sql.Result, err error) { + return Model.Where(gdb.GetWhereConditionOfStruct(r)).Delete() +} diff --git a/.example/frame/mvc/app/model/article/article_model.go b/.example/frame/mvc/app/model/article/article_model.go new file mode 100644 index 000000000..04398997f --- /dev/null +++ b/.example/frame/mvc/app/model/article/article_model.go @@ -0,0 +1,321 @@ +// ========================================================================== +// This is auto-generated by gf cli tool. You may not really want to edit it. +// ========================================================================== + +package article + +import ( + "database/sql" + "github.com/gogf/gf/database/gdb" + "github.com/gogf/gf/frame/g" + "time" +) + +// arModel is a active record design model for table gf_article operations. +type arModel struct { + M *gdb.Model +} + +var ( + // Table is the table name of gf_article. + Table = "gf_article" + // Model is the model object of gf_article. + Model = &arModel{g.DB("default").Table(Table).Safe()} + // Primary is the primary field name of table gf_article. + Primary = gdb.GetPrimaryKey(new(Entity)) +) + +// FindOne retrieves and returns a single Entity by a primary key or where conditions by +// Model.Where. +func FindOne(where ...interface{}) (*Entity, error) { + return Model.One(gdb.GetPrimaryKeyCondition(Primary, where...)...) +} + +// FindAll retrieves and returns multiple Entity by a primary key or where conditions by +// Model.Where. +func FindAll(where ...interface{}) ([]*Entity, error) { + return Model.All(gdb.GetPrimaryKeyCondition(Primary, where...)...) +} + +// FindValue retrieves and returns single field value by a primary key or where conditions by +// Model.Where. +func FindValue(fieldsAndWhere ...interface{}) (gdb.Value, error) { + if len(fieldsAndWhere) == 2 { + return Model.Value(append(fieldsAndWhere[0:1], gdb.GetPrimaryKeyCondition(Primary, fieldsAndWhere[1:]...)...)...) + } + return Model.Value(fieldsAndWhere...) +} + +// Insert is alias of Model.Insert. +func Insert(data ...interface{}) (result sql.Result, err error) { + return Model.Insert(data...) +} + +// Replace is alias of Model.Replace. +func Replace(data ...interface{}) (result sql.Result, err error) { + return Model.Replace(data...) +} + +// Save is alias of Model.Save. +func Save(data ...interface{}) (result sql.Result, err error) { + return Model.Save(data...) +} + +// Update is alias of Model.Update. +func Update(dataAndWhere ...interface{}) (result sql.Result, err error) { + return Model.Update(dataAndWhere...) +} + +// Delete is alias of Model.Delete. +func Delete(where ...interface{}) (result sql.Result, err error) { + return Model.Delete(where...) +} + +// TX sets the transaction for current operation. +func (m *arModel) TX(tx *gdb.TX) *arModel { + return &arModel{m.M.TX(tx)} +} + +// Master marks the following operation on master node. +func (m *arModel) Master() *arModel { + return &arModel{m.M.Master()} +} + +// Slave marks the following operation on slave node. +// Note that it makes sense only if there's any slave node configured. +func (m *arModel) Slave() *arModel { + return &arModel{m.M.Slave()} +} + +// LeftJoin does "LEFT JOIN ... ON ..." statement on the model. +func (m *arModel) LeftJoin(joinTable string, on string) *arModel { + return &arModel{m.M.LeftJoin(joinTable, on)} +} + +// RightJoin does "RIGHT JOIN ... ON ..." statement on the model. +func (m *arModel) RightJoin(joinTable string, on string) *arModel { + return &arModel{m.M.RightJoin(joinTable, on)} +} + +// InnerJoin does "INNER JOIN ... ON ..." statement on the model. +func (m *arModel) InnerJoin(joinTable string, on string) *arModel { + return &arModel{m.M.InnerJoin(joinTable, on)} +} + +// Fields sets the operation fields of the model, multiple fields joined using char ','. +func (m *arModel) Fields(fields string) *arModel { + return &arModel{m.M.Fields(fields)} +} + +// FieldsEx sets the excluded operation fields of the model, multiple fields joined using char ','. +func (m *arModel) FieldsEx(fields string) *arModel { + return &arModel{m.M.FieldsEx(fields)} +} + +// Option sets the extra operation option for the model. +func (m *arModel) Option(option int) *arModel { + return &arModel{m.M.Option(option)} +} + +// OmitEmpty sets OPTION_OMITEMPTY option for the model, which automatically filers +// the data and where attributes for empty values. +func (m *arModel) OmitEmpty() *arModel { + return &arModel{m.M.OmitEmpty()} +} + +// Filter marks filtering the fields which does not exist in the fields of the operated table. +func (m *arModel) Filter() *arModel { + return &arModel{m.M.Filter()} +} + +// Where sets the condition statement for the model. The parameter can be type of +// string/map/gmap/slice/struct/*struct, etc. Note that, if it's called more than one times, +// multiple conditions will be joined into where statement using "AND". +// Eg: +// Where("uid=10000") +// Where("uid", 10000) +// Where("money>? AND name like ?", 99999, "vip_%") +// Where("uid", 1).Where("name", "john") +// Where("status IN (?)", g.Slice{1,2,3}) +// Where("age IN(?,?)", 18, 50) +// Where(User{ Id : 1, UserName : "john"}) +func (m *arModel) Where(where interface{}, args ...interface{}) *arModel { + return &arModel{m.M.Where(where, args...)} +} + +// And adds "AND" condition to the where statement. +func (m *arModel) And(where interface{}, args ...interface{}) *arModel { + return &arModel{m.M.And(where, args...)} +} + +// Or adds "OR" condition to the where statement. +func (m *arModel) Or(where interface{}, args ...interface{}) *arModel { + return &arModel{m.M.Or(where, args...)} +} + +// GroupBy sets the "GROUP BY" statement for the model. +func (m *arModel) GroupBy(groupBy string) *arModel { + return &arModel{m.M.GroupBy(groupBy)} +} + +// OrderBy sets the "ORDER BY" statement for the model. +func (m *arModel) OrderBy(orderBy string) *arModel { + return &arModel{m.M.OrderBy(orderBy)} +} + +// Limit sets the "LIMIT" statement for the model. +// The parameter can be either one or two number, if passed two number is passed, +// it then sets "LIMIT limit[0],limit[1]" statement for the model, or else it sets "LIMIT limit[0]" +// statement. +func (m *arModel) Limit(limit ...int) *arModel { + return &arModel{m.M.Limit(limit...)} +} + +// Offset sets the "OFFSET" statement for the model. +// It only makes sense for some databases like SQLServer, PostgreSQL, etc. +func (m *arModel) Offset(offset int) *arModel { + return &arModel{m.M.Offset(offset)} +} + +// ForPage sets the paging number for the model. +// The parameter is started from 1 for paging. +// Note that, it differs that the Limit function start from 0 for "LIMIT" statement. +func (m *arModel) ForPage(page, limit int) *arModel { + return &arModel{m.M.ForPage(page, limit)} +} + +// Batch sets the batch operation number for the model. +func (m *arModel) Batch(batch int) *arModel { + return &arModel{m.M.Batch(batch)} +} + +// Cache sets the cache feature for the model. It caches the result of the sql, which means +// if there's another same sql request, it just reads and returns the result from cache, it +// but not committed and executed into the database. +// +// If the parameter < 0, which means it clear the cache with given . +// If the parameter = 0, which means it never expires. +// If the parameter > 0, which means it expires after . +// +// The optional parameter is used to bind a name to the cache, which means you can later +// control the cache like changing the or clearing the cache with specified . +// +// Note that, the cache feature is disabled if the model is operating on a transaction. +func (m *arModel) Cache(expire time.Duration, name ...string) *arModel { + return &arModel{m.M.Cache(expire, name...)} +} + +// Data sets the operation data for the model. +// The parameter can be type of string/map/gmap/slice/struct/*struct, etc. +// Eg: +// Data("uid=10000") +// Data("uid", 10000) +// Data(g.Map{"uid": 10000, "name":"john"}) +// Data(g.Slice{g.Map{"uid": 10000, "name":"john"}, g.Map{"uid": 20000, "name":"smith"}) +func (m *arModel) Data(data ...interface{}) *arModel { + return &arModel{m.M.Data(data...)} +} + +// Insert does "INSERT INTO ..." statement for the model. +// The optional parameter is the same as the parameter of Model.Data function, +// see Model.Data. +func (m *arModel) Insert(data ...interface{}) (result sql.Result, err error) { + return m.M.Insert(data...) +} + +// Replace does "REPLACE INTO ..." statement for the model. +// The optional parameter is the same as the parameter of Model.Data function, +// see Model.Data. +func (m *arModel) Replace(data ...interface{}) (result sql.Result, err error) { + return m.M.Replace(data...) +} + +// Save does "INSERT INTO ... ON DUPLICATE KEY UPDATE..." statement for the model. +// It updates the record if there's primary or unique index in the saving data, +// or else it inserts a new record into the table. +// +// The optional parameter is the same as the parameter of Model.Data function, +// see Model.Data. +func (m *arModel) Save(data ...interface{}) (result sql.Result, err error) { + return m.M.Save(data...) +} + +// Update does "UPDATE ... " statement for the model. +// +// If the optional parameter is given, the dataAndWhere[0] is the updated +// data field, and dataAndWhere[1:] is treated as where condition fields. +// Also see Model.Data and Model.Where functions. +func (m *arModel) Update(dataAndWhere ...interface{}) (result sql.Result, err error) { + return m.M.Update(dataAndWhere...) +} + +// Delete does "DELETE FROM ... " statement for the model. +// The optional parameter is the same as the parameter of Model.Where function, +// see Model.Where. +func (m *arModel) Delete(where ...interface{}) (result sql.Result, err error) { + return m.M.Delete(where...) +} + +// Count does "SELECT COUNT(x) FROM ..." statement for the model. +// The optional parameter is the same as the parameter of Model.Where function, +// see Model.Where. +func (m *arModel) Count(where ...interface{}) (int, error) { + return m.M.Count(where...) +} + +// All does "SELECT FROM ..." statement for the model. +// It retrieves the records from table and returns the result as []*Entity. +// It returns nil if there's no record retrieved with the given conditions from table. +// +// The optional parameter is the same as the parameter of Model.Where function, +// see Model.Where. +func (m *arModel) All(where ...interface{}) ([]*Entity, error) { + all, err := m.M.All(where...) + if err != nil { + return nil, err + } + var entities []*Entity + if err = all.Structs(&entities); err != nil && err != sql.ErrNoRows { + return nil, err + } + return entities, nil +} + +// One retrieves one record from table and returns the result as *Entity. +// It returns nil if there's no record retrieved with the given conditions from table. +// +// The optional parameter is the same as the parameter of Model.Where function, +// see Model.Where. +func (m *arModel) One(where ...interface{}) (*Entity, error) { + one, err := m.M.One(where...) + if err != nil { + return nil, err + } + var entity *Entity + if err = one.Struct(&entity); err != nil && err != sql.ErrNoRows { + return nil, err + } + return entity, nil +} + +// Value retrieves a specified record value from table and returns the result as interface type. +// It returns nil if there's no record found with the given conditions from table. +// +// If the optional parameter is given, the fieldsAndWhere[0] is the selected fields +// and fieldsAndWhere[1:] is treated as where condition fields. +// Also see Model.Fields and Model.Where functions. +func (m *arModel) Value(fieldsAndWhere ...interface{}) (gdb.Value, error) { + return m.M.Value(fieldsAndWhere...) +} + +// Chunk iterates the table with given size and callback function. +func (m *arModel) Chunk(limit int, callback func(entities []*Entity, err error) bool) { + m.M.Chunk(limit, func(result gdb.Result, err error) bool { + var entities []*Entity + err = result.Structs(&entities) + if err == sql.ErrNoRows { + return false + } + return callback(entities, err) + }) +} diff --git a/.example/frame/mvc/main.go b/.example/frame/mvc/main.go index d02b76620..47139cd17 100644 --- a/.example/frame/mvc/main.go +++ b/.example/frame/mvc/main.go @@ -1,13 +1,10 @@ package main import ( - "fmt" - "github.com/gogf/gf/.example/frame/mvc/app/model/defaults" - "github.com/gogf/gf/database/gdb" + "github.com/gogf/gf/.example/frame/mvc/app/model/article" ) func main() { - u := defaults.User{Id: 1, Nickname: "test"} - fmt.Println(gdb.GetWhereConditionOfStruct(&u)) - fmt.Println(u.Replace()) + m := article.Model + m.All() } diff --git a/.example/other/test.go b/.example/other/test.go index 96a2c7be2..92339853b 100644 --- a/.example/other/test.go +++ b/.example/other/test.go @@ -1,13 +1,10 @@ package main import ( - "fmt" - "github.com/gogf/gf/debug/gdebug" + "github.com/gogf/gf/.example/frame/mvc/app/model/article" "github.com/gogf/gf/frame/g" - "os" ) func main() { - g.Dump(os.Args) - fmt.Println(gdebug.BuildInfo()) + g.Dump(article.FindAll(g.Slice{2, 3})) } diff --git a/database/gdb/gdb_func.go b/database/gdb/gdb_func.go index 77efaca8b..fdaddbbab 100644 --- a/database/gdb/gdb_func.go +++ b/database/gdb/gdb_func.go @@ -78,7 +78,7 @@ func doQuoteString(s, charLeft, charRight string) string { return gstr.Join(array1, ",") } -// addTablePrefix adds prefix string to the table. It handles strings like: +// addTablePrefix adds prefix string to the table. It handles table string like: // "user", "user u", "user,user_detail", "user u, user_detail ut", "user as u, user_detail as ut". // // Note that, this should be used before any quoting function calls. @@ -95,7 +95,8 @@ func addTablePrefix(table, prefix string) string { return gstr.Join(array1, ",") } -// 获得struct对象对应的where查询条件 +// GetWhereConditionOfStruct returns the where condition sql and arguments by given struct pointer. +// This function automatically retrieves primary or unique field and its attribute value as condition. func GetWhereConditionOfStruct(pointer interface{}) (where string, args []interface{}) { array := ([]string)(nil) for _, field := range structs.TagFields(pointer, []string{ORM_TAG_FOR_STRUCT}, true) { @@ -112,6 +113,51 @@ func GetWhereConditionOfStruct(pointer interface{}) (where string, args []interf return } +// GetPrimaryKey retrieves and returns primary key field name from given struct. +func GetPrimaryKey(pointer interface{}) string { + array := ([]string)(nil) + for _, field := range structs.TagFields(pointer, []string{ORM_TAG_FOR_STRUCT}, true) { + array = strings.Split(field.Tag, ",") + if len(array) > 1 && array[1] == ORM_TAG_FOR_PRIMARY { + return array[0] + } + } + return "" +} + +// GetPrimaryKeyCondition returns a new where condition by primary field name. +// The parameter is like as follows: +// 123, []int{1,2,3}, "john", []string{"john","smith"} +// +// Note that it returns the given parameter directly if there's the is empty. +func GetPrimaryKeyCondition(primary string, where ...interface{}) (newWhereCondition []interface{}) { + if len(where) == 0 { + return nil + } + if primary == "" { + return where + } + if len(where) == 1 { + rv := reflect.ValueOf(where[0]) + kind := rv.Kind() + if kind == reflect.Ptr { + rv = rv.Elem() + kind = rv.Kind() + } + switch kind { + case reflect.Map, reflect.Struct: + break + + default: + return []interface{}{map[string]interface{}{ + primary: where[0], + }} + } + } + return where + +} + // 获得orm标签与属性的映射关系 func GetOrmMappingOfStruct(pointer interface{}) map[string]string { mapping := make(map[string]string) @@ -163,7 +209,6 @@ func formatWhere(db DB, where interface{}, args []interface{}, omitEmpty bool) ( }) break } - // TODO garray support. for key, value := range varToMapDeep(where) { if omitEmpty && empty.IsEmpty(value) { continue diff --git a/database/gdb/gdb_model.go b/database/gdb/gdb_model.go index 0c5101140..56cf0a8dd 100644 --- a/database/gdb/gdb_model.go +++ b/database/gdb/gdb_model.go @@ -484,7 +484,12 @@ func (m *Model) doFilterDataMapForInsertOrUpdate(data Map, allowOmitEmpty bool) } // Insert does "INSERT INTO ..." statement for the model. -func (m *Model) Insert() (result sql.Result, err error) { +// The optional parameter is the same as the parameter of Model.Data function, +// see Model.Data. +func (m *Model) Insert(data ...interface{}) (result sql.Result, err error) { + if len(data) > 0 { + return m.Data(data...).Insert() + } defer func() { if err == nil { m.checkAndRemoveCache() @@ -520,7 +525,12 @@ func (m *Model) Insert() (result sql.Result, err error) { } // Replace does "REPLACE INTO ..." statement for the model. -func (m *Model) Replace() (result sql.Result, err error) { +// The optional parameter is the same as the parameter of Model.Data function, +// see Model.Data. +func (m *Model) Replace(data ...interface{}) (result sql.Result, err error) { + if len(data) > 0 { + return m.Data(data...).Replace() + } defer func() { if err == nil { m.checkAndRemoveCache() @@ -555,9 +565,15 @@ func (m *Model) Replace() (result sql.Result, err error) { } // Save does "INSERT INTO ... ON DUPLICATE KEY UPDATE..." statement for the model. +// The optional parameter is the same as the parameter of Model.Data function, +// see Model.Data. +// // It updates the record if there's primary or unique index in the saving data, // or else it inserts a new record into the table. -func (m *Model) Save() (result sql.Result, err error) { +func (m *Model) Save(data ...interface{}) (result sql.Result, err error) { + if len(data) > 0 { + return m.Data(data...).Save() + } defer func() { if err == nil { m.checkAndRemoveCache() @@ -592,7 +608,20 @@ func (m *Model) Save() (result sql.Result, err error) { } // Update does "UPDATE ... " statement for the model. -func (m *Model) Update() (result sql.Result, err error) { +// +// If the optional parameter is given, the dataAndWhere[0] is the updated data field, +// and dataAndWhere[1:] is treated as where condition fields. +// Also see Model.Data and Model.Where functions. +func (m *Model) Update(dataAndWhere ...interface{}) (result sql.Result, err error) { + if len(dataAndWhere) > 0 { + if len(dataAndWhere) > 2 { + return m.Data(dataAndWhere[0]).Where(dataAndWhere[1], dataAndWhere[2:]...).Update() + } else if len(dataAndWhere) == 2 { + return m.Data(dataAndWhere[0]).Where(dataAndWhere[1]).Update() + } else { + return m.Data(dataAndWhere[0]).Update() + } + } defer func() { if err == nil { m.checkAndRemoveCache() @@ -612,7 +641,12 @@ func (m *Model) Update() (result sql.Result, err error) { } // Delete does "DELETE FROM ... " statement for the model. -func (m *Model) Delete() (result sql.Result, err error) { +// The optional parameter is the same as the parameter of Model.Where function, +// see Model.Where. +func (m *Model) Delete(where ...interface{}) (result sql.Result, err error) { + if len(where) > 0 { + return m.Where(where[0], where[1:]...).Delete() + } defer func() { if err == nil { m.checkAndRemoveCache() @@ -622,24 +656,34 @@ func (m *Model) Delete() (result sql.Result, err error) { return m.db.doDelete(m.getLink(), m.tables, condition, conditionArgs...) } -// Select is alias of All. -// See All. -func (m *Model) Select() (Result, error) { - return m.All() +// Select is alias of Model.All. +// See Model.All. +// Deprecated. +func (m *Model) Select(where ...interface{}) (Result, error) { + return m.All(where...) } // All does "SELECT FROM ..." statement for the model. // It retrieves the records from table and returns the result as slice type. // It returns nil if there's no record retrieved with the given conditions from table. -func (m *Model) All() (Result, error) { +// +// The optional parameter is the same as the parameter of Model.Where function, +// see Model.Where. +func (m *Model) All(where ...interface{}) (Result, error) { + if len(where) > 0 { + return m.Where(where[0], where[1:]...).All() + } condition, conditionArgs := m.formatCondition() return m.getAll(fmt.Sprintf("SELECT %s FROM %s%s", m.fields, m.tables, condition), conditionArgs...) } // One retrieves one record from table and returns the result as map type. // It returns nil if there's no record retrieved with the given conditions from table. -func (m *Model) One() (Record, error) { - list, err := m.All() +// +// The optional parameter is the same as the parameter of Model.Where function, +// see Model.Where. +func (m *Model) One(where ...interface{}) (Record, error) { + list, err := m.All(where...) if err != nil { return nil, err } @@ -651,7 +695,20 @@ func (m *Model) One() (Record, error) { // Value retrieves a specified record value from table and returns the result as interface type. // It returns nil if there's no record found with the given conditions from table. -func (m *Model) Value() (Value, error) { +// +// If the optional parameter is given, the fieldsAndWhere[0] is the selected fields +// and fieldsAndWhere[1:] is treated as where condition fields. +// Also see Model.Fields and Model.Where functions. +func (m *Model) Value(fieldsAndWhere ...interface{}) (Value, error) { + if len(fieldsAndWhere) > 0 { + if len(fieldsAndWhere) > 2 { + return m.Fields(gconv.String(fieldsAndWhere[0])).Where(fieldsAndWhere[1], fieldsAndWhere[2:]...).Value() + } else if len(fieldsAndWhere) == 2 { + return m.Fields(gconv.String(fieldsAndWhere[0])).Where(fieldsAndWhere[1]).Value() + } else { + return m.Fields(gconv.String(fieldsAndWhere[0])).Value() + } + } one, err := m.One() if err != nil { return nil, err @@ -666,6 +723,9 @@ func (m *Model) Value() (Value, error) { // The parameter should be type of *struct/**struct. If type **struct is given, // it can create the struct internally during converting. // +// The optional parameter is the same as the parameter of Model.Where function, +// see Model.Where. +// // Note that it returns sql.ErrNoRows if there's no record retrieved with the given conditions // from table. // @@ -675,8 +735,8 @@ func (m *Model) Value() (Value, error) { // // user := (*User)(nil) // err := db.Table("user").Where("id", 1).Struct(&user) -func (m *Model) Struct(pointer interface{}) error { - one, err := m.One() +func (m *Model) Struct(pointer interface{}, where ...interface{}) error { + one, err := m.One(where...) if err != nil { return err } @@ -690,6 +750,9 @@ func (m *Model) Struct(pointer interface{}) error { // The parameter should be type of *[]struct/*[]*struct. It can create and fill the struct // slice internally during converting. // +// The optional parameter is the same as the parameter of Model.Where function, +// see Model.Where. +// // Note that it returns sql.ErrNoRows if there's no record retrieved with the given conditions // from table. // @@ -699,8 +762,8 @@ func (m *Model) Struct(pointer interface{}) error { // // users := ([]*User)(nil) // err := db.Table("user").Structs(&users) -func (m *Model) Structs(pointer interface{}) error { - all, err := m.All() +func (m *Model) Structs(pointer interface{}, where ...interface{}) error { + all, err := m.All(where...) if err != nil { return err } @@ -714,6 +777,9 @@ func (m *Model) Structs(pointer interface{}) error { // It calls function Struct if is type of *struct/**struct. // It calls function Structs if is type of *[]struct/*[]*struct. // +// The optional parameter is the same as the parameter of Model.Where function, +// see Model.Where. +// // Note that it returns sql.ErrNoRows if there's no record retrieved with the given conditions // from table. // @@ -729,7 +795,7 @@ func (m *Model) Structs(pointer interface{}) error { // // users := ([]*User)(nil) // err := db.Table("user").Structs(&users) -func (m *Model) Scan(pointer interface{}) error { +func (m *Model) Scan(pointer interface{}, where ...interface{}) error { t := reflect.TypeOf(pointer) k := t.Kind() if k != reflect.Ptr { @@ -738,15 +804,20 @@ func (m *Model) Scan(pointer interface{}) error { switch t.Elem().Kind() { case reflect.Array: case reflect.Slice: - return m.Structs(pointer) + return m.Structs(pointer, where...) default: - return m.Struct(pointer) + return m.Struct(pointer, where...) } return nil } // Count does "SELECT COUNT(x) FROM ..." statement for the model. -func (m *Model) Count() (int, error) { +// The optional parameter is the same as the parameter of Model.Where function, +// see Model.Where. +func (m *Model) Count(where ...interface{}) (int, error) { + if len(where) > 0 { + return m.Where(where[0], where[1:]...).Count() + } defer func(fields string) { m.fields = fields }(m.fields) @@ -821,7 +892,7 @@ func (m *Model) checkAndRemoveCache() { } // formatCondition formats where arguments of the model and returns a new condition sql and its arguments. -// Note that this function does not change any of the attribute value of the mode. +// Note that this function does not change any attribute value of the . func (m *Model) formatCondition() (condition string, conditionArgs []interface{}) { var where string if len(m.whereHolder) > 0 {