github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/go-xorm/xorm/engine.go (about) 1 // Copyright 2015 The Xorm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package xorm 6 7 import ( 8 "bufio" 9 "bytes" 10 "database/sql" 11 "encoding/gob" 12 "errors" 13 "fmt" 14 "io" 15 "os" 16 "reflect" 17 "strconv" 18 "strings" 19 "sync" 20 "time" 21 22 "github.com/insionng/yougam/libraries/go-xorm/core" 23 ) 24 25 // Engine is the major struct of xorm, it means a database manager. 26 // Commonly, an application only need one engine 27 type Engine struct { 28 db *core.DB 29 dialect core.Dialect 30 31 ColumnMapper core.IMapper 32 TableMapper core.IMapper 33 TagIdentifier string 34 Tables map[reflect.Type]*core.Table 35 36 mutex *sync.RWMutex 37 Cacher core.Cacher 38 39 showSQL bool 40 showExecTime bool 41 42 logger core.ILogger 43 TZLocation *time.Location 44 DatabaseTZ *time.Location // The timezone of the database 45 46 disableGlobalCache bool 47 } 48 49 // ShowSQL show SQL statment or not on logger if log level is great than INFO 50 func (engine *Engine) ShowSQL(show ...bool) { 51 engine.logger.ShowSQL(show...) 52 if len(show) == 0 { 53 engine.showSQL = true 54 } else { 55 engine.showSQL = show[0] 56 } 57 } 58 59 // ShowExecTime show SQL statment and execute time or not on logger if log level is great than INFO 60 func (engine *Engine) ShowExecTime(show ...bool) { 61 if len(show) == 0 { 62 engine.showExecTime = true 63 } else { 64 engine.showExecTime = show[0] 65 } 66 } 67 68 // Logger return the logger interface 69 func (engine *Engine) Logger() core.ILogger { 70 return engine.logger 71 } 72 73 // SetLogger set the new logger 74 func (engine *Engine) SetLogger(logger core.ILogger) { 75 engine.logger = logger 76 engine.dialect.SetLogger(logger) 77 } 78 79 // SetDisableGlobalCache disable global cache or not 80 func (engine *Engine) SetDisableGlobalCache(disable bool) { 81 if engine.disableGlobalCache != disable { 82 engine.disableGlobalCache = disable 83 } 84 } 85 86 // DriverName return the current sql driver's name 87 func (engine *Engine) DriverName() string { 88 return engine.dialect.DriverName() 89 } 90 91 // DataSourceName return the current connection string 92 func (engine *Engine) DataSourceName() string { 93 return engine.dialect.DataSourceName() 94 } 95 96 // SetMapper set the name mapping rules 97 func (engine *Engine) SetMapper(mapper core.IMapper) { 98 engine.SetTableMapper(mapper) 99 engine.SetColumnMapper(mapper) 100 } 101 102 // SetTableMapper set the table name mapping rule 103 func (engine *Engine) SetTableMapper(mapper core.IMapper) { 104 engine.TableMapper = mapper 105 } 106 107 // SetColumnMapper set the column name mapping rule 108 func (engine *Engine) SetColumnMapper(mapper core.IMapper) { 109 engine.ColumnMapper = mapper 110 } 111 112 // SupportInsertMany If engine's database support batch insert records like 113 // "insert into user values (name, age), (name, age)". 114 // When the return is ture, then engine.Insert(&users) will 115 // generate batch sql and exeute. 116 func (engine *Engine) SupportInsertMany() bool { 117 return engine.dialect.SupportInsertMany() 118 } 119 120 // QuoteStr Engine's database use which charactor as quote. 121 // mysql, sqlite use ` and postgres use " 122 func (engine *Engine) QuoteStr() string { 123 return engine.dialect.QuoteStr() 124 } 125 126 // Quote Use QuoteStr quote the string sql 127 func (engine *Engine) Quote(value string) string { 128 value = strings.TrimSpace(value) 129 if len(value) == 0 { 130 return value 131 } 132 133 if string(value[0]) == engine.dialect.QuoteStr() || value[0] == '`' { 134 return value 135 } 136 137 value = strings.Replace(value, ".", engine.dialect.QuoteStr()+"."+engine.dialect.QuoteStr(), -1) 138 139 return engine.dialect.QuoteStr() + value + engine.dialect.QuoteStr() 140 } 141 142 // QuoteTo quotes string and writes into the buffer 143 func (engine *Engine) QuoteTo(buf *bytes.Buffer, value string) { 144 145 if buf == nil { 146 return 147 } 148 149 value = strings.TrimSpace(value) 150 if value == "" { 151 return 152 } 153 154 if string(value[0]) == engine.dialect.QuoteStr() || value[0] == '`' { 155 buf.WriteString(value) 156 return 157 } 158 159 value = strings.Replace(value, ".", engine.dialect.QuoteStr()+"."+engine.dialect.QuoteStr(), -1) 160 161 buf.WriteString(engine.dialect.QuoteStr()) 162 buf.WriteString(value) 163 buf.WriteString(engine.dialect.QuoteStr()) 164 } 165 166 func (engine *Engine) quote(sql string) string { 167 return engine.dialect.QuoteStr() + sql + engine.dialect.QuoteStr() 168 } 169 170 // SqlType will be depracated, please use SQLType instead 171 func (engine *Engine) SqlType(c *core.Column) string { 172 return engine.dialect.SqlType(c) 173 } 174 175 // SQLType A simple wrapper to dialect's core.SqlType method 176 func (engine *Engine) SQLType(c *core.Column) string { 177 return engine.dialect.SqlType(c) 178 } 179 180 // AutoIncrStr Database's autoincrement statement 181 func (engine *Engine) AutoIncrStr() string { 182 return engine.dialect.AutoIncrStr() 183 } 184 185 // SetMaxOpenConns is only available for go 1.2+ 186 func (engine *Engine) SetMaxOpenConns(conns int) { 187 engine.db.SetMaxOpenConns(conns) 188 } 189 190 // SetMaxIdleConns set the max idle connections on pool, default is 2 191 func (engine *Engine) SetMaxIdleConns(conns int) { 192 engine.db.SetMaxIdleConns(conns) 193 } 194 195 // SetDefaultCacher set the default cacher. Xorm's default not enable cacher. 196 func (engine *Engine) SetDefaultCacher(cacher core.Cacher) { 197 engine.Cacher = cacher 198 } 199 200 // NoCache If you has set default cacher, and you want temporilly stop use cache, 201 // you can use NoCache() 202 func (engine *Engine) NoCache() *Session { 203 session := engine.NewSession() 204 session.IsAutoClose = true 205 return session.NoCache() 206 } 207 208 // NoCascade If you do not want to auto cascade load object 209 func (engine *Engine) NoCascade() *Session { 210 session := engine.NewSession() 211 session.IsAutoClose = true 212 return session.NoCascade() 213 } 214 215 // MapCacher Set a table use a special cacher 216 func (engine *Engine) MapCacher(bean interface{}, cacher core.Cacher) { 217 v := rValue(bean) 218 tb := engine.autoMapType(v) 219 tb.Cacher = cacher 220 } 221 222 // NewDB provides an interface to operate database directly 223 func (engine *Engine) NewDB() (*core.DB, error) { 224 return core.OpenDialect(engine.dialect) 225 } 226 227 // DB return the wrapper of sql.DB 228 func (engine *Engine) DB() *core.DB { 229 return engine.db 230 } 231 232 // Dialect return database dialect 233 func (engine *Engine) Dialect() core.Dialect { 234 return engine.dialect 235 } 236 237 // NewSession New a session 238 func (engine *Engine) NewSession() *Session { 239 session := &Session{Engine: engine} 240 session.Init() 241 return session 242 } 243 244 // Close the engine 245 func (engine *Engine) Close() error { 246 return engine.db.Close() 247 } 248 249 // Ping tests if database is alive 250 func (engine *Engine) Ping() error { 251 session := engine.NewSession() 252 defer session.Close() 253 engine.logger.Infof("PING DATABASE %v", engine.DriverName()) 254 return session.Ping() 255 } 256 257 // logging sql 258 func (engine *Engine) logSQL(sqlStr string, sqlArgs ...interface{}) { 259 if engine.showSQL && !engine.showExecTime { 260 if len(sqlArgs) > 0 { 261 engine.logger.Infof("[sql] %v [args] %v", sqlStr, sqlArgs) 262 } else { 263 engine.logger.Infof("[sql] %v", sqlStr) 264 } 265 } 266 } 267 268 func (engine *Engine) logSQLQueryTime(sqlStr string, args []interface{}, executionBlock func() (*core.Stmt, *core.Rows, error)) (*core.Stmt, *core.Rows, error) { 269 if engine.showSQL && engine.showExecTime { 270 b4ExecTime := time.Now() 271 stmt, res, err := executionBlock() 272 execDuration := time.Since(b4ExecTime) 273 if len(args) > 0 { 274 engine.logger.Infof("[sql] %s [args] %v - took: %v", sqlStr, args, execDuration) 275 } else { 276 engine.logger.Infof("[sql] %s - took: %v", sqlStr, execDuration) 277 } 278 return stmt, res, err 279 } 280 return executionBlock() 281 } 282 283 func (engine *Engine) logSQLExecutionTime(sqlStr string, args []interface{}, executionBlock func() (sql.Result, error)) (sql.Result, error) { 284 if engine.showSQL && engine.showExecTime { 285 b4ExecTime := time.Now() 286 res, err := executionBlock() 287 execDuration := time.Since(b4ExecTime) 288 if len(args) > 0 { 289 engine.logger.Infof("[sql] %s [args] %v - took: %v", sqlStr, args, execDuration) 290 } else { 291 engine.logger.Infof("[sql] %s - took: %v", sqlStr, execDuration) 292 } 293 return res, err 294 } 295 return executionBlock() 296 } 297 298 // Sql will be depracated, please use SQL instead 299 func (engine *Engine) Sql(querystring string, args ...interface{}) *Session { 300 return engine.SQL(querystring, args...) 301 } 302 303 // SQL method let's you manualy write raw SQL and operate 304 // For example: 305 // 306 // engine.SQL("select * from user").Find(&users) 307 // 308 // This code will execute "select * from user" and set the records to users 309 func (engine *Engine) SQL(query interface{}, args ...interface{}) *Session { 310 session := engine.NewSession() 311 session.IsAutoClose = true 312 return session.SQL(query, args...) 313 } 314 315 // NoAutoTime Default if your struct has "created" or "updated" filed tag, the fields 316 // will automatically be filled with current time when Insert or Update 317 // invoked. Call NoAutoTime if you dont' want to fill automatically. 318 func (engine *Engine) NoAutoTime() *Session { 319 session := engine.NewSession() 320 session.IsAutoClose = true 321 return session.NoAutoTime() 322 } 323 324 // NoAutoCondition disable auto generate Where condition from bean or not 325 func (engine *Engine) NoAutoCondition(no ...bool) *Session { 326 session := engine.NewSession() 327 session.IsAutoClose = true 328 return session.NoAutoCondition(no...) 329 } 330 331 // DBMetas Retrieve all tables, columns, indexes' informations from database. 332 func (engine *Engine) DBMetas() ([]*core.Table, error) { 333 tables, err := engine.dialect.GetTables() 334 if err != nil { 335 return nil, err 336 } 337 338 for _, table := range tables { 339 colSeq, cols, err := engine.dialect.GetColumns(table.Name) 340 if err != nil { 341 return nil, err 342 } 343 for _, name := range colSeq { 344 table.AddColumn(cols[name]) 345 } 346 //table.Columns = cols 347 //table.ColumnsSeq = colSeq 348 indexes, err := engine.dialect.GetIndexes(table.Name) 349 if err != nil { 350 return nil, err 351 } 352 table.Indexes = indexes 353 354 for _, index := range indexes { 355 for _, name := range index.Cols { 356 if col := table.GetColumn(name); col != nil { 357 col.Indexes[index.Name] = index.Type 358 } else { 359 return nil, fmt.Errorf("Unknown col %s in indexe %v of table %v, columns %v", name, index.Name, table.Name, table.ColumnsSeq()) 360 } 361 } 362 } 363 } 364 return tables, nil 365 } 366 367 // DumpAllToFile dump database all table structs and data to a file 368 func (engine *Engine) DumpAllToFile(fp string) error { 369 f, err := os.Create(fp) 370 if err != nil { 371 return err 372 } 373 defer f.Close() 374 return engine.DumpAll(f) 375 } 376 377 // DumpAll dump database all table structs and data to w 378 func (engine *Engine) DumpAll(w io.Writer) error { 379 return engine.dumpAll(w, engine.dialect.DBType()) 380 } 381 382 // DumpTablesToFile dump specified tables to SQL file. 383 func (engine *Engine) DumpTablesToFile(tables []*core.Table, fp string, tp ...core.DbType) error { 384 f, err := os.Create(fp) 385 if err != nil { 386 return err 387 } 388 defer f.Close() 389 return engine.DumpTables(tables, f, tp...) 390 } 391 392 // DumpTables dump specify tables to io.Writer 393 func (engine *Engine) DumpTables(tables []*core.Table, w io.Writer, tp ...core.DbType) error { 394 return engine.dumpTables(tables, w, tp...) 395 } 396 397 func (engine *Engine) tableName(beanOrTableName interface{}) (string, error) { 398 v := rValue(beanOrTableName) 399 if v.Type().Kind() == reflect.String { 400 return beanOrTableName.(string), nil 401 } else if v.Type().Kind() == reflect.Struct { 402 return engine.tbName(v), nil 403 } 404 return "", errors.New("bean should be a struct or struct's point") 405 } 406 407 func (engine *Engine) tbName(v reflect.Value) string { 408 if tb, ok := v.Interface().(TableName); ok { 409 return tb.TableName() 410 } 411 412 if v.Type().Kind() == reflect.Ptr { 413 if tb, ok := reflect.Indirect(v).Interface().(TableName); ok { 414 return tb.TableName() 415 } 416 } else if v.CanAddr() { 417 if tb, ok := v.Addr().Interface().(TableName); ok { 418 return tb.TableName() 419 } 420 } 421 return engine.TableMapper.Obj2Table(reflect.Indirect(v).Type().Name()) 422 } 423 424 // DumpAll dump database all table structs and data to w with specify db type 425 func (engine *Engine) dumpAll(w io.Writer, tp ...core.DbType) error { 426 tables, err := engine.DBMetas() 427 if err != nil { 428 return err 429 } 430 431 var dialect core.Dialect 432 if len(tp) == 0 { 433 dialect = engine.dialect 434 } else { 435 dialect = core.QueryDialect(tp[0]) 436 if dialect == nil { 437 return errors.New("Unsupported database type.") 438 } 439 dialect.Init(nil, engine.dialect.URI(), "", "") 440 } 441 442 _, err = io.WriteString(w, fmt.Sprintf("/*Generated by xorm v%s %s*/\n\n", 443 Version, time.Now().In(engine.TZLocation).Format("2006-01-02 15:04:05"))) 444 if err != nil { 445 return err 446 } 447 448 for i, table := range tables { 449 if i > 0 { 450 _, err = io.WriteString(w, "\n") 451 if err != nil { 452 return err 453 } 454 } 455 _, err = io.WriteString(w, dialect.CreateTableSql(table, "", table.StoreEngine, "")+";\n") 456 if err != nil { 457 return err 458 } 459 for _, index := range table.Indexes { 460 _, err = io.WriteString(w, dialect.CreateIndexSql(table.Name, index)+";\n") 461 if err != nil { 462 return err 463 } 464 } 465 466 rows, err := engine.DB().Query("SELECT * FROM " + engine.Quote(table.Name)) 467 if err != nil { 468 return err 469 } 470 defer rows.Close() 471 472 cols, err := rows.Columns() 473 if err != nil { 474 return err 475 } 476 if len(cols) == 0 { 477 continue 478 } 479 for rows.Next() { 480 dest := make([]interface{}, len(cols)) 481 err = rows.ScanSlice(&dest) 482 if err != nil { 483 return err 484 } 485 486 _, err = io.WriteString(w, "INSERT INTO "+dialect.Quote(table.Name)+" ("+dialect.Quote(strings.Join(cols, dialect.Quote(", ")))+") VALUES (") 487 if err != nil { 488 return err 489 } 490 491 var temp string 492 for i, d := range dest { 493 col := table.GetColumn(cols[i]) 494 if d == nil { 495 temp += ", NULL" 496 } else if col.SQLType.IsText() || col.SQLType.IsTime() { 497 var v = fmt.Sprintf("%s", d) 498 temp += ", '" + strings.Replace(v, "'", "''", -1) + "'" 499 } else if col.SQLType.IsBlob() { 500 if reflect.TypeOf(d).Kind() == reflect.Slice { 501 temp += fmt.Sprintf(", %s", dialect.FormatBytes(d.([]byte))) 502 } else if reflect.TypeOf(d).Kind() == reflect.String { 503 temp += fmt.Sprintf(", '%s'", d.(string)) 504 } 505 } else if col.SQLType.IsNumeric() { 506 switch reflect.TypeOf(d).Kind() { 507 case reflect.Slice: 508 temp += fmt.Sprintf(", %s", string(d.([]byte))) 509 default: 510 temp += fmt.Sprintf(", %v", d) 511 } 512 } else { 513 s := fmt.Sprintf("%v", d) 514 if strings.Contains(s, ":") || strings.Contains(s, "-") { 515 temp += fmt.Sprintf(", '%s'", s) 516 } else { 517 temp += fmt.Sprintf(", %s", s) 518 } 519 } 520 } 521 _, err = io.WriteString(w, temp[2:]+");\n") 522 if err != nil { 523 return err 524 } 525 } 526 } 527 return nil 528 } 529 530 // DumpAll dump database all table structs and data to w with specify db type 531 func (engine *Engine) dumpTables(tables []*core.Table, w io.Writer, tp ...core.DbType) error { 532 var dialect core.Dialect 533 if len(tp) == 0 { 534 dialect = engine.dialect 535 } else { 536 dialect = core.QueryDialect(tp[0]) 537 if dialect == nil { 538 return errors.New("Unsupported database type.") 539 } 540 dialect.Init(nil, engine.dialect.URI(), "", "") 541 } 542 543 _, err := io.WriteString(w, fmt.Sprintf("/*Generated by xorm v%s %s, from %s to %s*/\n\n", 544 Version, time.Now().In(engine.TZLocation).Format("2006-01-02 15:04:05"), engine.dialect.DBType(), dialect.DBType())) 545 if err != nil { 546 return err 547 } 548 549 for i, table := range tables { 550 if i > 0 { 551 _, err = io.WriteString(w, "\n") 552 if err != nil { 553 return err 554 } 555 } 556 _, err = io.WriteString(w, dialect.CreateTableSql(table, "", table.StoreEngine, "")+";\n") 557 if err != nil { 558 return err 559 } 560 for _, index := range table.Indexes { 561 _, err = io.WriteString(w, dialect.CreateIndexSql(table.Name, index)+";\n") 562 if err != nil { 563 return err 564 } 565 } 566 567 rows, err := engine.DB().Query("SELECT * FROM " + engine.Quote(table.Name)) 568 if err != nil { 569 return err 570 } 571 defer rows.Close() 572 573 cols, err := rows.Columns() 574 if err != nil { 575 return err 576 } 577 if len(cols) == 0 { 578 continue 579 } 580 for rows.Next() { 581 dest := make([]interface{}, len(cols)) 582 err = rows.ScanSlice(&dest) 583 if err != nil { 584 return err 585 } 586 587 _, err = io.WriteString(w, "INSERT INTO "+dialect.Quote(table.Name)+" ("+dialect.Quote(strings.Join(cols, dialect.Quote(", ")))+") VALUES (") 588 if err != nil { 589 return err 590 } 591 592 var temp string 593 for i, d := range dest { 594 col := table.GetColumn(cols[i]) 595 if d == nil { 596 temp += ", NULL" 597 } else if col.SQLType.IsText() || col.SQLType.IsTime() { 598 var v = fmt.Sprintf("%s", d) 599 if strings.HasSuffix(v, " +0000 UTC") { 600 temp += fmt.Sprintf(", '%s'", v[0:len(v)-len(" +0000 UTC")]) 601 } else { 602 temp += ", '" + strings.Replace(v, "'", "''", -1) + "'" 603 } 604 } else if col.SQLType.IsBlob() { 605 if reflect.TypeOf(d).Kind() == reflect.Slice { 606 temp += fmt.Sprintf(", %s", dialect.FormatBytes(d.([]byte))) 607 } else if reflect.TypeOf(d).Kind() == reflect.String { 608 temp += fmt.Sprintf(", '%s'", d.(string)) 609 } 610 } else if col.SQLType.IsNumeric() { 611 switch reflect.TypeOf(d).Kind() { 612 case reflect.Slice: 613 temp += fmt.Sprintf(", %s", string(d.([]byte))) 614 default: 615 temp += fmt.Sprintf(", %v", d) 616 } 617 } else { 618 s := fmt.Sprintf("%v", d) 619 if strings.Contains(s, ":") || strings.Contains(s, "-") { 620 if strings.HasSuffix(s, " +0000 UTC") { 621 temp += fmt.Sprintf(", '%s'", s[0:len(s)-len(" +0000 UTC")]) 622 } else { 623 temp += fmt.Sprintf(", '%s'", s) 624 } 625 } else { 626 temp += fmt.Sprintf(", %s", s) 627 } 628 } 629 } 630 _, err = io.WriteString(w, temp[2:]+");\n") 631 if err != nil { 632 return err 633 } 634 } 635 } 636 return nil 637 } 638 639 // Cascade use cascade or not 640 func (engine *Engine) Cascade(trueOrFalse ...bool) *Session { 641 session := engine.NewSession() 642 session.IsAutoClose = true 643 return session.Cascade(trueOrFalse...) 644 } 645 646 // Where method provide a condition query 647 func (engine *Engine) Where(query interface{}, args ...interface{}) *Session { 648 session := engine.NewSession() 649 session.IsAutoClose = true 650 return session.Where(query, args...) 651 } 652 653 // Id will be depracated, please use ID instead 654 func (engine *Engine) Id(id interface{}) *Session { 655 session := engine.NewSession() 656 session.IsAutoClose = true 657 return session.Id(id) 658 } 659 660 // ID mehtod provoide a condition as (id) = ? 661 func (engine *Engine) ID(id interface{}) *Session { 662 session := engine.NewSession() 663 session.IsAutoClose = true 664 return session.ID(id) 665 } 666 667 // Before apply before Processor, affected bean is passed to closure arg 668 func (engine *Engine) Before(closures func(interface{})) *Session { 669 session := engine.NewSession() 670 session.IsAutoClose = true 671 return session.Before(closures) 672 } 673 674 // After apply after insert Processor, affected bean is passed to closure arg 675 func (engine *Engine) After(closures func(interface{})) *Session { 676 session := engine.NewSession() 677 session.IsAutoClose = true 678 return session.After(closures) 679 } 680 681 // Charset set charset when create table, only support mysql now 682 func (engine *Engine) Charset(charset string) *Session { 683 session := engine.NewSession() 684 session.IsAutoClose = true 685 return session.Charset(charset) 686 } 687 688 // StoreEngine set store engine when create table, only support mysql now 689 func (engine *Engine) StoreEngine(storeEngine string) *Session { 690 session := engine.NewSession() 691 session.IsAutoClose = true 692 return session.StoreEngine(storeEngine) 693 } 694 695 // Distinct use for distinct columns. Caution: when you are using cache, 696 // distinct will not be cached because cache system need id, 697 // but distinct will not provide id 698 func (engine *Engine) Distinct(columns ...string) *Session { 699 session := engine.NewSession() 700 session.IsAutoClose = true 701 return session.Distinct(columns...) 702 } 703 704 // Select customerize your select columns or contents 705 func (engine *Engine) Select(str string) *Session { 706 session := engine.NewSession() 707 session.IsAutoClose = true 708 return session.Select(str) 709 } 710 711 // Cols only use the paramters as select or update columns 712 func (engine *Engine) Cols(columns ...string) *Session { 713 session := engine.NewSession() 714 session.IsAutoClose = true 715 return session.Cols(columns...) 716 } 717 718 // AllCols indicates that all columns should be use 719 func (engine *Engine) AllCols() *Session { 720 session := engine.NewSession() 721 session.IsAutoClose = true 722 return session.AllCols() 723 } 724 725 // MustCols specify some columns must use even if they are empty 726 func (engine *Engine) MustCols(columns ...string) *Session { 727 session := engine.NewSession() 728 session.IsAutoClose = true 729 return session.MustCols(columns...) 730 } 731 732 // UseBool xorm automatically retrieve condition according struct, but 733 // if struct has bool field, it will ignore them. So use UseBool 734 // to tell system to do not ignore them. 735 // If no paramters, it will use all the bool field of struct, or 736 // it will use paramters's columns 737 func (engine *Engine) UseBool(columns ...string) *Session { 738 session := engine.NewSession() 739 session.IsAutoClose = true 740 return session.UseBool(columns...) 741 } 742 743 // Omit only not use the paramters as select or update columns 744 func (engine *Engine) Omit(columns ...string) *Session { 745 session := engine.NewSession() 746 session.IsAutoClose = true 747 return session.Omit(columns...) 748 } 749 750 // Nullable set null when column is zero-value and nullable for update 751 func (engine *Engine) Nullable(columns ...string) *Session { 752 session := engine.NewSession() 753 session.IsAutoClose = true 754 return session.Nullable(columns...) 755 } 756 757 // In will generate "column IN (?, ?)" 758 func (engine *Engine) In(column string, args ...interface{}) *Session { 759 session := engine.NewSession() 760 session.IsAutoClose = true 761 return session.In(column, args...) 762 } 763 764 // Incr provides a update string like "column = column + ?" 765 func (engine *Engine) Incr(column string, arg ...interface{}) *Session { 766 session := engine.NewSession() 767 session.IsAutoClose = true 768 return session.Incr(column, arg...) 769 } 770 771 // Decr provides a update string like "column = column - ?" 772 func (engine *Engine) Decr(column string, arg ...interface{}) *Session { 773 session := engine.NewSession() 774 session.IsAutoClose = true 775 return session.Decr(column, arg...) 776 } 777 778 // SetExpr provides a update string like "column = {expression}" 779 func (engine *Engine) SetExpr(column string, expression string) *Session { 780 session := engine.NewSession() 781 session.IsAutoClose = true 782 return session.SetExpr(column, expression) 783 } 784 785 // Table temporarily change the Get, Find, Update's table 786 func (engine *Engine) Table(tableNameOrBean interface{}) *Session { 787 session := engine.NewSession() 788 session.IsAutoClose = true 789 return session.Table(tableNameOrBean) 790 } 791 792 // Alias set the table alias 793 func (engine *Engine) Alias(alias string) *Session { 794 session := engine.NewSession() 795 session.IsAutoClose = true 796 return session.Alias(alias) 797 } 798 799 // Limit will generate "LIMIT start, limit" 800 func (engine *Engine) Limit(limit int, start ...int) *Session { 801 session := engine.NewSession() 802 session.IsAutoClose = true 803 return session.Limit(limit, start...) 804 } 805 806 // Desc will generate "ORDER BY column1 DESC, column2 DESC" 807 func (engine *Engine) Desc(colNames ...string) *Session { 808 session := engine.NewSession() 809 session.IsAutoClose = true 810 return session.Desc(colNames...) 811 } 812 813 // Asc will generate "ORDER BY column1,column2 Asc" 814 // This method can chainable use. 815 // 816 // engine.Desc("name").Asc("age").Find(&users) 817 // // SELECT * FROM user ORDER BY name DESC, age ASC 818 // 819 func (engine *Engine) Asc(colNames ...string) *Session { 820 session := engine.NewSession() 821 session.IsAutoClose = true 822 return session.Asc(colNames...) 823 } 824 825 // OrderBy will generate "ORDER BY order" 826 func (engine *Engine) OrderBy(order string) *Session { 827 session := engine.NewSession() 828 session.IsAutoClose = true 829 return session.OrderBy(order) 830 } 831 832 // Join the join_operator should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN 833 func (engine *Engine) Join(joinOperator string, tablename interface{}, condition string, args ...interface{}) *Session { 834 session := engine.NewSession() 835 session.IsAutoClose = true 836 return session.Join(joinOperator, tablename, condition, args...) 837 } 838 839 // GroupBy generate group by statement 840 func (engine *Engine) GroupBy(keys string) *Session { 841 session := engine.NewSession() 842 session.IsAutoClose = true 843 return session.GroupBy(keys) 844 } 845 846 // Having generate having statement 847 func (engine *Engine) Having(conditions string) *Session { 848 session := engine.NewSession() 849 session.IsAutoClose = true 850 return session.Having(conditions) 851 } 852 853 func (engine *Engine) autoMapType(v reflect.Value) *core.Table { 854 t := v.Type() 855 engine.mutex.Lock() 856 defer engine.mutex.Unlock() 857 table, ok := engine.Tables[t] 858 if !ok { 859 table = engine.mapType(v) 860 engine.Tables[t] = table 861 if engine.Cacher != nil { 862 if v.CanAddr() { 863 engine.GobRegister(v.Addr().Interface()) 864 } else { 865 engine.GobRegister(v.Interface()) 866 } 867 } 868 } 869 return table 870 } 871 872 // GobRegister register one struct to gob for cache use 873 func (engine *Engine) GobRegister(v interface{}) *Engine { 874 //fmt.Printf("Type: %[1]T => Data: %[1]#v\n", v) 875 gob.Register(v) 876 return engine 877 } 878 879 // Table table struct 880 type Table struct { 881 *core.Table 882 Name string 883 } 884 885 // TableInfo get table info according to bean's content 886 func (engine *Engine) TableInfo(bean interface{}) *Table { 887 v := rValue(bean) 888 return &Table{engine.autoMapType(v), engine.tbName(v)} 889 } 890 891 func addIndex(indexName string, table *core.Table, col *core.Column, indexType int) { 892 if index, ok := table.Indexes[indexName]; ok { 893 index.AddColumn(col.Name) 894 col.Indexes[index.Name] = indexType 895 } else { 896 index := core.NewIndex(indexName, indexType) 897 index.AddColumn(col.Name) 898 table.AddIndex(index) 899 col.Indexes[index.Name] = indexType 900 } 901 } 902 903 func (engine *Engine) newTable() *core.Table { 904 table := core.NewEmptyTable() 905 906 if !engine.disableGlobalCache { 907 table.Cacher = engine.Cacher 908 } 909 return table 910 } 911 912 // TableName table name interface to define customerize table name 913 type TableName interface { 914 TableName() string 915 } 916 917 var ( 918 tpTableName = reflect.TypeOf((*TableName)(nil)).Elem() 919 ) 920 921 func (engine *Engine) mapType(v reflect.Value) *core.Table { 922 t := v.Type() 923 table := engine.newTable() 924 if tb, ok := v.Interface().(TableName); ok { 925 table.Name = tb.TableName() 926 } else { 927 if v.CanAddr() { 928 if tb, ok = v.Addr().Interface().(TableName); ok { 929 table.Name = tb.TableName() 930 } 931 } 932 if table.Name == "" { 933 table.Name = engine.TableMapper.Obj2Table(t.Name()) 934 } 935 } 936 937 table.Type = t 938 939 var idFieldColName string 940 var err error 941 var hasCacheTag, hasNoCacheTag bool 942 943 for i := 0; i < t.NumField(); i++ { 944 tag := t.Field(i).Tag 945 946 ormTagStr := tag.Get(engine.TagIdentifier) 947 var col *core.Column 948 fieldValue := v.Field(i) 949 fieldType := fieldValue.Type() 950 951 if ormTagStr != "" { 952 col = &core.Column{FieldName: t.Field(i).Name, Nullable: true, IsPrimaryKey: false, 953 IsAutoIncrement: false, MapType: core.TWOSIDES, Indexes: make(map[string]int)} 954 tags := splitTag(ormTagStr) 955 956 if len(tags) > 0 { 957 if tags[0] == "-" { 958 continue 959 } 960 if strings.ToUpper(tags[0]) == "EXTENDS" { 961 switch fieldValue.Kind() { 962 case reflect.Ptr: 963 f := fieldValue.Type().Elem() 964 if f.Kind() == reflect.Struct { 965 fieldPtr := fieldValue 966 fieldValue = fieldValue.Elem() 967 if !fieldValue.IsValid() || fieldPtr.IsNil() { 968 fieldValue = reflect.New(f).Elem() 969 } 970 } 971 fallthrough 972 case reflect.Struct: 973 parentTable := engine.mapType(fieldValue) 974 for _, col := range parentTable.Columns() { 975 col.FieldName = fmt.Sprintf("%v.%v", t.Field(i).Name, col.FieldName) 976 table.AddColumn(col) 977 for indexName, indexType := range col.Indexes { 978 addIndex(indexName, table, col, indexType) 979 } 980 } 981 continue 982 default: 983 //TODO: warning 984 } 985 } 986 987 indexNames := make(map[string]int) 988 var isIndex, isUnique bool 989 var preKey string 990 for j, key := range tags { 991 k := strings.ToUpper(key) 992 switch { 993 case k == "<-": 994 col.MapType = core.ONLYFROMDB 995 case k == "->": 996 col.MapType = core.ONLYTODB 997 case k == "PK": 998 col.IsPrimaryKey = true 999 col.Nullable = false 1000 case k == "NULL": 1001 if j == 0 { 1002 col.Nullable = true 1003 } else { 1004 col.Nullable = (strings.ToUpper(tags[j-1]) != "NOT") 1005 } 1006 // TODO: for postgres how add autoincr? 1007 /*case strings.HasPrefix(k, "AUTOINCR(") && strings.HasSuffix(k, ")"): 1008 col.IsAutoIncrement = true 1009 1010 autoStart := k[len("AUTOINCR")+1 : len(k)-1] 1011 autoStartInt, err := strconv.Atoi(autoStart) 1012 if err != nil { 1013 engine.LogError(err) 1014 } 1015 col.AutoIncrStart = autoStartInt*/ 1016 case k == "AUTOINCR": 1017 col.IsAutoIncrement = true 1018 //col.AutoIncrStart = 1 1019 case k == "DEFAULT": 1020 col.Default = tags[j+1] 1021 case k == "CREATED": 1022 col.IsCreated = true 1023 case k == "VERSION": 1024 col.IsVersion = true 1025 col.Default = "1" 1026 case k == "UTC": 1027 col.TimeZone = time.UTC 1028 case k == "LOCAL": 1029 col.TimeZone = time.Local 1030 case strings.HasPrefix(k, "LOCALE(") && strings.HasSuffix(k, ")"): 1031 location := k[len("LOCALE")+1 : len(k)-1] 1032 col.TimeZone, err = time.LoadLocation(location) 1033 if err != nil { 1034 engine.logger.Error(err) 1035 } 1036 case k == "UPDATED": 1037 col.IsUpdated = true 1038 case k == "DELETED": 1039 col.IsDeleted = true 1040 case strings.HasPrefix(k, "INDEX(") && strings.HasSuffix(k, ")"): 1041 indexName := k[len("INDEX")+1 : len(k)-1] 1042 indexNames[indexName] = core.IndexType 1043 case k == "INDEX": 1044 isIndex = true 1045 case strings.HasPrefix(k, "UNIQUE(") && strings.HasSuffix(k, ")"): 1046 indexName := k[len("UNIQUE")+1 : len(k)-1] 1047 indexNames[indexName] = core.UniqueType 1048 case k == "UNIQUE": 1049 isUnique = true 1050 case k == "NOTNULL": 1051 col.Nullable = false 1052 case k == "CACHE": 1053 if !hasCacheTag { 1054 hasCacheTag = true 1055 } 1056 case k == "NOCACHE": 1057 if !hasNoCacheTag { 1058 hasNoCacheTag = true 1059 } 1060 case k == "NOT": 1061 default: 1062 if strings.HasPrefix(k, "'") && strings.HasSuffix(k, "'") { 1063 if preKey != "DEFAULT" { 1064 col.Name = key[1 : len(key)-1] 1065 } 1066 } else if strings.Contains(k, "(") && strings.HasSuffix(k, ")") { 1067 fs := strings.Split(k, "(") 1068 1069 if _, ok := core.SqlTypes[fs[0]]; !ok { 1070 preKey = k 1071 continue 1072 } 1073 col.SQLType = core.SQLType{Name: fs[0]} 1074 if fs[0] == core.Enum && fs[1][0] == '\'' { //enum 1075 options := strings.Split(fs[1][0:len(fs[1])-1], ",") 1076 col.EnumOptions = make(map[string]int) 1077 for k, v := range options { 1078 v = strings.TrimSpace(v) 1079 v = strings.Trim(v, "'") 1080 col.EnumOptions[v] = k 1081 } 1082 } else if fs[0] == core.Set && fs[1][0] == '\'' { //set 1083 options := strings.Split(fs[1][0:len(fs[1])-1], ",") 1084 col.SetOptions = make(map[string]int) 1085 for k, v := range options { 1086 v = strings.TrimSpace(v) 1087 v = strings.Trim(v, "'") 1088 col.SetOptions[v] = k 1089 } 1090 } else { 1091 fs2 := strings.Split(fs[1][0:len(fs[1])-1], ",") 1092 if len(fs2) == 2 { 1093 col.Length, err = strconv.Atoi(fs2[0]) 1094 if err != nil { 1095 engine.logger.Error(err) 1096 } 1097 col.Length2, err = strconv.Atoi(fs2[1]) 1098 if err != nil { 1099 engine.logger.Error(err) 1100 } 1101 } else if len(fs2) == 1 { 1102 col.Length, err = strconv.Atoi(fs2[0]) 1103 if err != nil { 1104 engine.logger.Error(err) 1105 } 1106 } 1107 } 1108 } else { 1109 if _, ok := core.SqlTypes[k]; ok { 1110 col.SQLType = core.SQLType{Name: k} 1111 } else if key != col.Default { 1112 col.Name = key 1113 } 1114 } 1115 engine.dialect.SqlType(col) 1116 } 1117 preKey = k 1118 } 1119 if col.SQLType.Name == "" { 1120 col.SQLType = core.Type2SQLType(fieldType) 1121 } 1122 if col.Length == 0 { 1123 col.Length = col.SQLType.DefaultLength 1124 } 1125 if col.Length2 == 0 { 1126 col.Length2 = col.SQLType.DefaultLength2 1127 } 1128 1129 if col.Name == "" { 1130 col.Name = engine.ColumnMapper.Obj2Table(t.Field(i).Name) 1131 } 1132 1133 if isUnique { 1134 indexNames[col.Name] = core.UniqueType 1135 } else if isIndex { 1136 indexNames[col.Name] = core.IndexType 1137 } 1138 1139 for indexName, indexType := range indexNames { 1140 addIndex(indexName, table, col, indexType) 1141 } 1142 } 1143 } else { 1144 var sqlType core.SQLType 1145 if fieldValue.CanAddr() { 1146 if _, ok := fieldValue.Addr().Interface().(core.Conversion); ok { 1147 sqlType = core.SQLType{Name: core.Text} 1148 } 1149 } 1150 if _, ok := fieldValue.Interface().(core.Conversion); ok { 1151 sqlType = core.SQLType{Name: core.Text} 1152 } else { 1153 sqlType = core.Type2SQLType(fieldType) 1154 } 1155 col = core.NewColumn(engine.ColumnMapper.Obj2Table(t.Field(i).Name), 1156 t.Field(i).Name, sqlType, sqlType.DefaultLength, 1157 sqlType.DefaultLength2, true) 1158 } 1159 if col.IsAutoIncrement { 1160 col.Nullable = false 1161 } 1162 1163 table.AddColumn(col) 1164 1165 if fieldType.Kind() == reflect.Int64 && (strings.ToUpper(col.FieldName) == "ID" || strings.HasSuffix(strings.ToUpper(col.FieldName), ".ID")) { 1166 idFieldColName = col.Name 1167 } 1168 } // end for 1169 1170 if idFieldColName != "" && len(table.PrimaryKeys) == 0 { 1171 col := table.GetColumn(idFieldColName) 1172 col.IsPrimaryKey = true 1173 col.IsAutoIncrement = true 1174 col.Nullable = false 1175 table.PrimaryKeys = append(table.PrimaryKeys, col.Name) 1176 table.AutoIncrement = col.Name 1177 } 1178 1179 if hasCacheTag { 1180 if engine.Cacher != nil { // !nash! use engine's cacher if provided 1181 engine.logger.Info("enable cache on table:", table.Name) 1182 table.Cacher = engine.Cacher 1183 } else { 1184 engine.logger.Info("enable LRU cache on table:", table.Name) 1185 table.Cacher = NewLRUCacher2(NewMemoryStore(), time.Hour, 10000) // !nashtsai! HACK use LRU cacher for now 1186 } 1187 } 1188 if hasNoCacheTag { 1189 engine.logger.Info("no cache on table:", table.Name) 1190 table.Cacher = nil 1191 } 1192 1193 return table 1194 } 1195 1196 // IsTableEmpty if a table has any reocrd 1197 func (engine *Engine) IsTableEmpty(bean interface{}) (bool, error) { 1198 session := engine.NewSession() 1199 defer session.Close() 1200 return session.IsTableEmpty(bean) 1201 } 1202 1203 // IsTableExist if a table is exist 1204 func (engine *Engine) IsTableExist(beanOrTableName interface{}) (bool, error) { 1205 session := engine.NewSession() 1206 defer session.Close() 1207 return session.IsTableExist(beanOrTableName) 1208 } 1209 1210 // IdOf get id from one struct 1211 func (engine *Engine) IdOf(bean interface{}) core.PK { 1212 return engine.IdOfV(reflect.ValueOf(bean)) 1213 } 1214 1215 // IdOfV get id from one value of struct 1216 func (engine *Engine) IdOfV(rv reflect.Value) core.PK { 1217 v := reflect.Indirect(rv) 1218 table := engine.autoMapType(v) 1219 pk := make([]interface{}, len(table.PrimaryKeys)) 1220 for i, col := range table.PKColumns() { 1221 pkField := v.FieldByName(col.FieldName) 1222 switch pkField.Kind() { 1223 case reflect.String: 1224 pk[i] = pkField.String() 1225 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 1226 pk[i] = pkField.Int() 1227 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 1228 pk[i] = pkField.Uint() 1229 } 1230 } 1231 return core.PK(pk) 1232 } 1233 1234 // CreateIndexes create indexes 1235 func (engine *Engine) CreateIndexes(bean interface{}) error { 1236 session := engine.NewSession() 1237 defer session.Close() 1238 return session.CreateIndexes(bean) 1239 } 1240 1241 // CreateUniques create uniques 1242 func (engine *Engine) CreateUniques(bean interface{}) error { 1243 session := engine.NewSession() 1244 defer session.Close() 1245 return session.CreateUniques(bean) 1246 } 1247 1248 func (engine *Engine) getCacher2(table *core.Table) core.Cacher { 1249 return table.Cacher 1250 } 1251 1252 func (engine *Engine) getCacher(v reflect.Value) core.Cacher { 1253 if table := engine.autoMapType(v); table != nil { 1254 return table.Cacher 1255 } 1256 return engine.Cacher 1257 } 1258 1259 // ClearCacheBean if enabled cache, clear the cache bean 1260 func (engine *Engine) ClearCacheBean(bean interface{}, id string) error { 1261 v := rValue(bean) 1262 t := v.Type() 1263 if t.Kind() != reflect.Struct { 1264 return errors.New("error params") 1265 } 1266 tableName := engine.tbName(v) 1267 table := engine.autoMapType(v) 1268 cacher := table.Cacher 1269 if cacher == nil { 1270 cacher = engine.Cacher 1271 } 1272 if cacher != nil { 1273 cacher.ClearIds(tableName) 1274 cacher.DelBean(tableName, id) 1275 } 1276 return nil 1277 } 1278 1279 // ClearCache if enabled cache, clear some tables' cache 1280 func (engine *Engine) ClearCache(beans ...interface{}) error { 1281 for _, bean := range beans { 1282 v := rValue(bean) 1283 t := v.Type() 1284 if t.Kind() != reflect.Struct { 1285 return errors.New("error params") 1286 } 1287 tableName := engine.tbName(v) 1288 table := engine.autoMapType(v) 1289 cacher := table.Cacher 1290 if cacher == nil { 1291 cacher = engine.Cacher 1292 } 1293 if cacher != nil { 1294 cacher.ClearIds(tableName) 1295 cacher.ClearBeans(tableName) 1296 } 1297 } 1298 return nil 1299 } 1300 1301 // Sync the new struct changes to database, this method will automatically add 1302 // table, column, index, unique. but will not delete or change anything. 1303 // If you change some field, you should change the database manually. 1304 func (engine *Engine) Sync(beans ...interface{}) error { 1305 for _, bean := range beans { 1306 v := rValue(bean) 1307 tableName := engine.tbName(v) 1308 table := engine.autoMapType(v) 1309 1310 s := engine.NewSession() 1311 defer s.Close() 1312 isExist, err := s.Table(bean).isTableExist(tableName) 1313 if err != nil { 1314 return err 1315 } 1316 if !isExist { 1317 err = engine.CreateTables(bean) 1318 if err != nil { 1319 return err 1320 } 1321 } 1322 /*isEmpty, err := engine.IsEmptyTable(bean) 1323 if err != nil { 1324 return err 1325 }*/ 1326 var isEmpty bool 1327 if isEmpty { 1328 err = engine.DropTables(bean) 1329 if err != nil { 1330 return err 1331 } 1332 err = engine.CreateTables(bean) 1333 if err != nil { 1334 return err 1335 } 1336 } else { 1337 for _, col := range table.Columns() { 1338 isExist, err := engine.dialect.IsColumnExist(tableName, col.Name) 1339 if err != nil { 1340 return err 1341 } 1342 if !isExist { 1343 session := engine.NewSession() 1344 session.Statement.setRefValue(v) 1345 defer session.Close() 1346 err = session.addColumn(col.Name) 1347 if err != nil { 1348 return err 1349 } 1350 } 1351 } 1352 1353 for name, index := range table.Indexes { 1354 session := engine.NewSession() 1355 session.Statement.setRefValue(v) 1356 defer session.Close() 1357 if index.Type == core.UniqueType { 1358 //isExist, err := session.isIndexExist(table.Name, name, true) 1359 isExist, err := session.isIndexExist2(tableName, index.Cols, true) 1360 if err != nil { 1361 return err 1362 } 1363 if !isExist { 1364 session := engine.NewSession() 1365 session.Statement.setRefValue(v) 1366 defer session.Close() 1367 err = session.addUnique(tableName, name) 1368 if err != nil { 1369 return err 1370 } 1371 } 1372 } else if index.Type == core.IndexType { 1373 isExist, err := session.isIndexExist2(tableName, index.Cols, false) 1374 if err != nil { 1375 return err 1376 } 1377 if !isExist { 1378 session := engine.NewSession() 1379 session.Statement.setRefValue(v) 1380 defer session.Close() 1381 err = session.addIndex(tableName, name) 1382 if err != nil { 1383 return err 1384 } 1385 } 1386 } else { 1387 return errors.New("unknow index type") 1388 } 1389 } 1390 } 1391 } 1392 return nil 1393 } 1394 1395 // Sync2 synchronize structs to database tables 1396 func (engine *Engine) Sync2(beans ...interface{}) error { 1397 s := engine.NewSession() 1398 defer s.Close() 1399 return s.Sync2(beans...) 1400 } 1401 1402 func (engine *Engine) unMap(beans ...interface{}) (e error) { 1403 engine.mutex.Lock() 1404 defer engine.mutex.Unlock() 1405 for _, bean := range beans { 1406 t := rType(bean) 1407 if _, ok := engine.Tables[t]; ok { 1408 delete(engine.Tables, t) 1409 } 1410 } 1411 return 1412 } 1413 1414 // Drop all mapped table 1415 func (engine *Engine) dropAll() error { 1416 session := engine.NewSession() 1417 defer session.Close() 1418 1419 err := session.Begin() 1420 if err != nil { 1421 return err 1422 } 1423 err = session.dropAll() 1424 if err != nil { 1425 session.Rollback() 1426 return err 1427 } 1428 return session.Commit() 1429 } 1430 1431 // CreateTables create tabls according bean 1432 func (engine *Engine) CreateTables(beans ...interface{}) error { 1433 session := engine.NewSession() 1434 defer session.Close() 1435 1436 err := session.Begin() 1437 if err != nil { 1438 return err 1439 } 1440 1441 for _, bean := range beans { 1442 err = session.CreateTable(bean) 1443 if err != nil { 1444 session.Rollback() 1445 return err 1446 } 1447 } 1448 return session.Commit() 1449 } 1450 1451 // DropTables drop specify tables 1452 func (engine *Engine) DropTables(beans ...interface{}) error { 1453 session := engine.NewSession() 1454 defer session.Close() 1455 1456 err := session.Begin() 1457 if err != nil { 1458 return err 1459 } 1460 1461 for _, bean := range beans { 1462 err = session.DropTable(bean) 1463 if err != nil { 1464 session.Rollback() 1465 return err 1466 } 1467 } 1468 return session.Commit() 1469 } 1470 1471 func (engine *Engine) createAll() error { 1472 session := engine.NewSession() 1473 defer session.Close() 1474 return session.createAll() 1475 } 1476 1477 // Exec raw sql 1478 func (engine *Engine) Exec(sql string, args ...interface{}) (sql.Result, error) { 1479 session := engine.NewSession() 1480 defer session.Close() 1481 return session.Exec(sql, args...) 1482 } 1483 1484 // Query a raw sql and return records as []map[string][]byte 1485 func (engine *Engine) Query(sql string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) { 1486 session := engine.NewSession() 1487 defer session.Close() 1488 return session.Query(sql, paramStr...) 1489 } 1490 1491 // Insert one or more records 1492 func (engine *Engine) Insert(beans ...interface{}) (int64, error) { 1493 session := engine.NewSession() 1494 defer session.Close() 1495 return session.Insert(beans...) 1496 } 1497 1498 // InsertOne insert only one record 1499 func (engine *Engine) InsertOne(bean interface{}) (int64, error) { 1500 session := engine.NewSession() 1501 defer session.Close() 1502 return session.InsertOne(bean) 1503 } 1504 1505 // Update records, bean's non-empty fields are updated contents, 1506 // condiBean' non-empty filds are conditions 1507 // CAUTION: 1508 // 1.bool will defaultly be updated content nor conditions 1509 // You should call UseBool if you have bool to use. 1510 // 2.float32 & float64 may be not inexact as conditions 1511 func (engine *Engine) Update(bean interface{}, condiBeans ...interface{}) (int64, error) { 1512 session := engine.NewSession() 1513 defer session.Close() 1514 return session.Update(bean, condiBeans...) 1515 } 1516 1517 // Delete records, bean's non-empty fields are conditions 1518 func (engine *Engine) Delete(bean interface{}) (int64, error) { 1519 session := engine.NewSession() 1520 defer session.Close() 1521 return session.Delete(bean) 1522 } 1523 1524 // Get retrieve one record from table, bean's non-empty fields 1525 // are conditions 1526 func (engine *Engine) Get(bean interface{}) (bool, error) { 1527 session := engine.NewSession() 1528 defer session.Close() 1529 return session.Get(bean) 1530 } 1531 1532 // Find retrieve records from table, condiBeans's non-empty fields 1533 // are conditions. beans could be []Struct, []*Struct, map[int64]Struct 1534 // map[int64]*Struct 1535 func (engine *Engine) Find(beans interface{}, condiBeans ...interface{}) error { 1536 session := engine.NewSession() 1537 defer session.Close() 1538 return session.Find(beans, condiBeans...) 1539 } 1540 1541 // Iterate record by record handle records from table, bean's non-empty fields 1542 // are conditions. 1543 func (engine *Engine) Iterate(bean interface{}, fun IterFunc) error { 1544 session := engine.NewSession() 1545 defer session.Close() 1546 return session.Iterate(bean, fun) 1547 } 1548 1549 // Rows return sql.Rows compatible Rows obj, as a forward Iterator object for iterating record by record, bean's non-empty fields 1550 // are conditions. 1551 func (engine *Engine) Rows(bean interface{}) (*Rows, error) { 1552 session := engine.NewSession() 1553 return session.Rows(bean) 1554 } 1555 1556 // Count counts the records. bean's non-empty fields are conditions. 1557 func (engine *Engine) Count(bean interface{}) (int64, error) { 1558 session := engine.NewSession() 1559 defer session.Close() 1560 return session.Count(bean) 1561 } 1562 1563 // Sum sum the records by some column. bean's non-empty fields are conditions. 1564 func (engine *Engine) Sum(bean interface{}, colName string) (float64, error) { 1565 session := engine.NewSession() 1566 defer session.Close() 1567 return session.Sum(bean, colName) 1568 } 1569 1570 // Sums sum the records by some columns. bean's non-empty fields are conditions. 1571 func (engine *Engine) Sums(bean interface{}, colNames ...string) ([]float64, error) { 1572 session := engine.NewSession() 1573 defer session.Close() 1574 return session.Sums(bean, colNames...) 1575 } 1576 1577 // SumsInt like Sums but return slice of int64 instead of float64. 1578 func (engine *Engine) SumsInt(bean interface{}, colNames ...string) ([]int64, error) { 1579 session := engine.NewSession() 1580 defer session.Close() 1581 return session.SumsInt(bean, colNames...) 1582 } 1583 1584 // ImportFile SQL DDL file 1585 func (engine *Engine) ImportFile(ddlPath string) ([]sql.Result, error) { 1586 file, err := os.Open(ddlPath) 1587 if err != nil { 1588 return nil, err 1589 } 1590 defer file.Close() 1591 return engine.Import(file) 1592 } 1593 1594 // Import SQL DDL from io.Reader 1595 func (engine *Engine) Import(r io.Reader) ([]sql.Result, error) { 1596 var results []sql.Result 1597 var lastError error 1598 scanner := bufio.NewScanner(r) 1599 1600 semiColSpliter := func(data []byte, atEOF bool) (advance int, token []byte, err error) { 1601 if atEOF && len(data) == 0 { 1602 return 0, nil, nil 1603 } 1604 if i := bytes.IndexByte(data, ';'); i >= 0 { 1605 return i + 1, data[0:i], nil 1606 } 1607 // If we're at EOF, we have a final, non-terminated line. Return it. 1608 if atEOF { 1609 return len(data), data, nil 1610 } 1611 // Request more data. 1612 return 0, nil, nil 1613 } 1614 1615 scanner.Split(semiColSpliter) 1616 1617 for scanner.Scan() { 1618 query := strings.Trim(scanner.Text(), " \t\n\r") 1619 if len(query) > 0 { 1620 engine.logSQL(query) 1621 result, err := engine.DB().Exec(query) 1622 results = append(results, result) 1623 if err != nil { 1624 return nil, err 1625 //lastError = err 1626 } 1627 } 1628 } 1629 1630 return results, lastError 1631 } 1632 1633 // TZTime change one time to xorm time location 1634 func (engine *Engine) TZTime(t time.Time) time.Time { 1635 if !t.IsZero() { // if time is not initialized it's not suitable for Time.In() 1636 return t.In(engine.TZLocation) 1637 } 1638 return t 1639 } 1640 1641 // NowTime return current time 1642 func (engine *Engine) NowTime(sqlTypeName string) interface{} { 1643 t := time.Now() 1644 return engine.FormatTime(sqlTypeName, t) 1645 } 1646 1647 // NowTime2 return current time 1648 func (engine *Engine) NowTime2(sqlTypeName string) (interface{}, time.Time) { 1649 t := time.Now() 1650 return engine.FormatTime(sqlTypeName, t), t 1651 } 1652 1653 // FormatTime format time 1654 func (engine *Engine) FormatTime(sqlTypeName string, t time.Time) (v interface{}) { 1655 return engine.formatTime(engine.TZLocation, sqlTypeName, t) 1656 } 1657 1658 func (engine *Engine) formatColTime(col *core.Column, t time.Time) (v interface{}) { 1659 if col.DisableTimeZone { 1660 return engine.formatTime(nil, col.SQLType.Name, t) 1661 } else if col.TimeZone != nil { 1662 return engine.formatTime(col.TimeZone, col.SQLType.Name, t) 1663 } 1664 return engine.formatTime(engine.TZLocation, col.SQLType.Name, t) 1665 } 1666 1667 func (engine *Engine) formatTime(tz *time.Location, sqlTypeName string, t time.Time) (v interface{}) { 1668 if engine.dialect.DBType() == core.ORACLE { 1669 return t 1670 } 1671 if tz != nil { 1672 t = engine.TZTime(t) 1673 } 1674 switch sqlTypeName { 1675 case core.Time: 1676 s := t.Format("2006-01-02 15:04:05") //time.RFC3339 1677 v = s[11:19] 1678 case core.Date: 1679 v = t.Format("2006-01-02") 1680 case core.DateTime, core.TimeStamp: 1681 if engine.dialect.DBType() == "ql" { 1682 v = t 1683 } else if engine.dialect.DBType() == "sqlite3" { 1684 v = t.UTC().Format("2006-01-02 15:04:05") 1685 } else { 1686 v = t.Format("2006-01-02 15:04:05") 1687 } 1688 case core.TimeStampz: 1689 if engine.dialect.DBType() == core.MSSQL { 1690 v = t.Format("2006-01-02T15:04:05.9999999Z07:00") 1691 } else if engine.DriverName() == "mssql" { 1692 v = t 1693 } else { 1694 v = t.Format(time.RFC3339Nano) 1695 } 1696 case core.BigInt, core.Int: 1697 v = t.Unix() 1698 default: 1699 v = t 1700 } 1701 return 1702 } 1703 1704 // Unscoped always disable struct tag "deleted" 1705 func (engine *Engine) Unscoped() *Session { 1706 session := engine.NewSession() 1707 session.IsAutoClose = true 1708 return session.Unscoped() 1709 }