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 }