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