diff --git a/database/gdb/gdb_model_fields.go b/database/gdb/gdb_model_fields.go index 2fdd98b85..003201577 100644 --- a/database/gdb/gdb_model_fields.go +++ b/database/gdb/gdb_model_fields.go @@ -33,40 +33,20 @@ func (m *Model) Fields(fields string) *Model { // FieldsEx sets the excluded operation fields of the model, multiple fields joined using char ','. // Note that this function supports only single table operations. func (m *Model) FieldsEx(fields string) *Model { - if gstr.Contains(m.tables, " ") { - panic("function FieldsEx supports only single table operations") - } - tableFields, err := m.db.TableFields(m.tables) - if err != nil { - panic(err) - } - if len(tableFields) == 0 { - panic(fmt.Sprintf(`empty table fields for table "%s"`, m.tables)) - } model := m.getModel() model.fieldsEx = fields - fieldsExSet := gset.NewStrSetFrom(gstr.SplitAndTrim(fields, ",")) - fieldsArray := make([]string, len(tableFields)) - for k, v := range tableFields { - fieldsArray[v.Index] = k - } - model.fields = "" - for _, k := range fieldsArray { - if fieldsExSet.Contains(k) { - continue - } - if len(model.fields) > 0 { - model.fields += "," - } - model.fields += k - } - model.fields = model.db.QuoteString(model.fields) return model } +// Deprecated, use GetFieldsStr instead. +// This function name confuses the user that it was a chaining function. +func (m *Model) FieldsStr(prefix ...string) string { + return m.GetFieldsStr(prefix...) +} + // FieldsStr retrieves and returns all fields from the table, joined with char ','. // The optional parameter specifies the prefix for each field, eg: FieldsStr("u."). -func (m *Model) FieldsStr(prefix ...string) string { +func (m *Model) GetFieldsStr(prefix ...string) string { prefixStr := "" if len(prefix) > 0 { prefixStr = prefix[0] @@ -93,11 +73,17 @@ func (m *Model) FieldsStr(prefix ...string) string { return newFields } +// Deprecated, use GetFieldsExStr instead. +// This function name confuses the user that it was a chaining function. +func (m *Model) FieldsExStr(fields string, prefix ...string) string { + return m.GetFieldsExStr(fields, prefix...) +} + // FieldsExStr retrieves and returns fields which are not in parameter from the table, // joined with char ','. // The parameter specifies the fields that are excluded. // The optional parameter specifies the prefix for each field, eg: FieldsExStr("id", "u."). -func (m *Model) FieldsExStr(fields string, prefix ...string) string { +func (m *Model) GetFieldsExStr(fields string, prefix ...string) string { prefixStr := "" if len(prefix) > 0 { prefixStr = prefix[0] diff --git a/database/gdb/gdb_model_select.go b/database/gdb/gdb_model_select.go index bf209b290..364c93dbb 100644 --- a/database/gdb/gdb_model_select.go +++ b/database/gdb/gdb_model_select.go @@ -8,7 +8,9 @@ package gdb import ( "fmt" + "github.com/gogf/gf/container/gset" "github.com/gogf/gf/container/gvar" + "github.com/gogf/gf/text/gstr" "github.com/gogf/gf/util/gconv" "reflect" ) @@ -53,12 +55,13 @@ func (m *Model) doGetAll(limit1 bool, where ...interface{}) (Result, error) { } conditionWhere += softDeletingCondition } + // DO NOT quote the m.fields where, in case of fields like: // DISTINCT t.user_id uid return m.doGetAllBySql( fmt.Sprintf( "SELECT %s FROM %s%s", - m.fields, + m.getFieldsFiltered(), m.tables, conditionWhere+conditionExtra, ), @@ -66,6 +69,53 @@ func (m *Model) doGetAll(limit1 bool, where ...interface{}) (Result, error) { ) } +// getFieldsFiltered checks the fields and fieldsEx attributes, filters and returns the fields that will +// really be committed to underlying database driver. +func (m *Model) getFieldsFiltered() string { + if m.fieldsEx == "" { + // No filtering. + return m.fields + } + var ( + fieldsArray []string + fieldsExSet = gset.NewStrSetFrom(gstr.SplitAndTrim(m.fieldsEx, ",")) + ) + if m.fields != "*" { + // Filter custom fields with fieldEx. + fieldsArray = make([]string, 0, 8) + for _, v := range gstr.SplitAndTrim(m.fields, ",") { + fieldsArray = append(fieldsArray, v[gstr.PosR(v, "-")+1:]) + } + } else { + if gstr.Contains(m.tables, " ") { + panic("function FieldsEx supports only single table operations") + } + // Filter table fields with fieldEx. + tableFields, err := m.db.TableFields(m.tables) + if err != nil { + panic(err) + } + if len(tableFields) == 0 { + panic(fmt.Sprintf(`empty table fields for table "%s"`, m.tables)) + } + fieldsArray = make([]string, len(tableFields)) + for k, v := range tableFields { + fieldsArray[v.Index] = k + } + } + newFields := "" + for _, k := range fieldsArray { + if fieldsExSet.Contains(k) { + continue + } + if len(newFields) > 0 { + newFields += "," + } + newFields += k + } + return newFields +} + // Chunk iterates the query result with given size and callback function. func (m *Model) Chunk(limit int, callback func(result Result, err error) bool) { page := m.start