2016-11-04 01:16:01 +03:00
// Copyright 2015 The Xorm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package xorm
import (
2019-06-23 18:22:43 +03:00
"context"
2016-11-04 01:16:01 +03:00
"database/sql"
"errors"
"fmt"
"io"
"os"
"reflect"
2020-06-15 23:46:01 +03:00
"runtime"
2016-11-04 01:16:01 +03:00
"strconv"
"strings"
"time"
2020-03-22 18:12:55 +03:00
"xorm.io/xorm/caches"
2020-06-15 23:46:01 +03:00
"xorm.io/xorm/contexts"
2020-03-22 18:12:55 +03:00
"xorm.io/xorm/core"
"xorm.io/xorm/dialects"
"xorm.io/xorm/internal/utils"
"xorm.io/xorm/log"
"xorm.io/xorm/names"
"xorm.io/xorm/schemas"
"xorm.io/xorm/tags"
2016-11-04 01:16:01 +03:00
)
// Engine is the major struct of xorm, it means a database manager.
// Commonly, an application only need one engine
type Engine struct {
2020-03-22 18:12:55 +03:00
cacherMgr * caches . Manager
defaultContext context . Context
dialect dialects . Dialect
engineGroup * EngineGroup
logger log . ContextLogger
tagParser * tags . Parser
2020-03-25 17:32:23 +03:00
db * core . DB
2016-11-04 01:16:01 +03:00
2020-03-22 18:12:55 +03:00
driverName string
dataSourceName string
2016-11-04 01:16:01 +03:00
2017-08-22 14:39:52 +03:00
TZLocation * time . Location // The timezone of the application
2016-11-04 01:16:01 +03:00
DatabaseTZ * time . Location // The timezone of the database
2020-06-15 23:46:01 +03:00
logSessionID bool // create session id
2018-07-20 05:10:17 +03:00
}
2020-06-15 23:46:01 +03:00
// NewEngine new a db manager according to the parameter. Currently support four
// drivers
func NewEngine ( driverName string , dataSourceName string ) ( * Engine , error ) {
dialect , err := dialects . OpenDialect ( driverName , dataSourceName )
if err != nil {
return nil , err
}
db , err := core . Open ( driverName , dataSourceName )
if err != nil {
return nil , err
}
2021-01-05 09:28:51 +03:00
return newEngine ( driverName , dataSourceName , dialect , db )
}
func newEngine ( driverName , dataSourceName string , dialect dialects . Dialect , db * core . DB ) ( * Engine , error ) {
2020-06-15 23:46:01 +03:00
cacherMgr := caches . NewManager ( )
mapper := names . NewCacheMapper ( new ( names . SnakeMapper ) )
tagParser := tags . NewParser ( "xorm" , dialect , mapper , mapper , cacherMgr )
engine := & Engine {
dialect : dialect ,
TZLocation : time . Local ,
defaultContext : context . Background ( ) ,
cacherMgr : cacherMgr ,
tagParser : tagParser ,
driverName : driverName ,
dataSourceName : dataSourceName ,
db : db ,
logSessionID : false ,
}
if dialect . URI ( ) . DBType == schemas . SQLITE {
engine . DatabaseTZ = time . UTC
} else {
engine . DatabaseTZ = time . Local
}
logger := log . NewSimpleLogger ( os . Stdout )
logger . SetLevel ( log . LOG_INFO )
engine . SetLogger ( log . NewLoggerAdapter ( logger ) )
runtime . SetFinalizer ( engine , func ( engine * Engine ) {
2021-01-05 09:28:51 +03:00
_ = engine . Close ( )
2020-06-15 23:46:01 +03:00
} )
return engine , nil
}
// NewEngineWithParams new a db manager with params. The params will be passed to dialects.
func NewEngineWithParams ( driverName string , dataSourceName string , params map [ string ] string ) ( * Engine , error ) {
engine , err := NewEngine ( driverName , dataSourceName )
engine . dialect . SetParams ( params )
return engine , err
}
2021-01-05 09:28:51 +03:00
// NewEngineWithDialectAndDB new a db manager according to the parameter.
// If you do not want to use your own dialect or db, please use NewEngine.
// For creating dialect, you can call dialects.OpenDialect. And, for creating db,
// you can call core.Open or core.FromDB.
func NewEngineWithDialectAndDB ( driverName , dataSourceName string , dialect dialects . Dialect , db * core . DB ) ( * Engine , error ) {
return newEngine ( driverName , dataSourceName , dialect , db )
}
2020-06-15 23:46:01 +03:00
// EnableSessionID if enable session id
func ( engine * Engine ) EnableSessionID ( enable bool ) {
engine . logSessionID = enable
}
// SetCacher sets cacher for the table
2020-03-22 18:12:55 +03:00
func ( engine * Engine ) SetCacher ( tableName string , cacher caches . Cacher ) {
engine . cacherMgr . SetCacher ( tableName , cacher )
2018-07-20 05:10:17 +03:00
}
2020-06-15 23:46:01 +03:00
// GetCacher returns the cachher of the special table
2020-03-22 18:12:55 +03:00
func ( engine * Engine ) GetCacher ( tableName string ) caches . Cacher {
return engine . cacherMgr . GetCacher ( tableName )
2018-07-20 05:10:17 +03:00
}
2020-06-15 23:46:01 +03:00
// SetQuotePolicy sets the special quote policy
2020-03-22 18:12:55 +03:00
func ( engine * Engine ) SetQuotePolicy ( quotePolicy dialects . QuotePolicy ) {
engine . dialect . SetQuotePolicy ( quotePolicy )
2018-01-27 18:20:59 +03:00
}
// BufferSize sets buffer size for iterate
func ( engine * Engine ) BufferSize ( size int ) * Session {
session := engine . NewSession ( )
session . isAutoClose = true
return session . BufferSize ( size )
}
2017-01-23 12:11:18 +03:00
// ShowSQL show SQL statement or not on logger if log level is great than INFO
2016-11-04 01:16:01 +03:00
func ( engine * Engine ) ShowSQL ( show ... bool ) {
engine . logger . ShowSQL ( show ... )
2020-03-22 18:12:55 +03:00
engine . DB ( ) . Logger = engine . logger
2016-11-04 01:16:01 +03:00
}
// Logger return the logger interface
2020-03-22 18:12:55 +03:00
func ( engine * Engine ) Logger ( ) log . ContextLogger {
2016-11-04 01:16:01 +03:00
return engine . logger
}
// SetLogger set the new logger
2020-03-22 18:12:55 +03:00
func ( engine * Engine ) SetLogger ( logger interface { } ) {
var realLogger log . ContextLogger
switch t := logger . ( type ) {
case log . ContextLogger :
realLogger = t
2020-07-12 00:07:52 +03:00
case log . Logger :
realLogger = log . NewLoggerAdapter ( t )
2020-03-22 18:12:55 +03:00
}
engine . logger = realLogger
engine . DB ( ) . Logger = realLogger
2016-11-04 01:16:01 +03:00
}
2018-01-27 18:20:59 +03:00
// SetLogLevel sets the logger level
2020-03-22 18:12:55 +03:00
func ( engine * Engine ) SetLogLevel ( level log . LogLevel ) {
2018-01-27 18:20:59 +03:00
engine . logger . SetLevel ( level )
}
2016-11-04 01:16:01 +03:00
// SetDisableGlobalCache disable global cache or not
func ( engine * Engine ) SetDisableGlobalCache ( disable bool ) {
2020-03-22 18:12:55 +03:00
engine . cacherMgr . SetDisableGlobalCache ( disable )
2016-11-04 01:16:01 +03:00
}
// DriverName return the current sql driver's name
func ( engine * Engine ) DriverName ( ) string {
2020-03-22 18:12:55 +03:00
return engine . driverName
2016-11-04 01:16:01 +03:00
}
// DataSourceName return the current connection string
func ( engine * Engine ) DataSourceName ( ) string {
2020-03-22 18:12:55 +03:00
return engine . dataSourceName
2016-11-04 01:16:01 +03:00
}
// SetMapper set the name mapping rules
2020-03-22 18:12:55 +03:00
func ( engine * Engine ) SetMapper ( mapper names . Mapper ) {
2016-11-04 01:16:01 +03:00
engine . SetTableMapper ( mapper )
engine . SetColumnMapper ( mapper )
}
// SetTableMapper set the table name mapping rule
2020-03-22 18:12:55 +03:00
func ( engine * Engine ) SetTableMapper ( mapper names . Mapper ) {
engine . tagParser . SetTableMapper ( mapper )
2016-11-04 01:16:01 +03:00
}
// SetColumnMapper set the column name mapping rule
2020-03-22 18:12:55 +03:00
func ( engine * Engine ) SetColumnMapper ( mapper names . Mapper ) {
engine . tagParser . SetColumnMapper ( mapper )
2018-12-12 04:01:41 +03:00
}
2016-11-04 01:16:01 +03:00
// Quote Use QuoteStr quote the string sql
2016-11-11 19:40:21 +03:00
func ( engine * Engine ) Quote ( value string ) string {
value = strings . TrimSpace ( value )
if len ( value ) == 0 {
return value
}
2016-11-04 01:16:01 +03:00
2019-09-24 16:22:39 +03:00
buf := strings . Builder { }
2019-08-27 05:17:23 +03:00
engine . QuoteTo ( & buf , value )
2016-11-11 19:40:21 +03:00
2019-08-27 05:17:23 +03:00
return buf . String ( )
2016-11-04 01:16:01 +03:00
}
2016-11-11 19:40:21 +03:00
// QuoteTo quotes string and writes into the buffer
2019-09-24 16:22:39 +03:00
func ( engine * Engine ) QuoteTo ( buf * strings . Builder , value string ) {
2016-11-11 19:40:21 +03:00
if buf == nil {
return
}
value = strings . TrimSpace ( value )
if value == "" {
return
2016-11-04 01:16:01 +03:00
}
2020-03-22 18:12:55 +03:00
engine . dialect . Quoter ( ) . QuoteTo ( buf , value )
2016-11-04 01:16:01 +03:00
}
// SQLType A simple wrapper to dialect's core.SqlType method
2020-03-22 18:12:55 +03:00
func ( engine * Engine ) SQLType ( c * schemas . Column ) string {
return engine . dialect . SQLType ( c )
2016-11-04 01:16:01 +03:00
}
// AutoIncrStr Database's autoincrement statement
func ( engine * Engine ) AutoIncrStr ( ) string {
return engine . dialect . AutoIncrStr ( )
}
2018-12-12 04:01:41 +03:00
// SetConnMaxLifetime sets the maximum amount of time a connection may be reused.
func ( engine * Engine ) SetConnMaxLifetime ( d time . Duration ) {
2020-03-22 18:12:55 +03:00
engine . DB ( ) . SetConnMaxLifetime ( d )
2018-12-12 04:01:41 +03:00
}
2016-11-04 01:16:01 +03:00
// SetMaxOpenConns is only available for go 1.2+
func ( engine * Engine ) SetMaxOpenConns ( conns int ) {
2020-03-22 18:12:55 +03:00
engine . DB ( ) . SetMaxOpenConns ( conns )
2016-11-04 01:16:01 +03:00
}
// SetMaxIdleConns set the max idle connections on pool, default is 2
func ( engine * Engine ) SetMaxIdleConns ( conns int ) {
2020-03-22 18:12:55 +03:00
engine . DB ( ) . SetMaxIdleConns ( conns )
2016-11-04 01:16:01 +03:00
}
// SetDefaultCacher set the default cacher. Xorm's default not enable cacher.
2020-03-22 18:12:55 +03:00
func ( engine * Engine ) SetDefaultCacher ( cacher caches . Cacher ) {
engine . cacherMgr . SetDefaultCacher ( cacher )
2016-11-04 01:16:01 +03:00
}
2018-01-27 18:20:59 +03:00
// GetDefaultCacher returns the default cacher
2020-03-22 18:12:55 +03:00
func ( engine * Engine ) GetDefaultCacher ( ) caches . Cacher {
return engine . cacherMgr . GetDefaultCacher ( )
2018-01-27 18:20:59 +03:00
}
2016-11-04 01:16:01 +03:00
// NoCache If you has set default cacher, and you want temporilly stop use cache,
// you can use NoCache()
func ( engine * Engine ) NoCache ( ) * Session {
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . NoCache ( )
}
// NoCascade If you do not want to auto cascade load object
func ( engine * Engine ) NoCascade ( ) * Session {
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . NoCascade ( )
}
// MapCacher Set a table use a special cacher
2020-03-22 18:12:55 +03:00
func ( engine * Engine ) MapCacher ( bean interface { } , cacher caches . Cacher ) error {
engine . SetCacher ( dialects . FullTableName ( engine . dialect , engine . GetTableMapper ( ) , bean , true ) , cacher )
2017-04-07 04:47:25 +03:00
return nil
2016-11-04 01:16:01 +03:00
}
// NewDB provides an interface to operate database directly
func ( engine * Engine ) NewDB ( ) ( * core . DB , error ) {
2020-03-22 18:12:55 +03:00
return core . Open ( engine . driverName , engine . dataSourceName )
2016-11-04 01:16:01 +03:00
}
// DB return the wrapper of sql.DB
func ( engine * Engine ) DB ( ) * core . DB {
2020-03-25 17:32:23 +03:00
return engine . db
2016-11-04 01:16:01 +03:00
}
// Dialect return database dialect
2020-03-22 18:12:55 +03:00
func ( engine * Engine ) Dialect ( ) dialects . Dialect {
2016-11-04 01:16:01 +03:00
return engine . dialect
}
// NewSession New a session
func ( engine * Engine ) NewSession ( ) * Session {
2020-06-15 23:46:01 +03:00
return newSession ( engine )
2016-11-04 01:16:01 +03:00
}
// Close the engine
func ( engine * Engine ) Close ( ) error {
2020-03-22 18:12:55 +03:00
return engine . DB ( ) . Close ( )
2016-11-04 01:16:01 +03:00
}
// Ping tests if database is alive
func ( engine * Engine ) Ping ( ) error {
session := engine . NewSession ( )
defer session . Close ( )
return session . Ping ( )
}
2017-01-23 12:11:18 +03:00
// SQL method let's you manually write raw SQL and operate
2016-11-04 01:16:01 +03:00
// For example:
//
// engine.SQL("select * from user").Find(&users)
//
// This code will execute "select * from user" and set the records to users
func ( engine * Engine ) SQL ( query interface { } , args ... interface { } ) * Session {
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . SQL ( query , args ... )
}
// NoAutoTime Default if your struct has "created" or "updated" filed tag, the fields
// will automatically be filled with current time when Insert or Update
// invoked. Call NoAutoTime if you dont' want to fill automatically.
func ( engine * Engine ) NoAutoTime ( ) * Session {
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . NoAutoTime ( )
}
// NoAutoCondition disable auto generate Where condition from bean or not
func ( engine * Engine ) NoAutoCondition ( no ... bool ) * Session {
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . NoAutoCondition ( no ... )
}
2020-03-22 18:12:55 +03:00
func ( engine * Engine ) loadTableInfo ( table * schemas . Table ) error {
2020-03-25 17:32:23 +03:00
colSeq , cols , err := engine . dialect . GetColumns ( engine . db , engine . defaultContext , table . Name )
2019-10-02 23:47:20 +03:00
if err != nil {
return err
}
for _ , name := range colSeq {
table . AddColumn ( cols [ name ] )
}
2020-03-25 17:32:23 +03:00
indexes , err := engine . dialect . GetIndexes ( engine . db , engine . defaultContext , table . Name )
2019-10-02 23:47:20 +03:00
if err != nil {
return err
}
table . Indexes = indexes
2020-03-22 18:12:55 +03:00
var seq int
2019-10-02 23:47:20 +03:00
for _ , index := range indexes {
for _ , name := range index . Cols {
2021-01-05 09:28:51 +03:00
parts := strings . Split ( strings . TrimSpace ( name ) , " " )
2020-03-22 18:12:55 +03:00
if len ( parts ) > 1 {
if parts [ 1 ] == "DESC" {
seq = 1
2021-01-05 09:28:51 +03:00
} else if parts [ 1 ] == "ASC" {
seq = 0
2020-03-22 18:12:55 +03:00
}
}
2021-01-05 09:28:51 +03:00
var colName = strings . Trim ( parts [ 0 ] , ` " ` )
if col := table . GetColumn ( colName ) ; col != nil {
2019-10-02 23:47:20 +03:00
col . Indexes [ index . Name ] = index . Type
} else {
2020-03-22 18:12:55 +03:00
return fmt . Errorf ( "Unknown col %s seq %d, in index %v of table %v, columns %v" , name , seq , index . Name , table . Name , table . ColumnsSeq ( ) )
2019-10-02 23:47:20 +03:00
}
}
}
return nil
}
2016-11-04 01:16:01 +03:00
// DBMetas Retrieve all tables, columns, indexes' informations from database.
2020-03-22 18:12:55 +03:00
func ( engine * Engine ) DBMetas ( ) ( [ ] * schemas . Table , error ) {
2020-03-25 17:32:23 +03:00
tables , err := engine . dialect . GetTables ( engine . db , engine . defaultContext )
2016-11-04 01:16:01 +03:00
if err != nil {
return nil , err
}
for _ , table := range tables {
2019-10-02 23:47:20 +03:00
if err = engine . loadTableInfo ( table ) ; err != nil {
2016-11-04 01:16:01 +03:00
return nil , err
}
}
return tables , nil
}
// DumpAllToFile dump database all table structs and data to a file
2020-03-22 18:12:55 +03:00
func ( engine * Engine ) DumpAllToFile ( fp string , tp ... schemas . DBType ) error {
2016-11-04 01:16:01 +03:00
f , err := os . Create ( fp )
if err != nil {
return err
}
defer f . Close ( )
2017-01-23 12:11:18 +03:00
return engine . DumpAll ( f , tp ... )
2016-11-04 01:16:01 +03:00
}
// DumpAll dump database all table structs and data to w
2020-03-22 18:12:55 +03:00
func ( engine * Engine ) DumpAll ( w io . Writer , tp ... schemas . DBType ) error {
2017-01-23 12:11:18 +03:00
tables , err := engine . DBMetas ( )
if err != nil {
return err
}
return engine . DumpTables ( tables , w , tp ... )
2016-11-04 01:16:01 +03:00
}
// DumpTablesToFile dump specified tables to SQL file.
2020-03-22 18:12:55 +03:00
func ( engine * Engine ) DumpTablesToFile ( tables [ ] * schemas . Table , fp string , tp ... schemas . DBType ) error {
2016-11-04 01:16:01 +03:00
f , err := os . Create ( fp )
if err != nil {
return err
}
defer f . Close ( )
return engine . DumpTables ( tables , f , tp ... )
}
// DumpTables dump specify tables to io.Writer
2020-03-22 18:12:55 +03:00
func ( engine * Engine ) DumpTables ( tables [ ] * schemas . Table , w io . Writer , tp ... schemas . DBType ) error {
2016-11-04 01:16:01 +03:00
return engine . dumpTables ( tables , w , tp ... )
}
2020-07-12 00:07:52 +03:00
func formatColumnValue ( dstDialect dialects . Dialect , d interface { } , col * schemas . Column ) string {
if d == nil {
return "NULL"
}
if dq , ok := d . ( bool ) ; ok && ( dstDialect . URI ( ) . DBType == schemas . SQLITE ||
dstDialect . URI ( ) . DBType == schemas . MSSQL ) {
if dq {
return "1"
}
return "0"
}
if col . SQLType . IsText ( ) {
var v = fmt . Sprintf ( "%s" , d )
return "'" + strings . Replace ( v , "'" , "''" , - 1 ) + "'"
} else if col . SQLType . IsTime ( ) {
var v = fmt . Sprintf ( "%s" , d )
if strings . HasSuffix ( v , " +0000 UTC" ) {
return fmt . Sprintf ( "'%s'" , v [ 0 : len ( v ) - len ( " +0000 UTC" ) ] )
} else if strings . HasSuffix ( v , " +0000 +0000" ) {
return fmt . Sprintf ( "'%s'" , v [ 0 : len ( v ) - len ( " +0000 +0000" ) ] )
}
return "'" + strings . Replace ( v , "'" , "''" , - 1 ) + "'"
} else if col . SQLType . IsBlob ( ) {
if reflect . TypeOf ( d ) . Kind ( ) == reflect . Slice {
return fmt . Sprintf ( "%s" , dstDialect . FormatBytes ( d . ( [ ] byte ) ) )
} else if reflect . TypeOf ( d ) . Kind ( ) == reflect . String {
return fmt . Sprintf ( "'%s'" , d . ( string ) )
}
} else if col . SQLType . IsNumeric ( ) {
switch reflect . TypeOf ( d ) . Kind ( ) {
case reflect . Slice :
if col . SQLType . Name == schemas . Bool {
return fmt . Sprintf ( "%v" , strconv . FormatBool ( d . ( [ ] byte ) [ 0 ] != byte ( '0' ) ) )
}
return fmt . Sprintf ( "%s" , string ( d . ( [ ] byte ) ) )
case reflect . Int16 , reflect . Int8 , reflect . Int32 , reflect . Int64 , reflect . Int :
if col . SQLType . Name == schemas . Bool {
v := reflect . ValueOf ( d ) . Int ( ) > 0
if dstDialect . URI ( ) . DBType == schemas . SQLITE {
if v {
return "1"
}
return "0"
}
return fmt . Sprintf ( "%v" , strconv . FormatBool ( v ) )
}
return fmt . Sprintf ( "%v" , d )
case reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uint64 :
if col . SQLType . Name == schemas . Bool {
v := reflect . ValueOf ( d ) . Uint ( ) > 0
if dstDialect . URI ( ) . DBType == schemas . SQLITE {
if v {
return "1"
}
return "0"
}
return fmt . Sprintf ( "%v" , strconv . FormatBool ( v ) )
}
return fmt . Sprintf ( "%v" , d )
default :
return fmt . Sprintf ( "%v" , d )
}
}
s := fmt . Sprintf ( "%v" , d )
if strings . Contains ( s , ":" ) || strings . Contains ( s , "-" ) {
if strings . HasSuffix ( s , " +0000 UTC" ) {
return fmt . Sprintf ( "'%s'" , s [ 0 : len ( s ) - len ( " +0000 UTC" ) ] )
}
return fmt . Sprintf ( "'%s'" , s )
}
return s
}
2017-01-23 12:11:18 +03:00
// dumpTables dump database all table structs and data to w with specify db type
2020-03-22 18:12:55 +03:00
func ( engine * Engine ) dumpTables ( tables [ ] * schemas . Table , w io . Writer , tp ... schemas . DBType ) error {
var dstDialect dialects . Dialect
2016-11-04 01:16:01 +03:00
if len ( tp ) == 0 {
2020-03-22 18:12:55 +03:00
dstDialect = engine . dialect
2016-11-04 01:16:01 +03:00
} else {
2020-03-22 18:12:55 +03:00
dstDialect = dialects . QueryDialect ( tp [ 0 ] )
if dstDialect == nil {
2017-01-03 11:20:28 +03:00
return errors . New ( "Unsupported database type" )
2016-11-04 01:16:01 +03:00
}
2020-03-22 18:12:55 +03:00
uri := engine . dialect . URI ( )
2020-07-12 00:07:52 +03:00
destURI := dialects . URI {
DBType : tp [ 0 ] ,
DBName : uri . DBName ,
}
2020-03-25 17:32:23 +03:00
dstDialect . Init ( & destURI )
2016-11-04 01:16:01 +03:00
}
2020-03-22 18:12:55 +03:00
_ , err := io . WriteString ( w , fmt . Sprintf ( "/*Generated by xorm %s, from %s to %s*/\n\n" ,
time . Now ( ) . In ( engine . TZLocation ) . Format ( "2006-01-02 15:04:05" ) , engine . dialect . URI ( ) . DBType , dstDialect . URI ( ) . DBType ) )
2016-11-04 01:16:01 +03:00
if err != nil {
return err
}
for i , table := range tables {
2020-03-22 18:12:55 +03:00
tableName := table . Name
if dstDialect . URI ( ) . Schema != "" {
tableName = fmt . Sprintf ( "%s.%s" , dstDialect . URI ( ) . Schema , table . Name )
}
originalTableName := table . Name
if engine . dialect . URI ( ) . Schema != "" {
originalTableName = fmt . Sprintf ( "%s.%s" , engine . dialect . URI ( ) . Schema , table . Name )
}
2016-11-04 01:16:01 +03:00
if i > 0 {
_ , err = io . WriteString ( w , "\n" )
if err != nil {
return err
}
}
2020-03-22 18:12:55 +03:00
sqls , _ := dstDialect . CreateTableSQL ( table , tableName )
for _ , s := range sqls {
_ , err = io . WriteString ( w , s + ";\n" )
if err != nil {
return err
}
2016-11-04 01:16:01 +03:00
}
2020-03-22 18:12:55 +03:00
if len ( table . PKColumns ( ) ) > 0 && dstDialect . URI ( ) . DBType == schemas . MSSQL {
fmt . Fprintf ( w , "SET IDENTITY_INSERT [%s] ON;\n" , table . Name )
}
2016-11-04 01:16:01 +03:00
for _ , index := range table . Indexes {
2020-03-22 18:12:55 +03:00
_ , err = io . WriteString ( w , dstDialect . CreateIndexSQL ( table . Name , index ) + ";\n" )
2016-11-04 01:16:01 +03:00
if err != nil {
return err
}
}
2017-01-23 12:11:18 +03:00
cols := table . ColumnsSeq ( )
2020-03-22 18:12:55 +03:00
colNames := engine . dialect . Quoter ( ) . Join ( cols , ", " )
destColNames := dstDialect . Quoter ( ) . Join ( cols , ", " )
2017-01-23 12:11:18 +03:00
2020-03-22 18:12:55 +03:00
rows , err := engine . DB ( ) . QueryContext ( engine . defaultContext , "SELECT " + colNames + " FROM " + engine . Quote ( originalTableName ) )
2016-11-04 01:16:01 +03:00
if err != nil {
return err
}
defer rows . Close ( )
for rows . Next ( ) {
dest := make ( [ ] interface { } , len ( cols ) )
err = rows . ScanSlice ( & dest )
if err != nil {
return err
}
2020-03-22 18:12:55 +03:00
_ , err = io . WriteString ( w , "INSERT INTO " + dstDialect . Quoter ( ) . Quote ( tableName ) + " (" + destColNames + ") VALUES (" )
2016-11-04 01:16:01 +03:00
if err != nil {
return err
}
var temp string
for i , d := range dest {
col := table . GetColumn ( cols [ i ] )
2017-01-23 12:11:18 +03:00
if col == nil {
return errors . New ( "unknow column error" )
}
2020-07-12 00:07:52 +03:00
temp += "," + formatColumnValue ( dstDialect , d , col )
2016-11-04 01:16:01 +03:00
}
2020-07-12 00:07:52 +03:00
_ , err = io . WriteString ( w , temp [ 1 : ] + ");\n" )
2016-11-04 01:16:01 +03:00
if err != nil {
return err
}
}
2017-02-10 18:02:26 +03:00
// FIXME: Hack for postgres
2020-03-22 18:12:55 +03:00
if dstDialect . URI ( ) . DBType == schemas . POSTGRES && table . AutoIncrColumn ( ) != nil {
_ , err = io . WriteString ( w , "SELECT setval('" + tableName + "_id_seq', COALESCE((SELECT MAX(" + table . AutoIncrColumn ( ) . Name + ") + 1 FROM " + dstDialect . Quoter ( ) . Quote ( tableName ) + "), 1), false);\n" )
2017-02-10 18:02:26 +03:00
if err != nil {
return err
}
}
2016-11-04 01:16:01 +03:00
}
return nil
}
// Cascade use cascade or not
func ( engine * Engine ) Cascade ( trueOrFalse ... bool ) * Session {
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . Cascade ( trueOrFalse ... )
}
// Where method provide a condition query
func ( engine * Engine ) Where ( query interface { } , args ... interface { } ) * Session {
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . Where ( query , args ... )
}
2017-01-25 17:54:52 +03:00
// ID method provoide a condition as (id) = ?
2016-11-04 01:16:01 +03:00
func ( engine * Engine ) ID ( id interface { } ) * Session {
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . ID ( id )
}
// Before apply before Processor, affected bean is passed to closure arg
func ( engine * Engine ) Before ( closures func ( interface { } ) ) * Session {
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . Before ( closures )
}
// After apply after insert Processor, affected bean is passed to closure arg
func ( engine * Engine ) After ( closures func ( interface { } ) ) * Session {
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . After ( closures )
}
// Charset set charset when create table, only support mysql now
func ( engine * Engine ) Charset ( charset string ) * Session {
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . Charset ( charset )
}
// StoreEngine set store engine when create table, only support mysql now
func ( engine * Engine ) StoreEngine ( storeEngine string ) * Session {
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . StoreEngine ( storeEngine )
}
// Distinct use for distinct columns. Caution: when you are using cache,
// distinct will not be cached because cache system need id,
// but distinct will not provide id
func ( engine * Engine ) Distinct ( columns ... string ) * Session {
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . Distinct ( columns ... )
}
// Select customerize your select columns or contents
func ( engine * Engine ) Select ( str string ) * Session {
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . Select ( str )
}
2017-01-23 12:11:18 +03:00
// Cols only use the parameters as select or update columns
2016-11-04 01:16:01 +03:00
func ( engine * Engine ) Cols ( columns ... string ) * Session {
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . Cols ( columns ... )
}
// AllCols indicates that all columns should be use
func ( engine * Engine ) AllCols ( ) * Session {
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . AllCols ( )
}
// MustCols specify some columns must use even if they are empty
func ( engine * Engine ) MustCols ( columns ... string ) * Session {
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . MustCols ( columns ... )
}
// UseBool xorm automatically retrieve condition according struct, but
// if struct has bool field, it will ignore them. So use UseBool
// to tell system to do not ignore them.
2017-01-23 12:11:18 +03:00
// If no parameters, it will use all the bool field of struct, or
// it will use parameters's columns
2016-11-04 01:16:01 +03:00
func ( engine * Engine ) UseBool ( columns ... string ) * Session {
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . UseBool ( columns ... )
}
2017-01-23 12:11:18 +03:00
// Omit only not use the parameters as select or update columns
2016-11-04 01:16:01 +03:00
func ( engine * Engine ) Omit ( columns ... string ) * Session {
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . Omit ( columns ... )
}
// Nullable set null when column is zero-value and nullable for update
func ( engine * Engine ) Nullable ( columns ... string ) * Session {
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . Nullable ( columns ... )
}
// In will generate "column IN (?, ?)"
func ( engine * Engine ) In ( column string , args ... interface { } ) * Session {
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . In ( column , args ... )
}
2017-08-22 14:39:52 +03:00
// NotIn will generate "column NOT IN (?, ?)"
func ( engine * Engine ) NotIn ( column string , args ... interface { } ) * Session {
session := engine . NewSession ( )
session . isAutoClose = true
return session . NotIn ( column , args ... )
}
2016-11-04 01:16:01 +03:00
// Incr provides a update string like "column = column + ?"
func ( engine * Engine ) Incr ( column string , arg ... interface { } ) * Session {
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . Incr ( column , arg ... )
}
// Decr provides a update string like "column = column - ?"
func ( engine * Engine ) Decr ( column string , arg ... interface { } ) * Session {
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . Decr ( column , arg ... )
}
// SetExpr provides a update string like "column = {expression}"
2019-09-24 16:22:39 +03:00
func ( engine * Engine ) SetExpr ( column string , expression interface { } ) * Session {
2016-11-04 01:16:01 +03:00
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . SetExpr ( column , expression )
}
// Table temporarily change the Get, Find, Update's table
func ( engine * Engine ) Table ( tableNameOrBean interface { } ) * Session {
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . Table ( tableNameOrBean )
}
// Alias set the table alias
func ( engine * Engine ) Alias ( alias string ) * Session {
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . Alias ( alias )
}
// Limit will generate "LIMIT start, limit"
func ( engine * Engine ) Limit ( limit int , start ... int ) * Session {
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . Limit ( limit , start ... )
}
// Desc will generate "ORDER BY column1 DESC, column2 DESC"
func ( engine * Engine ) Desc ( colNames ... string ) * Session {
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . Desc ( colNames ... )
}
// Asc will generate "ORDER BY column1,column2 Asc"
// This method can chainable use.
//
// engine.Desc("name").Asc("age").Find(&users)
// // SELECT * FROM user ORDER BY name DESC, age ASC
//
func ( engine * Engine ) Asc ( colNames ... string ) * Session {
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . Asc ( colNames ... )
}
// OrderBy will generate "ORDER BY order"
func ( engine * Engine ) OrderBy ( order string ) * Session {
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . OrderBy ( order )
}
2018-01-27 18:20:59 +03:00
// Prepare enables prepare statement
func ( engine * Engine ) Prepare ( ) * Session {
session := engine . NewSession ( )
session . isAutoClose = true
return session . Prepare ( )
}
2016-11-04 01:16:01 +03:00
// Join the join_operator should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN
func ( engine * Engine ) Join ( joinOperator string , tablename interface { } , condition string , args ... interface { } ) * Session {
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . Join ( joinOperator , tablename , condition , args ... )
}
// GroupBy generate group by statement
func ( engine * Engine ) GroupBy ( keys string ) * Session {
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . GroupBy ( keys )
}
// Having generate having statement
func ( engine * Engine ) Having ( conditions string ) * Session {
session := engine . NewSession ( )
2017-08-22 14:39:52 +03:00
session . isAutoClose = true
2016-11-04 01:16:01 +03:00
return session . Having ( conditions )
}
// Table table struct
type Table struct {
2020-03-22 18:12:55 +03:00
* schemas . Table
2016-11-04 01:16:01 +03:00
Name string
}
2017-04-07 04:47:25 +03:00
// IsValid if table is valid
func ( t * Table ) IsValid ( ) bool {
return t . Table != nil && len ( t . Name ) > 0
}
2016-11-04 01:16:01 +03:00
// TableInfo get table info according to bean's content
2020-03-22 18:12:55 +03:00
func ( engine * Engine ) TableInfo ( bean interface { } ) ( * schemas . Table , error ) {
v := utils . ReflectValue ( bean )
return engine . tagParser . ParseWithCache ( v )
2016-11-04 01:16:01 +03:00
}
// IsTableEmpty if a table has any reocrd
func ( engine * Engine ) IsTableEmpty ( bean interface { } ) ( bool , error ) {
session := engine . NewSession ( )
defer session . Close ( )
return session . IsTableEmpty ( bean )
}
// IsTableExist if a table is exist
func ( engine * Engine ) IsTableExist ( beanOrTableName interface { } ) ( bool , error ) {
session := engine . NewSession ( )
defer session . Close ( )
return session . IsTableExist ( beanOrTableName )
}
2020-03-22 18:12:55 +03:00
// TableName returns table name with schema prefix if has
func ( engine * Engine ) TableName ( bean interface { } , includeSchema ... bool ) string {
return dialects . FullTableName ( engine . dialect , engine . GetTableMapper ( ) , bean , includeSchema ... )
2017-01-03 11:20:28 +03:00
}
2016-11-04 01:16:01 +03:00
// CreateIndexes create indexes
func ( engine * Engine ) CreateIndexes ( bean interface { } ) error {
session := engine . NewSession ( )
defer session . Close ( )
return session . CreateIndexes ( bean )
}
// CreateUniques create uniques
func ( engine * Engine ) CreateUniques ( bean interface { } ) error {
session := engine . NewSession ( )
defer session . Close ( )
return session . CreateUniques ( bean )
}
// ClearCacheBean if enabled cache, clear the cache bean
func ( engine * Engine ) ClearCacheBean ( bean interface { } , id string ) error {
2020-03-22 18:12:55 +03:00
tableName := dialects . FullTableName ( engine . dialect , engine . GetTableMapper ( ) , bean )
cacher := engine . GetCacher ( tableName )
2016-11-04 01:16:01 +03:00
if cacher != nil {
cacher . ClearIds ( tableName )
cacher . DelBean ( tableName , id )
}
return nil
}
// ClearCache if enabled cache, clear some tables' cache
func ( engine * Engine ) ClearCache ( beans ... interface { } ) error {
for _ , bean := range beans {
2020-03-22 18:12:55 +03:00
tableName := dialects . FullTableName ( engine . dialect , engine . GetTableMapper ( ) , bean )
cacher := engine . GetCacher ( tableName )
2016-11-04 01:16:01 +03:00
if cacher != nil {
cacher . ClearIds ( tableName )
cacher . ClearBeans ( tableName )
}
}
return nil
}
2020-03-22 18:12:55 +03:00
// UnMapType remove table from tables cache
func ( engine * Engine ) UnMapType ( t reflect . Type ) {
engine . tagParser . ClearCacheTable ( t )
}
2016-11-04 01:16:01 +03:00
// Sync the new struct changes to database, this method will automatically add
// table, column, index, unique. but will not delete or change anything.
// If you change some field, you should change the database manually.
func ( engine * Engine ) Sync ( beans ... interface { } ) error {
2017-08-22 14:39:52 +03:00
session := engine . NewSession ( )
defer session . Close ( )
2016-11-04 01:16:01 +03:00
for _ , bean := range beans {
2020-03-22 18:12:55 +03:00
v := utils . ReflectValue ( bean )
tableNameNoSchema := dialects . FullTableName ( engine . dialect , engine . GetTableMapper ( ) , bean )
table , err := engine . tagParser . ParseWithCache ( v )
2017-04-07 04:47:25 +03:00
if err != nil {
return err
}
2016-11-04 01:16:01 +03:00
2018-07-20 05:10:17 +03:00
isExist , err := session . Table ( bean ) . isTableExist ( tableNameNoSchema )
2016-11-04 01:16:01 +03:00
if err != nil {
return err
}
if ! isExist {
2017-08-22 14:39:52 +03:00
err = session . createTable ( bean )
2016-11-04 01:16:01 +03:00
if err != nil {
return err
}
}
/ * isEmpty , err := engine . IsEmptyTable ( bean )
if err != nil {
return err
} * /
var isEmpty bool
if isEmpty {
2017-08-22 14:39:52 +03:00
err = session . dropTable ( bean )
2016-11-04 01:16:01 +03:00
if err != nil {
return err
}
2017-08-22 14:39:52 +03:00
err = session . createTable ( bean )
2016-11-04 01:16:01 +03:00
if err != nil {
return err
}
} else {
for _ , col := range table . Columns ( ) {
2020-03-25 17:32:23 +03:00
isExist , err := engine . dialect . IsColumnExist ( engine . db , session . ctx , tableNameNoSchema , col . Name )
2016-11-04 01:16:01 +03:00
if err != nil {
return err
}
if ! isExist {
2020-03-22 18:12:55 +03:00
if err := session . statement . SetRefBean ( bean ) ; err != nil {
2017-05-02 03:50:33 +03:00
return err
}
2016-11-04 01:16:01 +03:00
err = session . addColumn ( col . Name )
if err != nil {
return err
}
}
}
for name , index := range table . Indexes {
2020-03-22 18:12:55 +03:00
if err := session . statement . SetRefBean ( bean ) ; err != nil {
2017-05-02 03:50:33 +03:00
return err
}
2020-03-22 18:12:55 +03:00
if index . Type == schemas . UniqueType {
2018-07-20 05:10:17 +03:00
isExist , err := session . isIndexExist2 ( tableNameNoSchema , index . Cols , true )
2016-11-04 01:16:01 +03:00
if err != nil {
return err
}
if ! isExist {
2020-03-22 18:12:55 +03:00
if err := session . statement . SetRefBean ( bean ) ; err != nil {
2017-05-02 03:50:33 +03:00
return err
}
2018-07-20 05:10:17 +03:00
err = session . addUnique ( tableNameNoSchema , name )
2016-11-04 01:16:01 +03:00
if err != nil {
return err
}
}
2020-03-22 18:12:55 +03:00
} else if index . Type == schemas . IndexType {
2018-07-20 05:10:17 +03:00
isExist , err := session . isIndexExist2 ( tableNameNoSchema , index . Cols , false )
2016-11-04 01:16:01 +03:00
if err != nil {
return err
}
if ! isExist {
2020-03-22 18:12:55 +03:00
if err := session . statement . SetRefBean ( bean ) ; err != nil {
2017-05-02 03:50:33 +03:00
return err
}
2018-07-20 05:10:17 +03:00
err = session . addIndex ( tableNameNoSchema , name )
2016-11-04 01:16:01 +03:00
if err != nil {
return err
}
}
} else {
return errors . New ( "unknow index type" )
}
}
}
}
return nil
}
// Sync2 synchronize structs to database tables
func ( engine * Engine ) Sync2 ( beans ... interface { } ) error {
s := engine . NewSession ( )
defer s . Close ( )
return s . Sync2 ( beans ... )
}
// CreateTables create tabls according bean
func ( engine * Engine ) CreateTables ( beans ... interface { } ) error {
session := engine . NewSession ( )
defer session . Close ( )
err := session . Begin ( )
if err != nil {
return err
}
for _ , bean := range beans {
2017-08-22 14:39:52 +03:00
err = session . createTable ( bean )
2016-11-04 01:16:01 +03:00
if err != nil {
session . Rollback ( )
return err
}
}
return session . Commit ( )
}
// DropTables drop specify tables
func ( engine * Engine ) DropTables ( beans ... interface { } ) error {
session := engine . NewSession ( )
defer session . Close ( )
err := session . Begin ( )
if err != nil {
return err
}
for _ , bean := range beans {
2017-08-22 14:39:52 +03:00
err = session . dropTable ( bean )
2016-11-04 01:16:01 +03:00
if err != nil {
session . Rollback ( )
return err
}
}
return session . Commit ( )
}
2017-08-22 14:39:52 +03:00
// DropIndexes drop indexes of a table
func ( engine * Engine ) DropIndexes ( bean interface { } ) error {
2016-11-04 01:16:01 +03:00
session := engine . NewSession ( )
defer session . Close ( )
2017-08-22 14:39:52 +03:00
return session . DropIndexes ( bean )
2016-11-04 01:16:01 +03:00
}
// Exec raw sql
2019-06-23 18:22:43 +03:00
func ( engine * Engine ) Exec ( sqlOrArgs ... interface { } ) ( sql . Result , error ) {
2016-11-04 01:16:01 +03:00
session := engine . NewSession ( )
defer session . Close ( )
2019-06-23 18:22:43 +03:00
return session . Exec ( sqlOrArgs ... )
2016-11-04 01:16:01 +03:00
}
// Query a raw sql and return records as []map[string][]byte
2019-06-23 18:22:43 +03:00
func ( engine * Engine ) Query ( sqlOrArgs ... interface { } ) ( resultsSlice [ ] map [ string ] [ ] byte , err error ) {
2016-11-04 01:16:01 +03:00
session := engine . NewSession ( )
defer session . Close ( )
2019-06-23 18:22:43 +03:00
return session . Query ( sqlOrArgs ... )
2016-11-04 01:16:01 +03:00
}
2017-04-07 04:47:25 +03:00
// QueryString runs a raw sql and return records as []map[string]string
2019-06-23 18:22:43 +03:00
func ( engine * Engine ) QueryString ( sqlOrArgs ... interface { } ) ( [ ] map [ string ] string , error ) {
2017-04-07 04:47:25 +03:00
session := engine . NewSession ( )
defer session . Close ( )
2019-06-23 18:22:43 +03:00
return session . QueryString ( sqlOrArgs ... )
2017-04-07 04:47:25 +03:00
}
2017-09-13 08:18:22 +03:00
// QueryInterface runs a raw sql and return records as []map[string]interface{}
2019-06-23 18:22:43 +03:00
func ( engine * Engine ) QueryInterface ( sqlOrArgs ... interface { } ) ( [ ] map [ string ] interface { } , error ) {
2017-09-13 08:18:22 +03:00
session := engine . NewSession ( )
defer session . Close ( )
2019-06-23 18:22:43 +03:00
return session . QueryInterface ( sqlOrArgs ... )
2017-09-13 08:18:22 +03:00
}
2016-11-04 01:16:01 +03:00
// Insert one or more records
func ( engine * Engine ) Insert ( beans ... interface { } ) ( int64 , error ) {
session := engine . NewSession ( )
defer session . Close ( )
return session . Insert ( beans ... )
}
// InsertOne insert only one record
func ( engine * Engine ) InsertOne ( bean interface { } ) ( int64 , error ) {
session := engine . NewSession ( )
defer session . Close ( )
return session . InsertOne ( bean )
}
// Update records, bean's non-empty fields are updated contents,
// condiBean' non-empty filds are conditions
// CAUTION:
// 1.bool will defaultly be updated content nor conditions
// You should call UseBool if you have bool to use.
// 2.float32 & float64 may be not inexact as conditions
func ( engine * Engine ) Update ( bean interface { } , condiBeans ... interface { } ) ( int64 , error ) {
session := engine . NewSession ( )
defer session . Close ( )
return session . Update ( bean , condiBeans ... )
}
// Delete records, bean's non-empty fields are conditions
func ( engine * Engine ) Delete ( bean interface { } ) ( int64 , error ) {
session := engine . NewSession ( )
defer session . Close ( )
return session . Delete ( bean )
}
// Get retrieve one record from table, bean's non-empty fields
// are conditions
func ( engine * Engine ) Get ( bean interface { } ) ( bool , error ) {
session := engine . NewSession ( )
defer session . Close ( )
return session . Get ( bean )
}
2017-08-22 14:39:52 +03:00
// Exist returns true if the record exist otherwise return false
func ( engine * Engine ) Exist ( bean ... interface { } ) ( bool , error ) {
session := engine . NewSession ( )
defer session . Close ( )
return session . Exist ( bean ... )
}
2016-11-04 01:16:01 +03:00
// Find retrieve records from table, condiBeans's non-empty fields
// are conditions. beans could be []Struct, []*Struct, map[int64]Struct
// map[int64]*Struct
func ( engine * Engine ) Find ( beans interface { } , condiBeans ... interface { } ) error {
session := engine . NewSession ( )
defer session . Close ( )
return session . Find ( beans , condiBeans ... )
}
2018-07-20 05:10:17 +03:00
// FindAndCount find the results and also return the counts
func ( engine * Engine ) FindAndCount ( rowsSlicePtr interface { } , condiBean ... interface { } ) ( int64 , error ) {
session := engine . NewSession ( )
defer session . Close ( )
return session . FindAndCount ( rowsSlicePtr , condiBean ... )
}
2016-11-04 01:16:01 +03:00
// Iterate record by record handle records from table, bean's non-empty fields
// are conditions.
func ( engine * Engine ) Iterate ( bean interface { } , fun IterFunc ) error {
session := engine . NewSession ( )
defer session . Close ( )
return session . Iterate ( bean , fun )
}
// Rows return sql.Rows compatible Rows obj, as a forward Iterator object for iterating record by record, bean's non-empty fields
// are conditions.
func ( engine * Engine ) Rows ( bean interface { } ) ( * Rows , error ) {
session := engine . NewSession ( )
return session . Rows ( bean )
}
// Count counts the records. bean's non-empty fields are conditions.
2017-08-22 14:39:52 +03:00
func ( engine * Engine ) Count ( bean ... interface { } ) ( int64 , error ) {
2016-11-04 01:16:01 +03:00
session := engine . NewSession ( )
defer session . Close ( )
2017-08-22 14:39:52 +03:00
return session . Count ( bean ... )
2016-11-04 01:16:01 +03:00
}
// Sum sum the records by some column. bean's non-empty fields are conditions.
func ( engine * Engine ) Sum ( bean interface { } , colName string ) ( float64 , error ) {
session := engine . NewSession ( )
defer session . Close ( )
return session . Sum ( bean , colName )
}
2017-08-22 14:39:52 +03:00
// SumInt sum the records by some column. bean's non-empty fields are conditions.
func ( engine * Engine ) SumInt ( bean interface { } , colName string ) ( int64 , error ) {
session := engine . NewSession ( )
defer session . Close ( )
return session . SumInt ( bean , colName )
}
2016-11-04 01:16:01 +03:00
// Sums sum the records by some columns. bean's non-empty fields are conditions.
func ( engine * Engine ) Sums ( bean interface { } , colNames ... string ) ( [ ] float64 , error ) {
session := engine . NewSession ( )
defer session . Close ( )
return session . Sums ( bean , colNames ... )
}
// SumsInt like Sums but return slice of int64 instead of float64.
func ( engine * Engine ) SumsInt ( bean interface { } , colNames ... string ) ( [ ] int64 , error ) {
session := engine . NewSession ( )
defer session . Close ( )
return session . SumsInt ( bean , colNames ... )
}
// ImportFile SQL DDL file
func ( engine * Engine ) ImportFile ( ddlPath string ) ( [ ] sql . Result , error ) {
2020-03-22 18:12:55 +03:00
session := engine . NewSession ( )
defer session . Close ( )
return session . ImportFile ( ddlPath )
2016-11-04 01:16:01 +03:00
}
// Import SQL DDL from io.Reader
func ( engine * Engine ) Import ( r io . Reader ) ( [ ] sql . Result , error ) {
2020-03-22 18:12:55 +03:00
session := engine . NewSession ( )
defer session . Close ( )
return session . Import ( r )
2016-11-04 01:16:01 +03:00
}
2017-10-01 19:52:35 +03:00
// nowTime return current time
2020-03-22 18:12:55 +03:00
func ( engine * Engine ) nowTime ( col * schemas . Column ) ( interface { } , time . Time ) {
2016-11-04 01:16:01 +03:00
t := time . Now ( )
2017-10-01 19:52:35 +03:00
var tz = engine . DatabaseTZ
if ! col . DisableTimeZone && col . TimeZone != nil {
tz = col . TimeZone
}
2020-03-22 18:12:55 +03:00
return dialects . FormatTime ( engine . dialect , col . SQLType . Name , t . In ( tz ) ) , t . In ( engine . TZLocation )
2016-11-04 01:16:01 +03:00
}
2018-01-27 18:20:59 +03:00
// GetColumnMapper returns the column name mapper
2020-03-22 18:12:55 +03:00
func ( engine * Engine ) GetColumnMapper ( ) names . Mapper {
return engine . tagParser . GetColumnMapper ( )
2016-11-04 01:16:01 +03:00
}
2017-08-22 14:39:52 +03:00
2018-01-27 18:20:59 +03:00
// GetTableMapper returns the table name mapper
2020-03-22 18:12:55 +03:00
func ( engine * Engine ) GetTableMapper ( ) names . Mapper {
return engine . tagParser . GetTableMapper ( )
2017-08-22 14:39:52 +03:00
}
2017-10-01 19:52:35 +03:00
2018-01-27 18:20:59 +03:00
// GetTZLocation returns time zone of the application
func ( engine * Engine ) GetTZLocation ( ) * time . Location {
return engine . TZLocation
}
// SetTZLocation sets time zone of the application
func ( engine * Engine ) SetTZLocation ( tz * time . Location ) {
engine . TZLocation = tz
}
// GetTZDatabase returns time zone of the database
func ( engine * Engine ) GetTZDatabase ( ) * time . Location {
return engine . DatabaseTZ
}
// SetTZDatabase sets time zone of the database
func ( engine * Engine ) SetTZDatabase ( tz * time . Location ) {
engine . DatabaseTZ = tz
}
2018-07-20 05:10:17 +03:00
// SetSchema sets the schema of database
func ( engine * Engine ) SetSchema ( schema string ) {
2020-03-22 18:12:55 +03:00
engine . dialect . URI ( ) . SetSchema ( schema )
2018-07-20 05:10:17 +03:00
}
2020-06-15 23:46:01 +03:00
func ( engine * Engine ) AddHook ( hook contexts . Hook ) {
engine . db . AddHook ( hook )
}
2018-01-27 18:20:59 +03:00
// Unscoped always disable struct tag "deleted"
func ( engine * Engine ) Unscoped ( ) * Session {
2017-10-01 19:52:35 +03:00
session := engine . NewSession ( )
session . isAutoClose = true
2018-01-27 18:20:59 +03:00
return session . Unscoped ( )
2017-10-01 19:52:35 +03:00
}
2020-03-22 18:12:55 +03:00
func ( engine * Engine ) tbNameWithSchema ( v string ) string {
return dialects . TableNameWithSchema ( engine . dialect , v )
}
2020-06-15 23:46:01 +03:00
// ContextHook creates a session with the context
2020-03-22 18:12:55 +03:00
func ( engine * Engine ) Context ( ctx context . Context ) * Session {
session := engine . NewSession ( )
session . isAutoClose = true
return session . Context ( ctx )
}
// SetDefaultContext set the default context
func ( engine * Engine ) SetDefaultContext ( ctx context . Context ) {
engine . defaultContext = ctx
}
// PingContext tests if database is alive
func ( engine * Engine ) PingContext ( ctx context . Context ) error {
session := engine . NewSession ( )
defer session . Close ( )
return session . PingContext ( ctx )
}
// Transaction Execute sql wrapped in a transaction(abbr as tx), tx will automatic commit if no errors occurred
func ( engine * Engine ) Transaction ( f func ( * Session ) ( interface { } , error ) ) ( interface { } , error ) {
session := engine . NewSession ( )
defer session . Close ( )
if err := session . Begin ( ) ; err != nil {
return nil , err
}
result , err := f ( session )
if err != nil {
2020-07-12 00:07:52 +03:00
return result , err
2020-03-22 18:12:55 +03:00
}
if err := session . Commit ( ) ; err != nil {
2020-07-12 00:07:52 +03:00
return result , err
2020-03-22 18:12:55 +03:00
}
return result , nil
}