github.com/gogf/gf/v2@v2.7.4/database/gdb/gdb_model_select.go (about)

     1  // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/gogf/gf.
     6  
     7  package gdb
     8  
     9  import (
    10  	"context"
    11  	"fmt"
    12  	"reflect"
    13  
    14  	"github.com/gogf/gf/v2/container/gset"
    15  	"github.com/gogf/gf/v2/errors/gcode"
    16  	"github.com/gogf/gf/v2/errors/gerror"
    17  	"github.com/gogf/gf/v2/internal/reflection"
    18  	"github.com/gogf/gf/v2/text/gstr"
    19  	"github.com/gogf/gf/v2/util/gconv"
    20  )
    21  
    22  // All does "SELECT FROM ..." statement for the model.
    23  // It retrieves the records from table and returns the result as slice type.
    24  // It returns nil if there's no record retrieved with the given conditions from table.
    25  //
    26  // The optional parameter `where` is the same as the parameter of Model.Where function,
    27  // see Model.Where.
    28  func (m *Model) All(where ...interface{}) (Result, error) {
    29  	var ctx = m.GetCtx()
    30  	return m.doGetAll(ctx, false, where...)
    31  }
    32  
    33  // AllAndCount retrieves all records and the total count of records from the model.
    34  // If useFieldForCount is true, it will use the fields specified in the model for counting;
    35  // otherwise, it will use a constant value of 1 for counting.
    36  // It returns the result as a slice of records, the total count of records, and an error if any.
    37  // The where parameter is an optional list of conditions to use when retrieving records.
    38  //
    39  // Example:
    40  //
    41  //	var model Model
    42  //	var result Result
    43  //	var count int
    44  //	where := []interface{}{"name = ?", "John"}
    45  //	result, count, err := model.AllAndCount(true)
    46  //	if err != nil {
    47  //	    // Handle error.
    48  //	}
    49  //	fmt.Println(result, count)
    50  func (m *Model) AllAndCount(useFieldForCount bool) (result Result, totalCount int, err error) {
    51  	// Clone the model for counting
    52  	countModel := m.Clone()
    53  
    54  	// If useFieldForCount is false, set the fields to a constant value of 1 for counting
    55  	if !useFieldForCount {
    56  		countModel.fields = "1"
    57  	}
    58  
    59  	// Get the total count of records
    60  	totalCount, err = countModel.Count()
    61  	if err != nil {
    62  		return
    63  	}
    64  
    65  	// If the total count is 0, there are no records to retrieve, so return early
    66  	if totalCount == 0 {
    67  		return
    68  	}
    69  
    70  	// Retrieve all records
    71  	result, err = m.doGetAll(m.GetCtx(), false)
    72  	return
    73  }
    74  
    75  // Chunk iterates the query result with given `size` and `handler` function.
    76  func (m *Model) Chunk(size int, handler ChunkHandler) {
    77  	page := m.start
    78  	if page <= 0 {
    79  		page = 1
    80  	}
    81  	model := m
    82  	for {
    83  		model = model.Page(page, size)
    84  		data, err := model.All()
    85  		if err != nil {
    86  			handler(nil, err)
    87  			break
    88  		}
    89  		if len(data) == 0 {
    90  			break
    91  		}
    92  		if !handler(data, err) {
    93  			break
    94  		}
    95  		if len(data) < size {
    96  			break
    97  		}
    98  		page++
    99  	}
   100  }
   101  
   102  // One retrieves one record from table and returns the result as map type.
   103  // It returns nil if there's no record retrieved with the given conditions from table.
   104  //
   105  // The optional parameter `where` is the same as the parameter of Model.Where function,
   106  // see Model.Where.
   107  func (m *Model) One(where ...interface{}) (Record, error) {
   108  	var ctx = m.GetCtx()
   109  	if len(where) > 0 {
   110  		return m.Where(where[0], where[1:]...).One()
   111  	}
   112  	all, err := m.doGetAll(ctx, true)
   113  	if err != nil {
   114  		return nil, err
   115  	}
   116  	if len(all) > 0 {
   117  		return all[0], nil
   118  	}
   119  	return nil, nil
   120  }
   121  
   122  // Array queries and returns data values as slice from database.
   123  // Note that if there are multiple columns in the result, it returns just one column values randomly.
   124  //
   125  // If the optional parameter `fieldsAndWhere` is given, the fieldsAndWhere[0] is the selected fields
   126  // and fieldsAndWhere[1:] is treated as where condition fields.
   127  // Also see Model.Fields and Model.Where functions.
   128  func (m *Model) Array(fieldsAndWhere ...interface{}) ([]Value, error) {
   129  	if len(fieldsAndWhere) > 0 {
   130  		if len(fieldsAndWhere) > 2 {
   131  			return m.Fields(gconv.String(fieldsAndWhere[0])).Where(fieldsAndWhere[1], fieldsAndWhere[2:]...).Array()
   132  		} else if len(fieldsAndWhere) == 2 {
   133  			return m.Fields(gconv.String(fieldsAndWhere[0])).Where(fieldsAndWhere[1]).Array()
   134  		} else {
   135  			return m.Fields(gconv.String(fieldsAndWhere[0])).Array()
   136  		}
   137  	}
   138  	all, err := m.All()
   139  	if err != nil {
   140  		return nil, err
   141  	}
   142  	var (
   143  		field string
   144  		core  = m.db.GetCore()
   145  		ctx   = core.injectInternalColumn(m.GetCtx())
   146  	)
   147  	if len(all) > 0 {
   148  		if internalData := core.getInternalColumnFromCtx(ctx); internalData != nil {
   149  			field = internalData.FirstResultColumn
   150  		} else {
   151  			return nil, gerror.NewCode(
   152  				gcode.CodeInternalError,
   153  				`query array error: the internal context data is missing. there's internal issue should be fixed`,
   154  			)
   155  		}
   156  	}
   157  	return all.Array(field), nil
   158  }
   159  
   160  // Struct retrieves one record from table and converts it into given struct.
   161  // The parameter `pointer` should be type of *struct/**struct. If type **struct is given,
   162  // it can create the struct internally during converting.
   163  //
   164  // The optional parameter `where` is the same as the parameter of Model.Where function,
   165  // see Model.Where.
   166  //
   167  // Note that it returns sql.ErrNoRows if the given parameter `pointer` pointed to a variable that has
   168  // default value and there's no record retrieved with the given conditions from table.
   169  //
   170  // Example:
   171  // user := new(User)
   172  // err  := db.Model("user").Where("id", 1).Scan(user)
   173  //
   174  // user := (*User)(nil)
   175  // err  := db.Model("user").Where("id", 1).Scan(&user).
   176  func (m *Model) doStruct(pointer interface{}, where ...interface{}) error {
   177  	model := m
   178  	// Auto selecting fields by struct attributes.
   179  	if len(model.fieldsEx) == 0 && (model.fields == "" || model.fields == "*") {
   180  		if v, ok := pointer.(reflect.Value); ok {
   181  			model = m.Fields(v.Interface())
   182  		} else {
   183  			model = m.Fields(pointer)
   184  		}
   185  	}
   186  	one, err := model.One(where...)
   187  	if err != nil {
   188  		return err
   189  	}
   190  	if err = one.Struct(pointer); err != nil {
   191  		return err
   192  	}
   193  	return model.doWithScanStruct(pointer)
   194  }
   195  
   196  // Structs retrieves records from table and converts them into given struct slice.
   197  // The parameter `pointer` should be type of *[]struct/*[]*struct. It can create and fill the struct
   198  // slice internally during converting.
   199  //
   200  // The optional parameter `where` is the same as the parameter of Model.Where function,
   201  // see Model.Where.
   202  //
   203  // Note that it returns sql.ErrNoRows if the given parameter `pointer` pointed to a variable that has
   204  // default value and there's no record retrieved with the given conditions from table.
   205  //
   206  // Example:
   207  // users := ([]User)(nil)
   208  // err   := db.Model("user").Scan(&users)
   209  //
   210  // users := ([]*User)(nil)
   211  // err   := db.Model("user").Scan(&users).
   212  func (m *Model) doStructs(pointer interface{}, where ...interface{}) error {
   213  	model := m
   214  	// Auto selecting fields by struct attributes.
   215  	if len(model.fieldsEx) == 0 && (model.fields == "" || model.fields == "*") {
   216  		if v, ok := pointer.(reflect.Value); ok {
   217  			model = m.Fields(
   218  				reflect.New(
   219  					v.Type().Elem(),
   220  				).Interface(),
   221  			)
   222  		} else {
   223  			model = m.Fields(
   224  				reflect.New(
   225  					reflect.ValueOf(pointer).Elem().Type().Elem(),
   226  				).Interface(),
   227  			)
   228  		}
   229  	}
   230  	all, err := model.All(where...)
   231  	if err != nil {
   232  		return err
   233  	}
   234  	if err = all.Structs(pointer); err != nil {
   235  		return err
   236  	}
   237  	return model.doWithScanStructs(pointer)
   238  }
   239  
   240  // Scan automatically calls Struct or Structs function according to the type of parameter `pointer`.
   241  // It calls function doStruct if `pointer` is type of *struct/**struct.
   242  // It calls function doStructs if `pointer` is type of *[]struct/*[]*struct.
   243  //
   244  // The optional parameter `where` is the same as the parameter of Model.Where function,  see Model.Where.
   245  //
   246  // Note that it returns sql.ErrNoRows if the given parameter `pointer` pointed to a variable that has
   247  // default value and there's no record retrieved with the given conditions from table.
   248  //
   249  // Example:
   250  // user := new(User)
   251  // err  := db.Model("user").Where("id", 1).Scan(user)
   252  //
   253  // user := (*User)(nil)
   254  // err  := db.Model("user").Where("id", 1).Scan(&user)
   255  //
   256  // users := ([]User)(nil)
   257  // err   := db.Model("user").Scan(&users)
   258  //
   259  // users := ([]*User)(nil)
   260  // err   := db.Model("user").Scan(&users).
   261  func (m *Model) Scan(pointer interface{}, where ...interface{}) error {
   262  	reflectInfo := reflection.OriginTypeAndKind(pointer)
   263  	if reflectInfo.InputKind != reflect.Ptr {
   264  		return gerror.NewCode(
   265  			gcode.CodeInvalidParameter,
   266  			`the parameter "pointer" for function Scan should type of pointer`,
   267  		)
   268  	}
   269  	switch reflectInfo.OriginKind {
   270  	case reflect.Slice, reflect.Array:
   271  		return m.doStructs(pointer, where...)
   272  
   273  	case reflect.Struct, reflect.Invalid:
   274  		return m.doStruct(pointer, where...)
   275  
   276  	default:
   277  		return gerror.NewCode(
   278  			gcode.CodeInvalidParameter,
   279  			`element of parameter "pointer" for function Scan should type of struct/*struct/[]struct/[]*struct`,
   280  		)
   281  	}
   282  }
   283  
   284  // ScanAndCount scans a single record or record array that matches the given conditions and counts the total number of records that match those conditions.
   285  // If useFieldForCount is true, it will use the fields specified in the model for counting;
   286  // The pointer parameter is a pointer to a struct that the scanned data will be stored in.
   287  // The pointerCount parameter is a pointer to an integer that will be set to the total number of records that match the given conditions.
   288  // The where parameter is an optional list of conditions to use when retrieving records.
   289  //
   290  // Example:
   291  //
   292  //	var count int
   293  //	user := new(User)
   294  //	err  := db.Model("user").Where("id", 1).ScanAndCount(user,&count,true)
   295  //	fmt.Println(user, count)
   296  //
   297  // Example Join:
   298  //
   299  //	type User struct {
   300  //		Id       int
   301  //		Passport string
   302  //		Name     string
   303  //		Age      int
   304  //	}
   305  //	var users []User
   306  //	var count int
   307  //	db.Model(table).As("u1").
   308  //		LeftJoin(tableName2, "u2", "u2.id=u1.id").
   309  //		Fields("u1.passport,u1.id,u2.name,u2.age").
   310  //		Where("u1.id<2").
   311  //		ScanAndCount(&users, &count, false)
   312  func (m *Model) ScanAndCount(pointer interface{}, totalCount *int, useFieldForCount bool) (err error) {
   313  	// support Fields with *, example: .Fields("a.*, b.name"). Count sql is select count(1) from xxx
   314  	countModel := m.Clone()
   315  	// If useFieldForCount is false, set the fields to a constant value of 1 for counting
   316  	if !useFieldForCount {
   317  		countModel.fields = "1"
   318  	}
   319  
   320  	// Get the total count of records
   321  	*totalCount, err = countModel.Count()
   322  	if err != nil {
   323  		return err
   324  	}
   325  
   326  	// If the total count is 0, there are no records to retrieve, so return early
   327  	if *totalCount == 0 {
   328  		return
   329  	}
   330  	err = m.Scan(pointer)
   331  	return
   332  }
   333  
   334  // ScanList converts `r` to struct slice which contains other complex struct attributes.
   335  // Note that the parameter `listPointer` should be type of *[]struct/*[]*struct.
   336  //
   337  // See Result.ScanList.
   338  func (m *Model) ScanList(structSlicePointer interface{}, bindToAttrName string, relationAttrNameAndFields ...string) (err error) {
   339  	var result Result
   340  	out, err := checkGetSliceElementInfoForScanList(structSlicePointer, bindToAttrName)
   341  	if err != nil {
   342  		return err
   343  	}
   344  	if m.fields != defaultFields || len(m.fieldsEx) != 0 {
   345  		// There are custom fields.
   346  		result, err = m.All()
   347  	} else {
   348  		// Filter fields using temporary created struct using reflect.New.
   349  		result, err = m.Fields(reflect.New(out.BindToAttrType).Interface()).All()
   350  	}
   351  	if err != nil {
   352  		return err
   353  	}
   354  	var (
   355  		relationAttrName string
   356  		relationFields   string
   357  	)
   358  	switch len(relationAttrNameAndFields) {
   359  	case 2:
   360  		relationAttrName = relationAttrNameAndFields[0]
   361  		relationFields = relationAttrNameAndFields[1]
   362  	case 1:
   363  		relationFields = relationAttrNameAndFields[0]
   364  	}
   365  	return doScanList(doScanListInput{
   366  		Model:              m,
   367  		Result:             result,
   368  		StructSlicePointer: structSlicePointer,
   369  		StructSliceValue:   out.SliceReflectValue,
   370  		BindToAttrName:     bindToAttrName,
   371  		RelationAttrName:   relationAttrName,
   372  		RelationFields:     relationFields,
   373  	})
   374  }
   375  
   376  // Value retrieves a specified record value from table and returns the result as interface type.
   377  // It returns nil if there's no record found with the given conditions from table.
   378  //
   379  // If the optional parameter `fieldsAndWhere` is given, the fieldsAndWhere[0] is the selected fields
   380  // and fieldsAndWhere[1:] is treated as where condition fields.
   381  // Also see Model.Fields and Model.Where functions.
   382  func (m *Model) Value(fieldsAndWhere ...interface{}) (Value, error) {
   383  	var (
   384  		core = m.db.GetCore()
   385  		ctx  = core.injectInternalColumn(m.GetCtx())
   386  	)
   387  	if len(fieldsAndWhere) > 0 {
   388  		if len(fieldsAndWhere) > 2 {
   389  			return m.Fields(gconv.String(fieldsAndWhere[0])).Where(fieldsAndWhere[1], fieldsAndWhere[2:]...).Value()
   390  		} else if len(fieldsAndWhere) == 2 {
   391  			return m.Fields(gconv.String(fieldsAndWhere[0])).Where(fieldsAndWhere[1]).Value()
   392  		} else {
   393  			return m.Fields(gconv.String(fieldsAndWhere[0])).Value()
   394  		}
   395  	}
   396  	var (
   397  		sqlWithHolder, holderArgs = m.getFormattedSqlAndArgs(ctx, queryTypeValue, true)
   398  		all, err                  = m.doGetAllBySql(ctx, queryTypeValue, sqlWithHolder, holderArgs...)
   399  	)
   400  	if err != nil {
   401  		return nil, err
   402  	}
   403  	if len(all) > 0 {
   404  		if internalData := core.getInternalColumnFromCtx(ctx); internalData != nil {
   405  			if v, ok := all[0][internalData.FirstResultColumn]; ok {
   406  				return v, nil
   407  			}
   408  		} else {
   409  			return nil, gerror.NewCode(
   410  				gcode.CodeInternalError,
   411  				`query value error: the internal context data is missing. there's internal issue should be fixed`,
   412  			)
   413  		}
   414  	}
   415  	return nil, nil
   416  }
   417  
   418  // Count does "SELECT COUNT(x) FROM ..." statement for the model.
   419  // The optional parameter `where` is the same as the parameter of Model.Where function,
   420  // see Model.Where.
   421  func (m *Model) Count(where ...interface{}) (int, error) {
   422  	var (
   423  		core = m.db.GetCore()
   424  		ctx  = core.injectInternalColumn(m.GetCtx())
   425  	)
   426  	if len(where) > 0 {
   427  		return m.Where(where[0], where[1:]...).Count()
   428  	}
   429  	var (
   430  		sqlWithHolder, holderArgs = m.getFormattedSqlAndArgs(ctx, queryTypeCount, false)
   431  		all, err                  = m.doGetAllBySql(ctx, queryTypeCount, sqlWithHolder, holderArgs...)
   432  	)
   433  	if err != nil {
   434  		return 0, err
   435  	}
   436  	if len(all) > 0 {
   437  		if internalData := core.getInternalColumnFromCtx(ctx); internalData != nil {
   438  			if v, ok := all[0][internalData.FirstResultColumn]; ok {
   439  				return v.Int(), nil
   440  			}
   441  		} else {
   442  			return 0, gerror.NewCode(
   443  				gcode.CodeInternalError,
   444  				`query count error: the internal context data is missing. there's internal issue should be fixed`,
   445  			)
   446  		}
   447  	}
   448  	return 0, nil
   449  }
   450  
   451  // CountColumn does "SELECT COUNT(x) FROM ..." statement for the model.
   452  func (m *Model) CountColumn(column string) (int, error) {
   453  	if len(column) == 0 {
   454  		return 0, nil
   455  	}
   456  	return m.Fields(column).Count()
   457  }
   458  
   459  // Min does "SELECT MIN(x) FROM ..." statement for the model.
   460  func (m *Model) Min(column string) (float64, error) {
   461  	if len(column) == 0 {
   462  		return 0, nil
   463  	}
   464  	value, err := m.Fields(fmt.Sprintf(`MIN(%s)`, m.QuoteWord(column))).Value()
   465  	if err != nil {
   466  		return 0, err
   467  	}
   468  	return value.Float64(), err
   469  }
   470  
   471  // Max does "SELECT MAX(x) FROM ..." statement for the model.
   472  func (m *Model) Max(column string) (float64, error) {
   473  	if len(column) == 0 {
   474  		return 0, nil
   475  	}
   476  	value, err := m.Fields(fmt.Sprintf(`MAX(%s)`, m.QuoteWord(column))).Value()
   477  	if err != nil {
   478  		return 0, err
   479  	}
   480  	return value.Float64(), err
   481  }
   482  
   483  // Avg does "SELECT AVG(x) FROM ..." statement for the model.
   484  func (m *Model) Avg(column string) (float64, error) {
   485  	if len(column) == 0 {
   486  		return 0, nil
   487  	}
   488  	value, err := m.Fields(fmt.Sprintf(`AVG(%s)`, m.QuoteWord(column))).Value()
   489  	if err != nil {
   490  		return 0, err
   491  	}
   492  	return value.Float64(), err
   493  }
   494  
   495  // Sum does "SELECT SUM(x) FROM ..." statement for the model.
   496  func (m *Model) Sum(column string) (float64, error) {
   497  	if len(column) == 0 {
   498  		return 0, nil
   499  	}
   500  	value, err := m.Fields(fmt.Sprintf(`SUM(%s)`, m.QuoteWord(column))).Value()
   501  	if err != nil {
   502  		return 0, err
   503  	}
   504  	return value.Float64(), err
   505  }
   506  
   507  // Union does "(SELECT xxx FROM xxx) UNION (SELECT xxx FROM xxx) ..." statement for the model.
   508  func (m *Model) Union(unions ...*Model) *Model {
   509  	return m.db.Union(unions...)
   510  }
   511  
   512  // UnionAll does "(SELECT xxx FROM xxx) UNION ALL (SELECT xxx FROM xxx) ..." statement for the model.
   513  func (m *Model) UnionAll(unions ...*Model) *Model {
   514  	return m.db.UnionAll(unions...)
   515  }
   516  
   517  // Limit sets the "LIMIT" statement for the model.
   518  // The parameter `limit` can be either one or two number, if passed two number is passed,
   519  // it then sets "LIMIT limit[0],limit[1]" statement for the model, or else it sets "LIMIT limit[0]"
   520  // statement.
   521  func (m *Model) Limit(limit ...int) *Model {
   522  	model := m.getModel()
   523  	switch len(limit) {
   524  	case 1:
   525  		model.limit = limit[0]
   526  	case 2:
   527  		model.start = limit[0]
   528  		model.limit = limit[1]
   529  	}
   530  	return model
   531  }
   532  
   533  // Offset sets the "OFFSET" statement for the model.
   534  // It only makes sense for some databases like SQLServer, PostgreSQL, etc.
   535  func (m *Model) Offset(offset int) *Model {
   536  	model := m.getModel()
   537  	model.offset = offset
   538  	return model
   539  }
   540  
   541  // Distinct forces the query to only return distinct results.
   542  func (m *Model) Distinct() *Model {
   543  	model := m.getModel()
   544  	model.distinct = "DISTINCT "
   545  	return model
   546  }
   547  
   548  // Page sets the paging number for the model.
   549  // The parameter `page` is started from 1 for paging.
   550  // Note that, it differs that the Limit function starts from 0 for "LIMIT" statement.
   551  func (m *Model) Page(page, limit int) *Model {
   552  	model := m.getModel()
   553  	if page <= 0 {
   554  		page = 1
   555  	}
   556  	model.start = (page - 1) * limit
   557  	model.limit = limit
   558  	return model
   559  }
   560  
   561  // Having sets the having statement for the model.
   562  // The parameters of this function usage are as the same as function Where.
   563  // See Where.
   564  func (m *Model) Having(having interface{}, args ...interface{}) *Model {
   565  	model := m.getModel()
   566  	model.having = []interface{}{
   567  		having, args,
   568  	}
   569  	return model
   570  }
   571  
   572  // doGetAll does "SELECT FROM ..." statement for the model.
   573  // It retrieves the records from table and returns the result as slice type.
   574  // It returns nil if there's no record retrieved with the given conditions from table.
   575  //
   576  // The parameter `limit1` specifies whether limits querying only one record if m.limit is not set.
   577  // The optional parameter `where` is the same as the parameter of Model.Where function,
   578  // see Model.Where.
   579  func (m *Model) doGetAll(ctx context.Context, limit1 bool, where ...interface{}) (Result, error) {
   580  	if len(where) > 0 {
   581  		return m.Where(where[0], where[1:]...).All()
   582  	}
   583  	sqlWithHolder, holderArgs := m.getFormattedSqlAndArgs(ctx, queryTypeNormal, limit1)
   584  	return m.doGetAllBySql(ctx, queryTypeNormal, sqlWithHolder, holderArgs...)
   585  }
   586  
   587  // doGetAllBySql does the select statement on the database.
   588  func (m *Model) doGetAllBySql(ctx context.Context, queryType queryType, sql string, args ...interface{}) (result Result, err error) {
   589  	if result, err = m.getSelectResultFromCache(ctx, sql, args...); err != nil || result != nil {
   590  		return
   591  	}
   592  
   593  	in := &HookSelectInput{
   594  		internalParamHookSelect: internalParamHookSelect{
   595  			internalParamHook: internalParamHook{
   596  				link: m.getLink(false),
   597  			},
   598  			handler: m.hookHandler.Select,
   599  		},
   600  		Model: m,
   601  		Table: m.tables,
   602  		Sql:   sql,
   603  		Args:  m.mergeArguments(args),
   604  	}
   605  	if result, err = in.Next(ctx); err != nil {
   606  		return
   607  	}
   608  
   609  	err = m.saveSelectResultToCache(ctx, queryType, result, sql, args...)
   610  	return
   611  }
   612  
   613  func (m *Model) getFormattedSqlAndArgs(
   614  	ctx context.Context, queryType queryType, limit1 bool,
   615  ) (sqlWithHolder string, holderArgs []interface{}) {
   616  	switch queryType {
   617  	case queryTypeCount:
   618  		queryFields := "COUNT(1)"
   619  		if m.fields != "" && m.fields != "*" {
   620  			// DO NOT quote the m.fields here, in case of fields like:
   621  			// DISTINCT t.user_id uid
   622  			queryFields = fmt.Sprintf(`COUNT(%s%s)`, m.distinct, m.fields)
   623  		}
   624  		// Raw SQL Model.
   625  		if m.rawSql != "" {
   626  			sqlWithHolder = fmt.Sprintf("SELECT %s FROM (%s) AS T", queryFields, m.rawSql)
   627  			return sqlWithHolder, nil
   628  		}
   629  		conditionWhere, conditionExtra, conditionArgs := m.formatCondition(ctx, false, true)
   630  		sqlWithHolder = fmt.Sprintf("SELECT %s FROM %s%s", queryFields, m.tables, conditionWhere+conditionExtra)
   631  		if len(m.groupBy) > 0 {
   632  			sqlWithHolder = fmt.Sprintf("SELECT COUNT(1) FROM (%s) count_alias", sqlWithHolder)
   633  		}
   634  		return sqlWithHolder, conditionArgs
   635  
   636  	default:
   637  		conditionWhere, conditionExtra, conditionArgs := m.formatCondition(ctx, limit1, false)
   638  		// Raw SQL Model, especially for UNION/UNION ALL featured SQL.
   639  		if m.rawSql != "" {
   640  			sqlWithHolder = fmt.Sprintf(
   641  				"%s%s",
   642  				m.rawSql,
   643  				conditionWhere+conditionExtra,
   644  			)
   645  			return sqlWithHolder, conditionArgs
   646  		}
   647  		// DO NOT quote the m.fields where, in case of fields like:
   648  		// DISTINCT t.user_id uid
   649  		sqlWithHolder = fmt.Sprintf(
   650  			"SELECT %s%s FROM %s%s",
   651  			m.distinct, m.getFieldsFiltered(), m.tables, conditionWhere+conditionExtra,
   652  		)
   653  		return sqlWithHolder, conditionArgs
   654  	}
   655  }
   656  
   657  func (m *Model) getHolderAndArgsAsSubModel(ctx context.Context) (holder string, args []interface{}) {
   658  	holder, args = m.getFormattedSqlAndArgs(
   659  		ctx, queryTypeNormal, false,
   660  	)
   661  	args = m.mergeArguments(args)
   662  	return
   663  }
   664  
   665  func (m *Model) getAutoPrefix() string {
   666  	autoPrefix := ""
   667  	if gstr.Contains(m.tables, " JOIN ") {
   668  		autoPrefix = m.db.GetCore().QuoteWord(
   669  			m.db.GetCore().guessPrimaryTableName(m.tablesInit),
   670  		)
   671  	}
   672  	return autoPrefix
   673  }
   674  
   675  // getFieldsFiltered checks the fields and fieldsEx attributes, filters and returns the fields that will
   676  // really be committed to underlying database driver.
   677  func (m *Model) getFieldsFiltered() string {
   678  	if len(m.fieldsEx) == 0 {
   679  		// No filtering, containing special chars.
   680  		if gstr.ContainsAny(m.fields, "()") {
   681  			return m.fields
   682  		}
   683  		// No filtering.
   684  		if !gstr.ContainsAny(m.fields, ". ") {
   685  			return m.db.GetCore().QuoteString(m.fields)
   686  		}
   687  		return m.fields
   688  	}
   689  	var (
   690  		fieldsArray []string
   691  		fieldsExSet = gset.NewStrSetFrom(m.fieldsEx)
   692  	)
   693  	if m.fields != "*" {
   694  		// Filter custom fields with fieldEx.
   695  		fieldsArray = make([]string, 0, 8)
   696  		for _, v := range gstr.SplitAndTrim(m.fields, ",") {
   697  			fieldsArray = append(fieldsArray, v[gstr.PosR(v, "-")+1:])
   698  		}
   699  	} else {
   700  		if gstr.Contains(m.tables, " ") {
   701  			panic("function FieldsEx supports only single table operations")
   702  		}
   703  		// Filter table fields with fieldEx.
   704  		tableFields, err := m.TableFields(m.tablesInit)
   705  		if err != nil {
   706  			panic(err)
   707  		}
   708  		if len(tableFields) == 0 {
   709  			panic(fmt.Sprintf(`empty table fields for table "%s"`, m.tables))
   710  		}
   711  		fieldsArray = make([]string, len(tableFields))
   712  		for k, v := range tableFields {
   713  			fieldsArray[v.Index] = k
   714  		}
   715  	}
   716  	newFields := ""
   717  	for _, k := range fieldsArray {
   718  		if fieldsExSet.Contains(k) {
   719  			continue
   720  		}
   721  		if len(newFields) > 0 {
   722  			newFields += ","
   723  		}
   724  		newFields += m.db.GetCore().QuoteWord(k)
   725  	}
   726  	return newFields
   727  }
   728  
   729  // formatCondition formats where arguments of the model and returns a new condition sql and its arguments.
   730  // Note that this function does not change any attribute value of the `m`.
   731  //
   732  // The parameter `limit1` specifies whether limits querying only one record if m.limit is not set.
   733  func (m *Model) formatCondition(
   734  	ctx context.Context, limit1 bool, isCountStatement bool,
   735  ) (conditionWhere string, conditionExtra string, conditionArgs []interface{}) {
   736  	var autoPrefix = m.getAutoPrefix()
   737  	// GROUP BY.
   738  	if m.groupBy != "" {
   739  		conditionExtra += " GROUP BY " + m.groupBy
   740  	}
   741  	// WHERE
   742  	conditionWhere, conditionArgs = m.whereBuilder.Build()
   743  	softDeletingCondition := m.softTimeMaintainer().GetWhereConditionForDelete(ctx)
   744  	if m.rawSql != "" && conditionWhere != "" {
   745  		if gstr.ContainsI(m.rawSql, " WHERE ") {
   746  			conditionWhere = " AND " + conditionWhere
   747  		} else {
   748  			conditionWhere = " WHERE " + conditionWhere
   749  		}
   750  	} else if !m.unscoped && softDeletingCondition != "" {
   751  		if conditionWhere == "" {
   752  			conditionWhere = fmt.Sprintf(` WHERE %s`, softDeletingCondition)
   753  		} else {
   754  			conditionWhere = fmt.Sprintf(` WHERE (%s) AND %s`, conditionWhere, softDeletingCondition)
   755  		}
   756  	} else {
   757  		if conditionWhere != "" {
   758  			conditionWhere = " WHERE " + conditionWhere
   759  		}
   760  	}
   761  	// HAVING.
   762  	if len(m.having) > 0 {
   763  		havingHolder := WhereHolder{
   764  			Where:  m.having[0],
   765  			Args:   gconv.Interfaces(m.having[1]),
   766  			Prefix: autoPrefix,
   767  		}
   768  		havingStr, havingArgs := formatWhereHolder(ctx, m.db, formatWhereHolderInput{
   769  			WhereHolder: havingHolder,
   770  			OmitNil:     m.option&optionOmitNilWhere > 0,
   771  			OmitEmpty:   m.option&optionOmitEmptyWhere > 0,
   772  			Schema:      m.schema,
   773  			Table:       m.tables,
   774  		})
   775  		if len(havingStr) > 0 {
   776  			conditionExtra += " HAVING " + havingStr
   777  			conditionArgs = append(conditionArgs, havingArgs...)
   778  		}
   779  	}
   780  	// ORDER BY.
   781  	if !isCountStatement { // The count statement of sqlserver cannot contain the order by statement
   782  		if m.orderBy != "" {
   783  			conditionExtra += " ORDER BY " + m.orderBy
   784  		}
   785  	}
   786  	// LIMIT.
   787  	if !isCountStatement {
   788  		if m.limit != 0 {
   789  			if m.start >= 0 {
   790  				conditionExtra += fmt.Sprintf(" LIMIT %d,%d", m.start, m.limit)
   791  			} else {
   792  				conditionExtra += fmt.Sprintf(" LIMIT %d", m.limit)
   793  			}
   794  		} else if limit1 {
   795  			conditionExtra += " LIMIT 1"
   796  		}
   797  
   798  		if m.offset >= 0 {
   799  			conditionExtra += fmt.Sprintf(" OFFSET %d", m.offset)
   800  		}
   801  	}
   802  
   803  	if m.lockInfo != "" {
   804  		conditionExtra += " " + m.lockInfo
   805  	}
   806  	return
   807  }