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  }