xorm/engine.go

1319 lines
37 KiB
Go
Raw Normal View History

2015-04-28 08:25:04 +00: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.
2013-05-03 07:26:51 +00:00
package xorm
import (
"context"
2013-12-18 03:31:32 +00:00
"database/sql"
"errors"
"fmt"
"io"
2013-12-18 03:31:32 +00:00
"os"
"reflect"
"runtime"
2013-12-18 03:31:32 +00:00
"strconv"
"strings"
"time"
2013-12-20 06:53:40 +00:00
"xorm.io/xorm/caches"
"xorm.io/xorm/contexts"
"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"
2013-05-03 07:26:51 +00:00
)
// Engine is the major struct of xorm, it means a database manager.
// Commonly, an application only need one engine
2013-05-03 07:26:51 +00:00
type Engine struct {
cacherMgr *caches.Manager
defaultContext context.Context
dialect dialects.Dialect
engineGroup *EngineGroup
logger log.ContextLogger
tagParser *tags.Parser
db *core.DB
2014-05-02 00:48:51 +00:00
driverName string
dataSourceName string
TZLocation *time.Location // The timezone of the application
DatabaseTZ *time.Location // The timezone of the database
logSessionID bool // create session id
}
// 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
}
return newEngine(driverName, dataSourceName, dialect, db)
}
func newEngine(driverName, dataSourceName string, dialect dialects.Dialect, db *core.DB) (*Engine, error) {
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) {
_ = engine.Close()
})
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
}
// 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)
}
// EnableSessionID if enable session id
func (engine *Engine) EnableSessionID(enable bool) {
engine.logSessionID = enable
}
// SetCacher sets cacher for the table
func (engine *Engine) SetCacher(tableName string, cacher caches.Cacher) {
engine.cacherMgr.SetCacher(tableName, cacher)
}
// GetCacher returns the cachher of the special table
func (engine *Engine) GetCacher(tableName string) caches.Cacher {
return engine.cacherMgr.GetCacher(tableName)
}
// SetQuotePolicy sets the special quote policy
func (engine *Engine) SetQuotePolicy(quotePolicy dialects.QuotePolicy) {
engine.dialect.SetQuotePolicy(quotePolicy)
}
// 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-09 01:52:23 +00:00
// ShowSQL show SQL statement or not on logger if log level is great than INFO
func (engine *Engine) ShowSQL(show ...bool) {
engine.logger.ShowSQL(show...)
engine.DB().Logger = engine.logger
}
// Logger return the logger interface
func (engine *Engine) Logger() log.ContextLogger {
return engine.logger
}
// SetLogger set the new logger
func (engine *Engine) SetLogger(logger interface{}) {
var realLogger log.ContextLogger
switch t := logger.(type) {
case log.ContextLogger:
realLogger = t
case log.Logger:
realLogger = log.NewLoggerAdapter(t)
}
engine.logger = realLogger
engine.DB().Logger = realLogger
}
// SetLogLevel sets the logger level
func (engine *Engine) SetLogLevel(level log.LogLevel) {
engine.logger.SetLevel(level)
}
// SetDisableGlobalCache disable global cache or not
func (engine *Engine) SetDisableGlobalCache(disable bool) {
engine.cacherMgr.SetDisableGlobalCache(disable)
}
// DriverName return the current sql driver's name
func (engine *Engine) DriverName() string {
return engine.driverName
}
// DataSourceName return the current connection string
func (engine *Engine) DataSourceName() string {
return engine.dataSourceName
}
// SetMapper set the name mapping rules
func (engine *Engine) SetMapper(mapper names.Mapper) {
2013-12-18 03:31:32 +00:00
engine.SetTableMapper(mapper)
engine.SetColumnMapper(mapper)
2013-11-27 07:53:05 +00:00
}
// SetTableMapper set the table name mapping rule
func (engine *Engine) SetTableMapper(mapper names.Mapper) {
engine.tagParser.SetTableMapper(mapper)
2013-11-27 07:53:05 +00:00
}
// SetColumnMapper set the column name mapping rule
func (engine *Engine) SetColumnMapper(mapper names.Mapper) {
engine.tagParser.SetColumnMapper(mapper)
2013-11-27 07:53:05 +00:00
}
// Quote Use QuoteStr quote the string sql
func (engine *Engine) Quote(value string) string {
value = strings.TrimSpace(value)
if len(value) == 0 {
return value
}
2016-03-06 04:05:20 +00:00
buf := strings.Builder{}
2019-07-24 01:41:06 +00:00
engine.QuoteTo(&buf, value)
2019-07-24 01:41:06 +00:00
return buf.String()
2016-03-06 04:05:20 +00:00
}
// QuoteTo quotes string and writes into the buffer
func (engine *Engine) QuoteTo(buf *strings.Builder, value string) {
if buf == nil {
return
}
value = strings.TrimSpace(value)
if value == "" {
return
2014-04-18 14:14:15 +00:00
}
Fix join table name quote bug (#1534) Fix test Fix test Add new Quoter object to handle quote Fix join table name quote bug Move reserve words related files into dialects sub package (#1544) Move reserve words related files into dialects sub package Reviewed-on: https://gitea.com/xorm/xorm/pulls/1544 Fix mssql quote (#1535) Fix some quotes Fix mssql quote Merge core package back into the main repository and split into serval sub packages. (#1543) Fix test Improve fmt update go.mod Move core as a sub package Reviewed-on: https://gitea.com/xorm/xorm/pulls/1543 Fix int time deleted bug (#1539) Fix panic Fix test Fix test for mssql time Add sql type check on deleted cond Fix int time deleted bug Reviewed-on: https://gitea.com/xorm/xorm/pulls/1539 Add test for mysql8.0 (#1538) Fix pk order on test Add test for mysql8.0 Reviewed-on: https://gitea.com/xorm/xorm/pulls/1538 Add test for join limit (#1536) Add test for join limit Reviewed-on: https://gitea.com/xorm/xorm/pulls/1536 Improve drone (#1537) Fix drone Improve drone * use traditional positional parameters on inser... Reviewed-on: https://gitea.com/xorm/xorm/pulls/1537 Fix slice of struct not cache bug (#895) Fix failure caused by nil bean Judge both type of struct and pointer in case of out-of-range Fix issue #894 Add test for join subquery (#1528) Fix test Fix subquery with schema Add test for join subquery Add makefile (#1531) Fix drone Fix ci Add deps Improve drone Fix envs Add makefile Reviewed-on: https://gitea.com/xorm/xorm/pulls/1531 Add password for postgres drone image (#1530) Add password for postgres drone image Reviewed-on: https://gitea.com/xorm/xorm/pulls/1530 format time when sqlTypeName is core.Varchar (#1026) fix time test add test for time format sign codes according to contributing rules. format time when sqlTypeName is core.Varchar. Same with core.DateTime or core.TimeStamp Add test for second insert error (#1527) Add test for second insert error Reviewed-on: https://gitea.com/xorm/xorm/pulls/1527 Add tests for table name (#1517) add tests for table name Fix test (#1526) Fix test Reviewed-on: https://gitea.com/xorm/xorm/pulls/1526 Fix test (#1526) Fix test Reviewed-on: https://gitea.com/xorm/xorm/pulls/1526 Fix wrong warning log on autoincrement column when sync table (#1525) improve doc Fix wrong warning log on autoincrement column when sync table Reviewed-on: https://gitea.com/xorm/xorm/pulls/1525 Fixed Join strings on func Exist (#1520) fix test fixed Join strings on func Exist Co-authored-by: Tomofumi Kusana <tkusana@morisawa.co.jp> Reviewed-on: https://gitea.com/xorm/xorm/pulls/1520 For nullable columns, store nil values as NULL (#531) Merge branch 'master' into jcsalem/fix/nil_ptr_is_nullable fix bug when buffersize with iterate (#941) Merge branch 'master' into lunny/fix_buffer_iterate Exclude schema from index name (#1505) Merge branch 'master' into fix-schema-idx SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 fix vet fix drone lint remove go1.10 test on drone Exclude schema from the index name Co-authored-by: Guillermo Prandi <guillep2k@users.noreply.github.com> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Reviewed-on: https://gitea.com/xorm/xorm/pulls/1505 fix test fix bug fix bug when buffersize with iterate SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 fix vet fix drone lint remove go1.10 test on drone Fix update with Alias (#1455) Co-authored-by: Guillermo Prandi <guillep2k@noreply.gitea.io> Reviewed-on: https://gitea.com/xorm/xorm/pulls/941 fix update map with version (#1448) fix test fix update map with version SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 fix vet fix drone lint remove go1.10 test on drone Fix update with Alias (#1455) Reviewed-on: https://gitea.com/xorm/xorm/pulls/1448 Exclude schema from index name (#1505) Merge branch 'master' into fix-schema-idx SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 fix vet fix drone lint remove go1.10 test on drone Exclude schema from the index name Co-authored-by: Guillermo Prandi <guillep2k@users.noreply.github.com> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Reviewed-on: https://gitea.com/xorm/xorm/pulls/1505 SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 For nullable columns, store nil values as NULL fix vet fix drone lint remove go1.10 test on drone Fix update with Alias (#1455) Improve c... Reviewed-on: https://gitea.com/xorm/xorm/pulls/1534
2020-02-25 00:01:36 +00:00
engine.dialect.Quoter().QuoteTo(buf, value)
}
2016-07-11 03:29:34 +00:00
// SQLType A simple wrapper to dialect's core.SqlType method
func (engine *Engine) SQLType(c *schemas.Column) string {
return engine.dialect.SQLType(c)
2016-07-11 03:29:34 +00:00
}
// AutoIncrStr Database's autoincrement statement
func (engine *Engine) AutoIncrStr() string {
2013-12-18 03:31:32 +00:00
return engine.dialect.AutoIncrStr()
}
// SetConnMaxLifetime sets the maximum amount of time a connection may be reused.
func (engine *Engine) SetConnMaxLifetime(d time.Duration) {
engine.DB().SetConnMaxLifetime(d)
}
2014-04-17 02:13:16 +00:00
// SetMaxOpenConns is only available for go 1.2+
func (engine *Engine) SetMaxOpenConns(conns int) {
engine.DB().SetMaxOpenConns(conns)
2013-09-01 02:37:46 +00:00
}
// SetMaxIdleConns set the max idle connections on pool, default is 2
func (engine *Engine) SetMaxIdleConns(conns int) {
engine.DB().SetMaxIdleConns(conns)
}
// SetDefaultCacher set the default cacher. Xorm's default not enable cacher.
func (engine *Engine) SetDefaultCacher(cacher caches.Cacher) {
engine.cacherMgr.SetDefaultCacher(cacher)
}
// GetDefaultCacher returns the default cacher
func (engine *Engine) GetDefaultCacher() caches.Cacher {
return engine.cacherMgr.GetDefaultCacher()
}
// NoCache If you has set default cacher, and you want temporilly stop use cache,
2013-09-30 07:08:34 +00:00
// you can use NoCache()
2013-09-22 09:32:23 +00:00
func (engine *Engine) NoCache() *Session {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
session.isAutoClose = true
2013-12-18 03:31:32 +00:00
return session.NoCache()
}
// NoCascade If you do not want to auto cascade load object
2013-12-19 14:32:00 +00:00
func (engine *Engine) NoCascade() *Session {
session := engine.NewSession()
session.isAutoClose = true
2013-12-19 14:32:00 +00:00
return session.NoCascade()
}
// MapCacher Set a table use a special cacher
func (engine *Engine) MapCacher(bean interface{}, cacher caches.Cacher) error {
engine.SetCacher(dialects.FullTableName(engine.dialect, engine.GetTableMapper(), bean, true), cacher)
2017-04-02 10:02:47 +00:00
return nil
}
2014-04-15 06:37:10 +00:00
// NewDB provides an interface to operate database directly
func (engine *Engine) NewDB() (*core.DB, error) {
return core.Open(engine.driverName, engine.dataSourceName)
}
// DB return the wrapper of sql.DB
func (engine *Engine) DB() *core.DB {
return engine.db
2013-05-03 07:26:51 +00:00
}
// Dialect return database dialect
func (engine *Engine) Dialect() dialects.Dialect {
2014-04-17 02:13:16 +00:00
return engine.dialect
}
// NewSession New a session
2013-06-16 03:05:16 +00:00
func (engine *Engine) NewSession() *Session {
return newSession(engine)
2013-05-03 07:26:51 +00:00
}
2013-09-30 07:08:34 +00:00
// Close the engine
func (engine *Engine) Close() error {
return engine.DB().Close()
}
2014-04-15 06:37:10 +00:00
// Ping tests if database is alive
func (engine *Engine) Ping() error {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
defer session.Close()
return session.Ping()
}
2017-01-09 01:52:23 +00:00
// SQL method let's you manually write raw SQL and operate
// For example:
//
2016-07-11 03:29:34 +00:00
// engine.SQL("select * from user").Find(&users)
//
2013-12-09 02:29:23 +00:00
// This code will execute "select * from user" and set the records to users
func (engine *Engine) SQL(query interface{}, args ...interface{}) *Session {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
session.isAutoClose = true
return session.SQL(query, args...)
2013-07-17 17:26:14 +00:00
}
// 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 {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
session.isAutoClose = true
2013-12-18 03:31:32 +00:00
return session.NoAutoTime()
}
// NoAutoCondition disable auto generate Where condition from bean or not
2016-01-02 15:55:01 +00:00
func (engine *Engine) NoAutoCondition(no ...bool) *Session {
session := engine.NewSession()
session.isAutoClose = true
2016-01-02 15:55:01 +00:00
return session.NoAutoCondition(no...)
}
func (engine *Engine) loadTableInfo(table *schemas.Table) error {
colSeq, cols, err := engine.dialect.GetColumns(engine.db, engine.defaultContext, table.Name)
2019-09-30 08:32:57 +00:00
if err != nil {
return err
}
for _, name := range colSeq {
table.AddColumn(cols[name])
}
indexes, err := engine.dialect.GetIndexes(engine.db, engine.defaultContext, table.Name)
2019-09-30 08:32:57 +00:00
if err != nil {
return err
}
table.Indexes = indexes
var seq int
2019-09-30 08:32:57 +00:00
for _, index := range indexes {
for _, name := range index.Cols {
parts := strings.Split(strings.TrimSpace(name), " ")
if len(parts) > 1 {
if parts[1] == "DESC" {
seq = 1
} else if parts[1] == "ASC" {
seq = 0
}
}
var colName = strings.Trim(parts[0], `"`)
if col := table.GetColumn(colName); col != nil {
2019-09-30 08:32:57 +00:00
col.Indexes[index.Name] = index.Type
} else {
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-09-30 08:32:57 +00:00
}
}
}
return nil
}
// DBMetas Retrieve all tables, columns, indexes' informations from database.
func (engine *Engine) DBMetas() ([]*schemas.Table, error) {
tables, err := engine.dialect.GetTables(engine.db, engine.defaultContext)
2013-12-18 03:31:32 +00:00
if err != nil {
return nil, err
}
for _, table := range tables {
2019-09-30 08:32:57 +00:00
if err = engine.loadTableInfo(table); err != nil {
2013-12-18 03:31:32 +00:00
return nil, err
}
}
return tables, nil
2013-10-12 15:16:51 +00:00
}
// DumpAllToFile dump database all table structs and data to a file
func (engine *Engine) DumpAllToFile(fp string, tp ...schemas.DBType) error {
f, err := os.Create(fp)
if err != nil {
return err
}
defer f.Close()
return engine.DumpAll(f, tp...)
}
// DumpAll dump database all table structs and data to w
func (engine *Engine) DumpAll(w io.Writer, tp ...schemas.DBType) error {
tables, err := engine.DBMetas()
if err != nil {
return err
}
return engine.DumpTables(tables, w, tp...)
}
// DumpTablesToFile dump specified tables to SQL file.
func (engine *Engine) DumpTablesToFile(tables []*schemas.Table, fp string, tp ...schemas.DBType) error {
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
func (engine *Engine) DumpTables(tables []*schemas.Table, w io.Writer, tp ...schemas.DBType) error {
return engine.dumpTables(tables, w, tp...)
}
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
}
// dumpTables dump database all table structs and data to w with specify db type
func (engine *Engine) dumpTables(tables []*schemas.Table, w io.Writer, tp ...schemas.DBType) error {
var dstDialect dialects.Dialect
if len(tp) == 0 {
dstDialect = engine.dialect
} else {
dstDialect = dialects.QueryDialect(tp[0])
if dstDialect == nil {
2016-12-11 04:45:37 +00:00
return errors.New("Unsupported database type")
}
uri := engine.dialect.URI()
destURI := dialects.URI{
DBType: tp[0],
DBName: uri.DBName,
}
dstDialect.Init(&destURI)
}
_, 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))
if err != nil {
return err
}
for i, table := range tables {
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)
}
if i > 0 {
_, err = io.WriteString(w, "\n")
if err != nil {
return err
}
}
sqls, _ := dstDialect.CreateTableSQL(table, tableName)
for _, s := range sqls {
_, err = io.WriteString(w, s+";\n")
if err != nil {
return err
}
}
if len(table.PKColumns()) > 0 && dstDialect.URI().DBType == schemas.MSSQL {
fmt.Fprintf(w, "SET IDENTITY_INSERT [%s] ON;\n", table.Name)
}
for _, index := range table.Indexes {
_, err = io.WriteString(w, dstDialect.CreateIndexSQL(table.Name, index)+";\n")
if err != nil {
return err
}
}
2017-01-18 15:08:43 +00:00
cols := table.ColumnsSeq()
Fix join table name quote bug (#1534) Fix test Fix test Add new Quoter object to handle quote Fix join table name quote bug Move reserve words related files into dialects sub package (#1544) Move reserve words related files into dialects sub package Reviewed-on: https://gitea.com/xorm/xorm/pulls/1544 Fix mssql quote (#1535) Fix some quotes Fix mssql quote Merge core package back into the main repository and split into serval sub packages. (#1543) Fix test Improve fmt update go.mod Move core as a sub package Reviewed-on: https://gitea.com/xorm/xorm/pulls/1543 Fix int time deleted bug (#1539) Fix panic Fix test Fix test for mssql time Add sql type check on deleted cond Fix int time deleted bug Reviewed-on: https://gitea.com/xorm/xorm/pulls/1539 Add test for mysql8.0 (#1538) Fix pk order on test Add test for mysql8.0 Reviewed-on: https://gitea.com/xorm/xorm/pulls/1538 Add test for join limit (#1536) Add test for join limit Reviewed-on: https://gitea.com/xorm/xorm/pulls/1536 Improve drone (#1537) Fix drone Improve drone * use traditional positional parameters on inser... Reviewed-on: https://gitea.com/xorm/xorm/pulls/1537 Fix slice of struct not cache bug (#895) Fix failure caused by nil bean Judge both type of struct and pointer in case of out-of-range Fix issue #894 Add test for join subquery (#1528) Fix test Fix subquery with schema Add test for join subquery Add makefile (#1531) Fix drone Fix ci Add deps Improve drone Fix envs Add makefile Reviewed-on: https://gitea.com/xorm/xorm/pulls/1531 Add password for postgres drone image (#1530) Add password for postgres drone image Reviewed-on: https://gitea.com/xorm/xorm/pulls/1530 format time when sqlTypeName is core.Varchar (#1026) fix time test add test for time format sign codes according to contributing rules. format time when sqlTypeName is core.Varchar. Same with core.DateTime or core.TimeStamp Add test for second insert error (#1527) Add test for second insert error Reviewed-on: https://gitea.com/xorm/xorm/pulls/1527 Add tests for table name (#1517) add tests for table name Fix test (#1526) Fix test Reviewed-on: https://gitea.com/xorm/xorm/pulls/1526 Fix test (#1526) Fix test Reviewed-on: https://gitea.com/xorm/xorm/pulls/1526 Fix wrong warning log on autoincrement column when sync table (#1525) improve doc Fix wrong warning log on autoincrement column when sync table Reviewed-on: https://gitea.com/xorm/xorm/pulls/1525 Fixed Join strings on func Exist (#1520) fix test fixed Join strings on func Exist Co-authored-by: Tomofumi Kusana <tkusana@morisawa.co.jp> Reviewed-on: https://gitea.com/xorm/xorm/pulls/1520 For nullable columns, store nil values as NULL (#531) Merge branch 'master' into jcsalem/fix/nil_ptr_is_nullable fix bug when buffersize with iterate (#941) Merge branch 'master' into lunny/fix_buffer_iterate Exclude schema from index name (#1505) Merge branch 'master' into fix-schema-idx SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 fix vet fix drone lint remove go1.10 test on drone Exclude schema from the index name Co-authored-by: Guillermo Prandi <guillep2k@users.noreply.github.com> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Reviewed-on: https://gitea.com/xorm/xorm/pulls/1505 fix test fix bug fix bug when buffersize with iterate SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 fix vet fix drone lint remove go1.10 test on drone Fix update with Alias (#1455) Co-authored-by: Guillermo Prandi <guillep2k@noreply.gitea.io> Reviewed-on: https://gitea.com/xorm/xorm/pulls/941 fix update map with version (#1448) fix test fix update map with version SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 fix vet fix drone lint remove go1.10 test on drone Fix update with Alias (#1455) Reviewed-on: https://gitea.com/xorm/xorm/pulls/1448 Exclude schema from index name (#1505) Merge branch 'master' into fix-schema-idx SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 fix vet fix drone lint remove go1.10 test on drone Exclude schema from the index name Co-authored-by: Guillermo Prandi <guillep2k@users.noreply.github.com> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Reviewed-on: https://gitea.com/xorm/xorm/pulls/1505 SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 For nullable columns, store nil values as NULL fix vet fix drone lint remove go1.10 test on drone Fix update with Alias (#1455) Improve c... Reviewed-on: https://gitea.com/xorm/xorm/pulls/1534
2020-02-25 00:01:36 +00:00
colNames := engine.dialect.Quoter().Join(cols, ", ")
destColNames := dstDialect.Quoter().Join(cols, ", ")
2017-01-18 15:08:43 +00:00
rows, err := engine.DB().QueryContext(engine.defaultContext, "SELECT "+colNames+" FROM "+engine.Quote(originalTableName))
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
}
_, err = io.WriteString(w, "INSERT INTO "+dstDialect.Quoter().Quote(tableName)+" ("+destColNames+") VALUES (")
if err != nil {
return err
}
var temp string
for i, d := range dest {
col := table.GetColumn(cols[i])
2017-01-18 15:08:43 +00:00
if col == nil {
return errors.New("unknow column error")
}
temp += "," + formatColumnValue(dstDialect, d, col)
}
_, err = io.WriteString(w, temp[1:]+");\n")
if err != nil {
return err
}
}
2017-02-10 01:55:37 +00:00
// FIXME: Hack for postgres
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 01:55:37 +00:00
if err != nil {
return err
}
}
}
return nil
}
2016-07-11 03:29:34 +00:00
// Cascade use cascade or not
2013-07-17 17:26:14 +00:00
func (engine *Engine) Cascade(trueOrFalse ...bool) *Session {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
session.isAutoClose = true
2013-12-18 03:31:32 +00:00
return session.Cascade(trueOrFalse...)
}
// Where method provide a condition query
func (engine *Engine) Where(query interface{}, args ...interface{}) *Session {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
session.isAutoClose = true
return session.Where(query, args...)
2013-05-06 08:01:17 +00:00
}
2017-01-21 14:51:25 +00:00
// ID method provoide a condition as (id) = ?
2016-07-11 03:29:34 +00:00
func (engine *Engine) ID(id interface{}) *Session {
session := engine.NewSession()
session.isAutoClose = true
2016-07-11 03:29:34 +00:00
return session.ID(id)
}
// Before apply before Processor, affected bean is passed to closure arg
func (engine *Engine) Before(closures func(interface{})) *Session {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
session.isAutoClose = true
2013-12-18 03:31:32 +00:00
return session.Before(closures)
2013-12-04 10:39:22 +00:00
}
2016-07-11 03:29:34 +00:00
// After apply after insert Processor, affected bean is passed to closure arg
func (engine *Engine) After(closures func(interface{})) *Session {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
session.isAutoClose = true
2013-12-18 03:31:32 +00:00
return session.After(closures)
2013-12-04 10:39:22 +00:00
}
2016-07-11 03:29:34 +00:00
// Charset set charset when create table, only support mysql now
func (engine *Engine) Charset(charset string) *Session {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
session.isAutoClose = true
2013-12-18 03:31:32 +00:00
return session.Charset(charset)
}
2016-07-11 03:29:34 +00:00
// StoreEngine set store engine when create table, only support mysql now
func (engine *Engine) StoreEngine(storeEngine string) *Session {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
session.isAutoClose = true
2013-12-18 03:31:32 +00:00
return session.StoreEngine(storeEngine)
}
2016-07-11 03:29:34 +00:00
// 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 {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
session.isAutoClose = true
2013-12-18 03:31:32 +00:00
return session.Distinct(columns...)
}
2016-07-11 03:29:34 +00:00
// Select customerize your select columns or contents
func (engine *Engine) Select(str string) *Session {
session := engine.NewSession()
session.isAutoClose = true
return session.Select(str)
}
2017-01-09 01:52:23 +00:00
// Cols only use the parameters as select or update columns
func (engine *Engine) Cols(columns ...string) *Session {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
session.isAutoClose = true
2013-12-18 03:31:32 +00:00
return session.Cols(columns...)
}
2016-07-11 03:29:34 +00:00
// AllCols indicates that all columns should be use
func (engine *Engine) AllCols() *Session {
session := engine.NewSession()
session.isAutoClose = true
return session.AllCols()
}
2016-07-11 03:29:34 +00:00
// MustCols specify some columns must use even if they are empty
func (engine *Engine) MustCols(columns ...string) *Session {
session := engine.NewSession()
session.isAutoClose = true
return session.MustCols(columns...)
}
2016-07-11 03:29:34 +00:00
// 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-09 01:52:23 +00:00
// If no parameters, it will use all the bool field of struct, or
// it will use parameters's columns
func (engine *Engine) UseBool(columns ...string) *Session {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
session.isAutoClose = true
2013-12-18 03:31:32 +00:00
return session.UseBool(columns...)
}
2017-01-09 01:52:23 +00:00
// Omit only not use the parameters as select or update columns
func (engine *Engine) Omit(columns ...string) *Session {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
session.isAutoClose = true
2013-12-18 03:31:32 +00:00
return session.Omit(columns...)
}
2016-07-11 03:29:34 +00:00
// Nullable set null when column is zero-value and nullable for update
func (engine *Engine) Nullable(columns ...string) *Session {
session := engine.NewSession()
session.isAutoClose = true
return session.Nullable(columns...)
}
2016-07-11 03:29:34 +00:00
// In will generate "column IN (?, ?)"
2013-06-16 03:05:16 +00:00
func (engine *Engine) In(column string, args ...interface{}) *Session {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
session.isAutoClose = true
2013-12-18 03:31:32 +00:00
return session.In(column, args...)
2013-05-11 08:27:17 +00: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-07-11 03:29:34 +00:00
// Incr provides a update string like "column = column + ?"
2014-04-15 04:14:18 +00:00
func (engine *Engine) Incr(column string, arg ...interface{}) *Session {
2014-04-15 01:54:49 +00:00
session := engine.NewSession()
session.isAutoClose = true
2014-04-15 04:14:18 +00:00
return session.Incr(column, arg...)
2013-05-11 08:27:17 +00:00
}
2016-07-11 03:29:34 +00:00
// Decr provides a update string like "column = column - ?"
2014-07-15 15:25:24 +00:00
func (engine *Engine) Decr(column string, arg ...interface{}) *Session {
session := engine.NewSession()
session.isAutoClose = true
2014-07-15 15:25:24 +00:00
return session.Decr(column, arg...)
}
2016-07-11 03:29:34 +00:00
// SetExpr provides a update string like "column = {expression}"
func (engine *Engine) SetExpr(column string, expression interface{}) *Session {
2015-01-28 05:23:01 +00:00
session := engine.NewSession()
session.isAutoClose = true
2015-01-28 06:10:45 +00:00
return session.SetExpr(column, expression)
2015-01-28 05:23:01 +00:00
}
2016-07-11 03:29:34 +00:00
// Table temporarily change the Get, Find, Update's table
func (engine *Engine) Table(tableNameOrBean interface{}) *Session {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
session.isAutoClose = true
2013-12-18 03:31:32 +00:00
return session.Table(tableNameOrBean)
2013-05-19 05:25:52 +00:00
}
2016-07-11 03:29:34 +00:00
// Alias set the table alias
2014-11-18 16:41:03 +00:00
func (engine *Engine) Alias(alias string) *Session {
session := engine.NewSession()
session.isAutoClose = true
2014-11-18 16:41:03 +00:00
return session.Alias(alias)
}
2016-07-11 03:29:34 +00:00
// Limit will generate "LIMIT start, limit"
2013-06-16 03:05:16 +00:00
func (engine *Engine) Limit(limit int, start ...int) *Session {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
session.isAutoClose = true
2013-12-18 03:31:32 +00:00
return session.Limit(limit, start...)
2013-05-06 08:01:17 +00:00
}
2016-07-11 03:29:34 +00:00
// Desc will generate "ORDER BY column1 DESC, column2 DESC"
2013-09-02 02:06:32 +00:00
func (engine *Engine) Desc(colNames ...string) *Session {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
session.isAutoClose = true
2013-12-18 03:31:32 +00:00
return session.Desc(colNames...)
2013-09-02 01:54:37 +00:00
}
2016-07-11 03:29:34 +00:00
// Asc will generate "ORDER BY column1,column2 Asc"
// This method can chainable use.
//
2013-12-09 02:29:23 +00:00
// engine.Desc("name").Asc("age").Find(&users)
// // SELECT * FROM user ORDER BY name DESC, age ASC
//
2013-09-02 02:06:32 +00:00
func (engine *Engine) Asc(colNames ...string) *Session {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
session.isAutoClose = true
2013-12-18 03:31:32 +00:00
return session.Asc(colNames...)
2013-09-02 01:54:37 +00:00
}
2016-07-11 03:29:34 +00:00
// OrderBy will generate "ORDER BY order"
2013-06-16 03:05:16 +00:00
func (engine *Engine) OrderBy(order string) *Session {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
session.isAutoClose = true
2013-12-18 03:31:32 +00:00
return session.OrderBy(order)
2013-05-06 08:01:17 +00:00
}
2017-11-29 02:03:54 +00:00
// Prepare enables prepare statement
func (engine *Engine) Prepare() *Session {
session := engine.NewSession()
session.isAutoClose = true
return session.Prepare()
}
2016-07-11 03:29:34 +00: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 {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
session.isAutoClose = true
2016-07-11 03:29:34 +00:00
return session.Join(joinOperator, tablename, condition, args...)
2013-05-06 08:01:17 +00:00
}
2016-07-11 03:29:34 +00:00
// GroupBy generate group by statement
2013-06-16 03:05:16 +00:00
func (engine *Engine) GroupBy(keys string) *Session {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
session.isAutoClose = true
2013-12-18 03:31:32 +00:00
return session.GroupBy(keys)
2013-05-06 08:01:17 +00:00
}
2016-07-11 03:29:34 +00:00
// Having generate having statement
2013-06-16 03:05:16 +00:00
func (engine *Engine) Having(conditions string) *Session {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
session.isAutoClose = true
2013-12-18 03:31:32 +00:00
return session.Having(conditions)
2013-05-06 08:01:17 +00:00
}
2016-07-11 03:29:34 +00:00
// Table table struct
type Table struct {
*schemas.Table
Name string
}
2017-04-02 10:02:47 +00:00
// IsValid if table is valid
func (t *Table) IsValid() bool {
return t.Table != nil && len(t.Name) > 0
}
2016-07-11 03:29:34 +00:00
// TableInfo get table info according to bean's content
func (engine *Engine) TableInfo(bean interface{}) (*schemas.Table, error) {
v := utils.ReflectValue(bean)
return engine.tagParser.ParseWithCache(v)
2013-05-13 11:56:38 +00:00
}
2016-07-11 03:29:34 +00:00
// IsTableEmpty if a table has any reocrd
2013-09-30 07:08:34 +00:00
func (engine *Engine) IsTableEmpty(bean interface{}) (bool, error) {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
defer session.Close()
2015-02-12 03:46:03 +00:00
return session.IsTableEmpty(bean)
}
2016-07-11 03:29:34 +00:00
// IsTableExist if a table is exist
2015-02-12 03:46:03 +00:00
func (engine *Engine) IsTableExist(beanOrTableName interface{}) (bool, error) {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
defer session.Close()
2015-02-12 03:46:03 +00:00
return session.IsTableExist(beanOrTableName)
}
// 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...)
}
2016-07-11 03:29:34 +00:00
// CreateIndexes create indexes
2013-10-12 15:16:51 +00:00
func (engine *Engine) CreateIndexes(bean interface{}) error {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
defer session.Close()
return session.CreateIndexes(bean)
2013-10-12 15:16:51 +00:00
}
2016-07-11 03:29:34 +00:00
// CreateUniques create uniques
2013-10-12 15:16:51 +00:00
func (engine *Engine) CreateUniques(bean interface{}) error {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
defer session.Close()
return session.CreateUniques(bean)
2013-10-12 15:16:51 +00:00
}
2016-07-11 03:29:34 +00:00
// ClearCacheBean if enabled cache, clear the cache bean
func (engine *Engine) ClearCacheBean(bean interface{}, id string) error {
tableName := dialects.FullTableName(engine.dialect, engine.GetTableMapper(), bean)
cacher := engine.GetCacher(tableName)
2014-01-07 09:33:27 +00:00
if cacher != nil {
cacher.ClearIds(tableName)
cacher.DelBean(tableName, id)
2013-12-18 03:31:32 +00:00
}
return nil
}
2016-07-11 03:29:34 +00:00
// ClearCache if enabled cache, clear some tables' cache
func (engine *Engine) ClearCache(beans ...interface{}) error {
2013-12-18 03:31:32 +00:00
for _, bean := range beans {
tableName := dialects.FullTableName(engine.dialect, engine.GetTableMapper(), bean)
cacher := engine.GetCacher(tableName)
2014-01-07 09:33:27 +00:00
if cacher != nil {
cacher.ClearIds(tableName)
cacher.ClearBeans(tableName)
2013-12-18 03:31:32 +00:00
}
}
return nil
}
// UnMapType remove table from tables cache
func (engine *Engine) UnMapType(t reflect.Type) {
engine.tagParser.ClearCacheTable(t)
}
// Sync the new struct changes to database, this method will automatically add
2013-09-30 06:45:34 +00:00
// 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-20 09:05:42 +00:00
session := engine.NewSession()
defer session.Close()
2013-12-18 03:31:32 +00:00
for _, bean := range beans {
v := utils.ReflectValue(bean)
tableNameNoSchema := dialects.FullTableName(engine.dialect, engine.GetTableMapper(), bean)
table, err := engine.tagParser.ParseWithCache(v)
2017-04-02 10:02:47 +00:00
if err != nil {
return err
}
2013-12-18 03:31:32 +00:00
isExist, err := session.Table(bean).isTableExist(tableNameNoSchema)
2013-12-18 03:31:32 +00:00
if err != nil {
return err
}
if !isExist {
2017-08-20 09:05:42 +00:00
err = session.createTable(bean)
2013-12-18 03:31:32 +00:00
if err != nil {
return err
}
}
/*isEmpty, err := engine.IsEmptyTable(bean)
if err != nil {
return err
}*/
var isEmpty bool
2013-12-18 03:31:32 +00:00
if isEmpty {
2017-08-20 09:05:42 +00:00
err = session.dropTable(bean)
2013-12-18 03:31:32 +00:00
if err != nil {
return err
}
2017-08-20 09:05:42 +00:00
err = session.createTable(bean)
2013-12-18 03:31:32 +00:00
if err != nil {
return err
}
} else {
2014-01-07 09:33:27 +00:00
for _, col := range table.Columns() {
isExist, err := engine.dialect.IsColumnExist(engine.db, session.ctx, tableNameNoSchema, col.Name)
2013-12-18 03:31:32 +00:00
if err != nil {
return err
}
if !isExist {
if err := session.statement.SetRefBean(bean); err != nil {
2017-04-10 11:45:00 +00:00
return err
}
2013-12-18 03:31:32 +00:00
err = session.addColumn(col.Name)
if err != nil {
return err
}
}
}
for name, index := range table.Indexes {
if err := session.statement.SetRefBean(bean); err != nil {
2017-04-10 11:45:00 +00:00
return err
}
if index.Type == schemas.UniqueType {
isExist, err := session.isIndexExist2(tableNameNoSchema, index.Cols, true)
2013-12-18 03:31:32 +00:00
if err != nil {
return err
}
if !isExist {
if err := session.statement.SetRefBean(bean); err != nil {
2017-04-10 11:45:00 +00:00
return err
}
err = session.addUnique(tableNameNoSchema, name)
2013-12-18 03:31:32 +00:00
if err != nil {
return err
}
}
} else if index.Type == schemas.IndexType {
isExist, err := session.isIndexExist2(tableNameNoSchema, index.Cols, false)
2013-12-18 03:31:32 +00:00
if err != nil {
return err
}
if !isExist {
if err := session.statement.SetRefBean(bean); err != nil {
2017-04-10 11:45:00 +00:00
return err
}
err = session.addIndex(tableNameNoSchema, name)
2013-12-18 03:31:32 +00:00
if err != nil {
return err
}
}
} else {
return errors.New("unknow index type")
}
}
}
}
return nil
}
2016-07-11 03:29:34 +00:00
// Sync2 synchronize structs to database tables
func (engine *Engine) Sync2(beans ...interface{}) error {
s := engine.NewSession()
defer s.Close()
return s.Sync2(beans...)
}
2013-09-30 06:45:34 +00:00
// CreateTables create tabls according bean
2013-09-30 06:48:17 +00:00
func (engine *Engine) CreateTables(beans ...interface{}) error {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
defer session.Close()
err := session.Begin()
2013-12-18 03:31:32 +00:00
if err != nil {
return err
}
for _, bean := range beans {
2017-08-20 09:05:42 +00:00
err = session.createTable(bean)
2013-12-18 03:31:32 +00:00
if err != nil {
session.Rollback()
return err
}
}
return session.Commit()
2013-05-03 07:26:51 +00:00
}
2016-07-11 03:29:34 +00:00
// DropTables drop specify tables
2013-09-30 06:48:17 +00:00
func (engine *Engine) DropTables(beans ...interface{}) error {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
defer session.Close()
2015-03-12 10:03:52 +00:00
err := session.Begin()
2013-12-18 03:31:32 +00:00
if err != nil {
return err
}
for _, bean := range beans {
2017-08-20 09:05:42 +00:00
err = session.dropTable(bean)
2013-12-18 03:31:32 +00:00
if err != nil {
session.Rollback()
return err
}
}
return session.Commit()
2013-07-27 13:47:22 +00:00
}
2017-05-27 14:14:13 +00:00
// DropIndexes drop indexes of a table
func (engine *Engine) DropIndexes(bean interface{}) error {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
defer session.Close()
2017-05-27 14:14:13 +00:00
return session.DropIndexes(bean)
2013-05-03 07:26:51 +00:00
}
2013-11-22 06:11:07 +00:00
// Exec raw sql
2019-06-06 02:55:52 +00:00
func (engine *Engine) Exec(sqlOrArgs ...interface{}) (sql.Result, error) {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
defer session.Close()
2019-06-06 02:55:52 +00:00
return session.Exec(sqlOrArgs...)
2013-05-08 13:42:22 +00:00
}
2016-07-11 03:29:34 +00:00
// Query a raw sql and return records as []map[string][]byte
2019-06-06 02:55:52 +00:00
func (engine *Engine) Query(sqlOrArgs ...interface{}) (resultsSlice []map[string][]byte, err error) {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
defer session.Close()
2019-06-06 02:55:52 +00:00
return session.Query(sqlOrArgs...)
2013-05-08 13:42:22 +00:00
}
2017-04-01 02:35:27 +00:00
// QueryString runs a raw sql and return records as []map[string]string
2019-06-06 02:55:52 +00:00
func (engine *Engine) QueryString(sqlOrArgs ...interface{}) ([]map[string]string, error) {
2017-04-01 02:35:27 +00:00
session := engine.NewSession()
defer session.Close()
2019-06-06 02:55:52 +00:00
return session.QueryString(sqlOrArgs...)
2017-04-01 02:35:27 +00:00
}
// QueryInterface runs a raw sql and return records as []map[string]interface{}
2019-06-06 02:55:52 +00:00
func (engine *Engine) QueryInterface(sqlOrArgs ...interface{}) ([]map[string]interface{}, error) {
session := engine.NewSession()
defer session.Close()
2019-06-06 02:55:52 +00:00
return session.QueryInterface(sqlOrArgs...)
}
2013-11-22 06:11:07 +00:00
// Insert one or more records
2013-05-03 07:26:51 +00:00
func (engine *Engine) Insert(beans ...interface{}) (int64, error) {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
defer session.Close()
return session.Insert(beans...)
2013-05-03 07:26:51 +00:00
}
2016-07-11 03:29:34 +00:00
// InsertOne insert only one record
func (engine *Engine) InsertOne(bean interface{}) (int64, error) {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
defer session.Close()
return session.InsertOne(bean)
}
2013-11-22 06:11:07 +00:00
// Update records, bean's non-empty fields are updated contents,
// condiBean' non-empty filds are conditions
// CAUTION:
2013-12-09 02:29:23 +00:00
// 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
2013-05-08 13:42:22 +00:00
func (engine *Engine) Update(bean interface{}, condiBeans ...interface{}) (int64, error) {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
defer session.Close()
return session.Update(bean, condiBeans...)
2013-05-03 07:26:51 +00:00
}
2013-11-22 06:11:07 +00:00
// Delete records, bean's non-empty fields are conditions
2013-05-03 07:26:51 +00:00
func (engine *Engine) Delete(bean interface{}) (int64, error) {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
defer session.Close()
return session.Delete(bean)
2013-05-03 07:26:51 +00:00
}
2013-11-22 06:11:07 +00:00
// Get retrieve one record from table, bean's non-empty fields
// are conditions
2013-06-16 03:05:16 +00:00
func (engine *Engine) Get(bean interface{}) (bool, error) {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
defer session.Close()
return session.Get(bean)
2013-05-03 07:26:51 +00:00
}
2017-07-14 01:20:13 +00: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...)
}
2013-11-22 06:11:07 +00:00
// Find retrieve records from table, condiBeans's non-empty fields
// are conditions. beans could be []Struct, []*Struct, map[int64]Struct
// map[int64]*Struct
2013-05-08 13:42:22 +00:00
func (engine *Engine) Find(beans interface{}, condiBeans ...interface{}) error {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
defer session.Close()
return session.Find(beans, condiBeans...)
2018-02-07 13:06:13 +00: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...)
2013-05-03 07:26:51 +00:00
}
2013-11-22 06:11:07 +00: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 {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
defer session.Close()
return session.Iterate(bean, fun)
}
2016-07-11 03:29:34 +00:00
// 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)
}
2016-07-07 14:34:43 +00:00
// Count counts the records. bean's non-empty fields are conditions.
2017-08-20 09:05:42 +00:00
func (engine *Engine) Count(bean ...interface{}) (int64, error) {
2013-12-18 03:31:32 +00:00
session := engine.NewSession()
defer session.Close()
2017-08-20 09:05:42 +00:00
return session.Count(bean...)
2013-05-03 07:26:51 +00:00
}
2013-12-04 10:39:22 +00:00
2016-07-07 14:34:43 +00: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-06-12 08:33:11 +00: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-07-07 14:34:43 +00: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...)
}
2016-07-11 03:29:34 +00:00
// ImportFile SQL DDL file
2014-05-24 08:05:48 +00:00
func (engine *Engine) ImportFile(ddlPath string) ([]sql.Result, error) {
session := engine.NewSession()
defer session.Close()
return session.ImportFile(ddlPath)
2014-05-24 08:05:48 +00:00
}
2013-12-18 03:31:32 +00:00
2016-07-11 03:29:34 +00:00
// Import SQL DDL from io.Reader
2014-05-24 08:05:48 +00:00
func (engine *Engine) Import(r io.Reader) ([]sql.Result, error) {
session := engine.NewSession()
defer session.Close()
return session.Import(r)
2013-12-04 10:39:22 +00:00
}
// nowTime return current time
func (engine *Engine) nowTime(col *schemas.Column) (interface{}, time.Time) {
2015-02-23 04:24:26 +00:00
t := time.Now()
var tz = engine.DatabaseTZ
if !col.DisableTimeZone && col.TimeZone != nil {
tz = col.TimeZone
}
return dialects.FormatTime(engine.dialect, col.SQLType.Name, t.In(tz)), t.In(engine.TZLocation)
2016-01-28 08:54:15 +00:00
}
// GetColumnMapper returns the column name mapper
func (engine *Engine) GetColumnMapper() names.Mapper {
return engine.tagParser.GetColumnMapper()
2014-11-03 13:03:12 +00:00
}
2017-06-15 12:09:46 +00:00
// GetTableMapper returns the table name mapper
func (engine *Engine) GetTableMapper() names.Mapper {
return engine.tagParser.GetTableMapper()
2017-06-15 12:09:46 +00:00
}
2017-09-19 12:59:41 +00: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
}
// SetSchema sets the schema of database
func (engine *Engine) SetSchema(schema string) {
engine.dialect.URI().SetSchema(schema)
}
func (engine *Engine) AddHook(hook contexts.Hook) {
engine.db.AddHook(hook)
}
// Unscoped always disable struct tag "deleted"
func (engine *Engine) Unscoped() *Session {
2017-09-19 12:59:41 +00:00
session := engine.NewSession()
session.isAutoClose = true
return session.Unscoped()
2017-09-19 12:59:41 +00:00
}
func (engine *Engine) tbNameWithSchema(v string) string {
return dialects.TableNameWithSchema(engine.dialect, v)
}
// ContextHook creates a session with the context
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 {
return result, err
}
if err := session.Commit(); err != nil {
return result, err
}
return result, nil
}