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 }