github.com/gogf/gf@v1.16.9/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 "fmt" 11 "github.com/gogf/gf/errors/gcode" 12 "github.com/gogf/gf/errors/gerror" 13 "reflect" 14 15 "github.com/gogf/gf/container/gset" 16 "github.com/gogf/gf/container/gvar" 17 "github.com/gogf/gf/internal/intlog" 18 "github.com/gogf/gf/internal/json" 19 "github.com/gogf/gf/text/gstr" 20 "github.com/gogf/gf/util/gconv" 21 ) 22 23 // Select is alias of Model.All. 24 // See Model.All. 25 // Deprecated, use All instead. 26 func (m *Model) Select(where ...interface{}) (Result, error) { 27 return m.All(where...) 28 } 29 30 // All does "SELECT FROM ..." statement for the model. 31 // It retrieves the records from table and returns the result as slice type. 32 // It returns nil if there's no record retrieved with the given conditions from table. 33 // 34 // The optional parameter `where` is the same as the parameter of Model.Where function, 35 // see Model.Where. 36 func (m *Model) All(where ...interface{}) (Result, error) { 37 return m.doGetAll(false, where...) 38 } 39 40 // doGetAll does "SELECT FROM ..." statement for the model. 41 // It retrieves the records from table and returns the result as slice type. 42 // It returns nil if there's no record retrieved with the given conditions from table. 43 // 44 // The parameter `limit1` specifies whether limits querying only one record if m.limit is not set. 45 // The optional parameter `where` is the same as the parameter of Model.Where function, 46 // see Model.Where. 47 func (m *Model) doGetAll(limit1 bool, where ...interface{}) (Result, error) { 48 if len(where) > 0 { 49 return m.Where(where[0], where[1:]...).All() 50 } 51 sqlWithHolder, holderArgs := m.getFormattedSqlAndArgs(queryTypeNormal, limit1) 52 return m.doGetAllBySql(sqlWithHolder, holderArgs...) 53 } 54 55 // getFieldsFiltered checks the fields and fieldsEx attributes, filters and returns the fields that will 56 // really be committed to underlying database driver. 57 func (m *Model) getFieldsFiltered() string { 58 if m.fieldsEx == "" { 59 // No filtering. 60 if !gstr.Contains(m.fields, ".") && !gstr.Contains(m.fields, " ") { 61 return m.db.GetCore().QuoteString(m.fields) 62 } 63 return m.fields 64 } 65 var ( 66 fieldsArray []string 67 fieldsExSet = gset.NewStrSetFrom(gstr.SplitAndTrim(m.fieldsEx, ",")) 68 ) 69 if m.fields != "*" { 70 // Filter custom fields with fieldEx. 71 fieldsArray = make([]string, 0, 8) 72 for _, v := range gstr.SplitAndTrim(m.fields, ",") { 73 fieldsArray = append(fieldsArray, v[gstr.PosR(v, "-")+1:]) 74 } 75 } else { 76 if gstr.Contains(m.tables, " ") { 77 panic("function FieldsEx supports only single table operations") 78 } 79 // Filter table fields with fieldEx. 80 tableFields, err := m.TableFields(m.tablesInit) 81 if err != nil { 82 panic(err) 83 } 84 if len(tableFields) == 0 { 85 panic(fmt.Sprintf(`empty table fields for table "%s"`, m.tables)) 86 } 87 fieldsArray = make([]string, len(tableFields)) 88 for k, v := range tableFields { 89 fieldsArray[v.Index] = k 90 } 91 } 92 newFields := "" 93 for _, k := range fieldsArray { 94 if fieldsExSet.Contains(k) { 95 continue 96 } 97 if len(newFields) > 0 { 98 newFields += "," 99 } 100 newFields += m.db.GetCore().QuoteWord(k) 101 } 102 return newFields 103 } 104 105 // Chunk iterates the query result with given `size` and `handler` function. 106 func (m *Model) Chunk(size int, handler ChunkHandler) { 107 page := m.start 108 if page <= 0 { 109 page = 1 110 } 111 model := m 112 for { 113 model = model.Page(page, size) 114 data, err := model.All() 115 if err != nil { 116 handler(nil, err) 117 break 118 } 119 if len(data) == 0 { 120 break 121 } 122 if handler(data, err) == false { 123 break 124 } 125 if len(data) < size { 126 break 127 } 128 page++ 129 } 130 } 131 132 // One retrieves one record from table and returns the result as map type. 133 // It returns nil if there's no record retrieved with the given conditions from table. 134 // 135 // The optional parameter `where` is the same as the parameter of Model.Where function, 136 // see Model.Where. 137 func (m *Model) One(where ...interface{}) (Record, error) { 138 if len(where) > 0 { 139 return m.Where(where[0], where[1:]...).One() 140 } 141 all, err := m.doGetAll(true) 142 if err != nil { 143 return nil, err 144 } 145 if len(all) > 0 { 146 return all[0], nil 147 } 148 return nil, nil 149 } 150 151 // Value retrieves a specified record value from table and returns the result as interface type. 152 // It returns nil if there's no record found with the given conditions from table. 153 // 154 // If the optional parameter `fieldsAndWhere` is given, the fieldsAndWhere[0] is the selected fields 155 // and fieldsAndWhere[1:] is treated as where condition fields. 156 // Also see Model.Fields and Model.Where functions. 157 func (m *Model) Value(fieldsAndWhere ...interface{}) (Value, error) { 158 if len(fieldsAndWhere) > 0 { 159 if len(fieldsAndWhere) > 2 { 160 return m.Fields(gconv.String(fieldsAndWhere[0])).Where(fieldsAndWhere[1], fieldsAndWhere[2:]...).Value() 161 } else if len(fieldsAndWhere) == 2 { 162 return m.Fields(gconv.String(fieldsAndWhere[0])).Where(fieldsAndWhere[1]).Value() 163 } else { 164 return m.Fields(gconv.String(fieldsAndWhere[0])).Value() 165 } 166 } 167 one, err := m.One() 168 if err != nil { 169 return gvar.New(nil), err 170 } 171 for _, v := range one { 172 return v, nil 173 } 174 return gvar.New(nil), nil 175 } 176 177 // Array queries and returns data values as slice from database. 178 // Note that if there are multiple columns in the result, it returns just one column values randomly. 179 // 180 // If the optional parameter `fieldsAndWhere` is given, the fieldsAndWhere[0] is the selected fields 181 // and fieldsAndWhere[1:] is treated as where condition fields. 182 // Also see Model.Fields and Model.Where functions. 183 func (m *Model) Array(fieldsAndWhere ...interface{}) ([]Value, error) { 184 if len(fieldsAndWhere) > 0 { 185 if len(fieldsAndWhere) > 2 { 186 return m.Fields(gconv.String(fieldsAndWhere[0])).Where(fieldsAndWhere[1], fieldsAndWhere[2:]...).Array() 187 } else if len(fieldsAndWhere) == 2 { 188 return m.Fields(gconv.String(fieldsAndWhere[0])).Where(fieldsAndWhere[1]).Array() 189 } else { 190 return m.Fields(gconv.String(fieldsAndWhere[0])).Array() 191 } 192 } 193 all, err := m.All() 194 if err != nil { 195 return nil, err 196 } 197 return all.Array(), nil 198 } 199 200 // Struct retrieves one record from table and converts it into given struct. 201 // The parameter `pointer` should be type of *struct/**struct. If type **struct is given, 202 // it can create the struct internally during converting. 203 // 204 // Deprecated, use Scan instead. 205 func (m *Model) Struct(pointer interface{}, where ...interface{}) error { 206 return m.doStruct(pointer, where...) 207 } 208 209 // Struct retrieves one record from table and converts it into given struct. 210 // The parameter `pointer` should be type of *struct/**struct. If type **struct is given, 211 // it can create the struct internally during converting. 212 // 213 // The optional parameter `where` is the same as the parameter of Model.Where function, 214 // see Model.Where. 215 // 216 // Note that it returns sql.ErrNoRows if the given parameter `pointer` pointed to a variable that has 217 // default value and there's no record retrieved with the given conditions from table. 218 // 219 // Example: 220 // user := new(User) 221 // err := db.Model("user").Where("id", 1).Scan(user) 222 // 223 // user := (*User)(nil) 224 // err := db.Model("user").Where("id", 1).Scan(&user) 225 func (m *Model) doStruct(pointer interface{}, where ...interface{}) error { 226 model := m 227 // Auto selecting fields by struct attributes. 228 if model.fieldsEx == "" && (model.fields == "" || model.fields == "*") { 229 model = m.Fields(pointer) 230 } 231 one, err := model.One(where...) 232 if err != nil { 233 return err 234 } 235 if err = one.Struct(pointer); err != nil { 236 return err 237 } 238 return model.doWithScanStruct(pointer) 239 } 240 241 // Structs retrieves records from table and converts them into given struct slice. 242 // The parameter `pointer` should be type of *[]struct/*[]*struct. It can create and fill the struct 243 // slice internally during converting. 244 // 245 // Deprecated, use Scan instead. 246 func (m *Model) Structs(pointer interface{}, where ...interface{}) error { 247 return m.doStructs(pointer, where...) 248 } 249 250 // Structs retrieves records from table and converts them into given struct slice. 251 // The parameter `pointer` should be type of *[]struct/*[]*struct. It can create and fill the struct 252 // slice internally during converting. 253 // 254 // The optional parameter `where` is the same as the parameter of Model.Where function, 255 // see Model.Where. 256 // 257 // Note that it returns sql.ErrNoRows if the given parameter `pointer` pointed to a variable that has 258 // default value and there's no record retrieved with the given conditions from table. 259 // 260 // Example: 261 // users := ([]User)(nil) 262 // err := db.Model("user").Scan(&users) 263 // 264 // users := ([]*User)(nil) 265 // err := db.Model("user").Scan(&users) 266 func (m *Model) doStructs(pointer interface{}, where ...interface{}) error { 267 model := m 268 // Auto selecting fields by struct attributes. 269 if model.fieldsEx == "" && (model.fields == "" || model.fields == "*") { 270 model = m.Fields( 271 reflect.New( 272 reflect.ValueOf(pointer).Elem().Type().Elem(), 273 ).Interface(), 274 ) 275 } 276 all, err := model.All(where...) 277 if err != nil { 278 return err 279 } 280 if err = all.Structs(pointer); err != nil { 281 return err 282 } 283 return model.doWithScanStructs(pointer) 284 } 285 286 // Scan automatically calls Struct or Structs function according to the type of parameter `pointer`. 287 // It calls function doStruct if `pointer` is type of *struct/**struct. 288 // It calls function doStructs if `pointer` is type of *[]struct/*[]*struct. 289 // 290 // The optional parameter `where` is the same as the parameter of Model.Where function, see Model.Where. 291 // 292 // Note that it returns sql.ErrNoRows if the given parameter `pointer` pointed to a variable that has 293 // default value and there's no record retrieved with the given conditions from table. 294 // 295 // Example: 296 // user := new(User) 297 // err := db.Model("user").Where("id", 1).Scan(user) 298 // 299 // user := (*User)(nil) 300 // err := db.Model("user").Where("id", 1).Scan(&user) 301 // 302 // users := ([]User)(nil) 303 // err := db.Model("user").Scan(&users) 304 // 305 // users := ([]*User)(nil) 306 // err := db.Model("user").Scan(&users) 307 func (m *Model) Scan(pointer interface{}, where ...interface{}) error { 308 var ( 309 reflectValue reflect.Value 310 reflectKind reflect.Kind 311 ) 312 if v, ok := pointer.(reflect.Value); ok { 313 reflectValue = v 314 } else { 315 reflectValue = reflect.ValueOf(pointer) 316 } 317 318 reflectKind = reflectValue.Kind() 319 if reflectKind != reflect.Ptr { 320 return gerror.NewCode(gcode.CodeInvalidParameter, `the parameter "pointer" for function Scan should type of pointer`) 321 } 322 for reflectKind == reflect.Ptr { 323 reflectValue = reflectValue.Elem() 324 reflectKind = reflectValue.Kind() 325 } 326 327 switch reflectKind { 328 case reflect.Slice, reflect.Array: 329 return m.doStructs(pointer, where...) 330 331 case reflect.Struct, reflect.Invalid: 332 return m.doStruct(pointer, where...) 333 334 default: 335 return gerror.NewCode( 336 gcode.CodeInvalidParameter, 337 `element of parameter "pointer" for function Scan should type of struct/*struct/[]struct/[]*struct`, 338 ) 339 } 340 } 341 342 // ScanList converts `r` to struct slice which contains other complex struct attributes. 343 // Note that the parameter `listPointer` should be type of *[]struct/*[]*struct. 344 // Usage example: 345 // 346 // type Entity struct { 347 // User *EntityUser 348 // UserDetail *EntityUserDetail 349 // UserScores []*EntityUserScores 350 // } 351 // var users []*Entity 352 // or 353 // var users []Entity 354 // 355 // ScanList(&users, "User") 356 // ScanList(&users, "UserDetail", "User", "uid:Uid") 357 // ScanList(&users, "UserScores", "User", "uid:Uid") 358 // The parameters "User"/"UserDetail"/"UserScores" in the example codes specify the target attribute struct 359 // that current result will be bound to. 360 // The "uid" in the example codes is the table field name of the result, and the "Uid" is the relational 361 // struct attribute name. It automatically calculates the HasOne/HasMany relationship with given `relation` 362 // parameter. 363 // See the example or unit testing cases for clear understanding for this function. 364 func (m *Model) ScanList(listPointer interface{}, attributeName string, relation ...string) (err error) { 365 result, err := m.All() 366 if err != nil { 367 return err 368 } 369 return doScanList(m, result, listPointer, attributeName, relation...) 370 } 371 372 // Count does "SELECT COUNT(x) FROM ..." statement for the model. 373 // The optional parameter `where` is the same as the parameter of Model.Where function, 374 // see Model.Where. 375 func (m *Model) Count(where ...interface{}) (int, error) { 376 if len(where) > 0 { 377 return m.Where(where[0], where[1:]...).Count() 378 } 379 var ( 380 sqlWithHolder, holderArgs = m.getFormattedSqlAndArgs(queryTypeCount, false) 381 list, err = m.doGetAllBySql(sqlWithHolder, holderArgs...) 382 ) 383 if err != nil { 384 return 0, err 385 } 386 if len(list) > 0 { 387 for _, v := range list[0] { 388 return v.Int(), nil 389 } 390 } 391 return 0, nil 392 } 393 394 // CountColumn does "SELECT COUNT(x) FROM ..." statement for the model. 395 func (m *Model) CountColumn(column string) (int, error) { 396 if len(column) == 0 { 397 return 0, nil 398 } 399 return m.Fields(column).Count() 400 } 401 402 // Min does "SELECT MIN(x) FROM ..." statement for the model. 403 func (m *Model) Min(column string) (float64, error) { 404 if len(column) == 0 { 405 return 0, nil 406 } 407 value, err := m.Fields(fmt.Sprintf(`MIN(%s)`, m.db.GetCore().QuoteWord(column))).Value() 408 if err != nil { 409 return 0, err 410 } 411 return value.Float64(), err 412 } 413 414 // Max does "SELECT MAX(x) FROM ..." statement for the model. 415 func (m *Model) Max(column string) (float64, error) { 416 if len(column) == 0 { 417 return 0, nil 418 } 419 value, err := m.Fields(fmt.Sprintf(`MAX(%s)`, m.db.GetCore().QuoteWord(column))).Value() 420 if err != nil { 421 return 0, err 422 } 423 return value.Float64(), err 424 } 425 426 // Avg does "SELECT AVG(x) FROM ..." statement for the model. 427 func (m *Model) Avg(column string) (float64, error) { 428 if len(column) == 0 { 429 return 0, nil 430 } 431 value, err := m.Fields(fmt.Sprintf(`AVG(%s)`, m.db.GetCore().QuoteWord(column))).Value() 432 if err != nil { 433 return 0, err 434 } 435 return value.Float64(), err 436 } 437 438 // Sum does "SELECT SUM(x) FROM ..." statement for the model. 439 func (m *Model) Sum(column string) (float64, error) { 440 if len(column) == 0 { 441 return 0, nil 442 } 443 value, err := m.Fields(fmt.Sprintf(`SUM(%s)`, m.db.GetCore().QuoteWord(column))).Value() 444 if err != nil { 445 return 0, err 446 } 447 return value.Float64(), err 448 } 449 450 // FindOne retrieves and returns a single Record by Model.WherePri and Model.One. 451 // Also see Model.WherePri and Model.One. 452 func (m *Model) FindOne(where ...interface{}) (Record, error) { 453 if len(where) > 0 { 454 return m.WherePri(where[0], where[1:]...).One() 455 } 456 return m.One() 457 } 458 459 // FindAll retrieves and returns Result by by Model.WherePri and Model.All. 460 // Also see Model.WherePri and Model.All. 461 func (m *Model) FindAll(where ...interface{}) (Result, error) { 462 if len(where) > 0 { 463 return m.WherePri(where[0], where[1:]...).All() 464 } 465 return m.All() 466 } 467 468 // FindValue retrieves and returns single field value by Model.WherePri and Model.Value. 469 // Also see Model.WherePri and Model.Value. 470 func (m *Model) FindValue(fieldsAndWhere ...interface{}) (Value, error) { 471 if len(fieldsAndWhere) >= 2 { 472 return m.WherePri(fieldsAndWhere[1], fieldsAndWhere[2:]...).Fields(gconv.String(fieldsAndWhere[0])).Value() 473 } 474 if len(fieldsAndWhere) == 1 { 475 return m.Fields(gconv.String(fieldsAndWhere[0])).Value() 476 } 477 return m.Value() 478 } 479 480 // FindArray queries and returns data values as slice from database. 481 // Note that if there are multiple columns in the result, it returns just one column values randomly. 482 // Also see Model.WherePri and Model.Value. 483 func (m *Model) FindArray(fieldsAndWhere ...interface{}) ([]Value, error) { 484 if len(fieldsAndWhere) >= 2 { 485 return m.WherePri(fieldsAndWhere[1], fieldsAndWhere[2:]...).Fields(gconv.String(fieldsAndWhere[0])).Array() 486 } 487 if len(fieldsAndWhere) == 1 { 488 return m.Fields(gconv.String(fieldsAndWhere[0])).Array() 489 } 490 return m.Array() 491 } 492 493 // FindCount retrieves and returns the record number by Model.WherePri and Model.Count. 494 // Also see Model.WherePri and Model.Count. 495 func (m *Model) FindCount(where ...interface{}) (int, error) { 496 if len(where) > 0 { 497 return m.WherePri(where[0], where[1:]...).Count() 498 } 499 return m.Count() 500 } 501 502 // FindScan retrieves and returns the record/records by Model.WherePri and Model.Scan. 503 // Also see Model.WherePri and Model.Scan. 504 func (m *Model) FindScan(pointer interface{}, where ...interface{}) error { 505 if len(where) > 0 { 506 return m.WherePri(where[0], where[1:]...).Scan(pointer) 507 } 508 return m.Scan(pointer) 509 } 510 511 // Union does "(SELECT xxx FROM xxx) UNION (SELECT xxx FROM xxx) ..." statement for the model. 512 func (m *Model) Union(unions ...*Model) *Model { 513 return m.db.Union(unions...) 514 } 515 516 // UnionAll does "(SELECT xxx FROM xxx) UNION ALL (SELECT xxx FROM xxx) ..." statement for the model. 517 func (m *Model) UnionAll(unions ...*Model) *Model { 518 return m.db.UnionAll(unions...) 519 } 520 521 // doGetAllBySql does the select statement on the database. 522 func (m *Model) doGetAllBySql(sql string, args ...interface{}) (result Result, err error) { 523 cacheKey := "" 524 cacheObj := m.db.GetCache().Ctx(m.GetCtx()) 525 // Retrieve from cache. 526 if m.cacheEnabled && m.tx == nil { 527 cacheKey = m.cacheName 528 if len(cacheKey) == 0 { 529 cacheKey = sql + ", @PARAMS:" + gconv.String(args) 530 } 531 if v, _ := cacheObj.GetVar(cacheKey); !v.IsNil() { 532 if result, ok := v.Val().(Result); ok { 533 // In-memory cache. 534 return result, nil 535 } else { 536 // Other cache, it needs conversion. 537 var result Result 538 if err = json.UnmarshalUseNumber(v.Bytes(), &result); err != nil { 539 return nil, err 540 } else { 541 return result, nil 542 } 543 } 544 } 545 } 546 result, err = m.db.DoGetAll( 547 m.GetCtx(), m.getLink(false), sql, m.mergeArguments(args)..., 548 ) 549 // Cache the result. 550 if cacheKey != "" && err == nil { 551 if m.cacheDuration < 0 { 552 if _, err := cacheObj.Remove(cacheKey); err != nil { 553 intlog.Error(m.GetCtx(), err) 554 } 555 } else { 556 // In case of Cache Penetration. 557 if result == nil { 558 result = Result{} 559 } 560 if err := cacheObj.Set(cacheKey, result, m.cacheDuration); err != nil { 561 intlog.Error(m.GetCtx(), err) 562 } 563 } 564 } 565 return result, err 566 } 567 568 func (m *Model) getFormattedSqlAndArgs(queryType int, limit1 bool) (sqlWithHolder string, holderArgs []interface{}) { 569 switch queryType { 570 case queryTypeCount: 571 countFields := "COUNT(1)" 572 if m.fields != "" && m.fields != "*" { 573 // DO NOT quote the m.fields here, in case of fields like: 574 // DISTINCT t.user_id uid 575 countFields = fmt.Sprintf(`COUNT(%s%s)`, m.distinct, m.fields) 576 } 577 // Raw SQL Model. 578 if m.rawSql != "" { 579 sqlWithHolder = fmt.Sprintf("SELECT %s FROM (%s) AS T", countFields, m.rawSql) 580 return sqlWithHolder, nil 581 } 582 conditionWhere, conditionExtra, conditionArgs := m.formatCondition(false, true) 583 sqlWithHolder = fmt.Sprintf("SELECT %s FROM %s%s", countFields, m.tables, conditionWhere+conditionExtra) 584 if len(m.groupBy) > 0 { 585 sqlWithHolder = fmt.Sprintf("SELECT COUNT(1) FROM (%s) count_alias", sqlWithHolder) 586 } 587 return sqlWithHolder, conditionArgs 588 589 default: 590 conditionWhere, conditionExtra, conditionArgs := m.formatCondition(limit1, false) 591 // Raw SQL Model, especially for UNION/UNION ALL featured SQL. 592 if m.rawSql != "" { 593 sqlWithHolder = fmt.Sprintf( 594 "%s%s", 595 m.rawSql, 596 conditionWhere+conditionExtra, 597 ) 598 return sqlWithHolder, conditionArgs 599 } 600 // DO NOT quote the m.fields where, in case of fields like: 601 // DISTINCT t.user_id uid 602 sqlWithHolder = fmt.Sprintf( 603 "SELECT %s%s FROM %s%s", 604 m.distinct, 605 m.getFieldsFiltered(), 606 m.tables, 607 conditionWhere+conditionExtra, 608 ) 609 return sqlWithHolder, conditionArgs 610 } 611 }