require lint before tests
use golangci/golangci-lint-action instead of reviewdog/action-golangci-lint as the second was not reporting any failures even if there was some. Report code coverage with codecov/codecov-action I have set some flags per dialect and go version Several linters has been fixed, some disabled so the build can pass
This commit is contained in:
		
							parent
							
								
									2c3fc2db28
								
							
						
					
					
						commit
						21423b914f
					
				
							
								
								
									
										11
									
								
								.github/workflows/reviewdog.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								.github/workflows/reviewdog.yml
									
									
									
									
										vendored
									
									
								
							@ -1,11 +0,0 @@
 | 
				
			|||||||
name: reviewdog
 | 
					 | 
				
			||||||
on: [pull_request]
 | 
					 | 
				
			||||||
jobs:
 | 
					 | 
				
			||||||
  golangci-lint:
 | 
					 | 
				
			||||||
    name: runner / golangci-lint
 | 
					 | 
				
			||||||
    runs-on: ubuntu-latest
 | 
					 | 
				
			||||||
    steps:
 | 
					 | 
				
			||||||
      - name: Check out code into the Go module directory
 | 
					 | 
				
			||||||
        uses: actions/checkout@v2
 | 
					 | 
				
			||||||
      - name: golangci-lint
 | 
					 | 
				
			||||||
        uses: reviewdog/action-golangci-lint@v2
 | 
					 | 
				
			||||||
							
								
								
									
										64
									
								
								.github/workflows/tests.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										64
									
								
								.github/workflows/tests.yml
									
									
									
									
										vendored
									
									
								
							@ -9,8 +9,28 @@ on:
 | 
				
			|||||||
      - 'gh-pages'
 | 
					      - 'gh-pages'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
jobs:
 | 
					jobs:
 | 
				
			||||||
 | 
					  lint:
 | 
				
			||||||
 | 
					    name: runner / golangci-lint
 | 
				
			||||||
 | 
					    runs-on: ubuntu-latest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    steps:
 | 
				
			||||||
 | 
					      - name: Setup go
 | 
				
			||||||
 | 
					        uses: actions/setup-go@v2
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          go-version: '1.17'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - name: Checkout repository
 | 
				
			||||||
 | 
					        uses: actions/checkout@v2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - name: Setup golangci-lint
 | 
				
			||||||
 | 
					        uses: golangci/golangci-lint-action@v2
 | 
				
			||||||
 | 
					        with:
 | 
				
			||||||
 | 
					          version: latest
 | 
				
			||||||
 | 
					          args: --verbose
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Label of the container job
 | 
					  # Label of the container job
 | 
				
			||||||
  sqlite:
 | 
					  sqlite:
 | 
				
			||||||
 | 
					    needs: lint
 | 
				
			||||||
    strategy:
 | 
					    strategy:
 | 
				
			||||||
      matrix:
 | 
					      matrix:
 | 
				
			||||||
        go: ['1.17', '1.16']
 | 
					        go: ['1.17', '1.16']
 | 
				
			||||||
@ -18,7 +38,7 @@ jobs:
 | 
				
			|||||||
    runs-on: ${{ matrix.platform }}
 | 
					    runs-on: ${{ matrix.platform }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
    - name: Set up Go 1.x
 | 
					    - name: Set up Go ${{ matrix.go }}
 | 
				
			||||||
      uses: actions/setup-go@v2
 | 
					      uses: actions/setup-go@v2
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
        go-version: ${{ matrix.go }}
 | 
					        go-version: ${{ matrix.go }}
 | 
				
			||||||
@ -35,7 +55,16 @@ jobs:
 | 
				
			|||||||
    - name: Tests
 | 
					    - name: Tests
 | 
				
			||||||
      run: GORM_DIALECT=sqlite ./tests/tests_all.sh
 | 
					      run: GORM_DIALECT=sqlite ./tests/tests_all.sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    - name: Upload Code Coverage
 | 
				
			||||||
 | 
					      uses: codecov/codecov-action@v2
 | 
				
			||||||
 | 
					      with:
 | 
				
			||||||
 | 
					        name: sqlite
 | 
				
			||||||
 | 
					        flags: sqlite,go-${{ matrix.go }}
 | 
				
			||||||
 | 
					        fail_ci_if_error: true
 | 
				
			||||||
 | 
					        token: ${{ secrets.CODECOV_TOKEN }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  mysql:
 | 
					  mysql:
 | 
				
			||||||
 | 
					    needs: lint
 | 
				
			||||||
    strategy:
 | 
					    strategy:
 | 
				
			||||||
      matrix:
 | 
					      matrix:
 | 
				
			||||||
        dbversion: ['mysql:latest', 'mysql:5.7', 'mariadb:latest']
 | 
					        dbversion: ['mysql:latest', 'mysql:5.7', 'mariadb:latest']
 | 
				
			||||||
@ -61,7 +90,7 @@ jobs:
 | 
				
			|||||||
          --health-retries 10
 | 
					          --health-retries 10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
    - name: Set up Go 1.x
 | 
					    - name: Set up Go ${{ matrix.go }}
 | 
				
			||||||
      uses: actions/setup-go@v2
 | 
					      uses: actions/setup-go@v2
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
        go-version: ${{ matrix.go }}
 | 
					        go-version: ${{ matrix.go }}
 | 
				
			||||||
@ -69,7 +98,6 @@ jobs:
 | 
				
			|||||||
    - name: Check out code into the Go module directory
 | 
					    - name: Check out code into the Go module directory
 | 
				
			||||||
      uses: actions/checkout@v2
 | 
					      uses: actions/checkout@v2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    - name: go mod package cache
 | 
					    - name: go mod package cache
 | 
				
			||||||
      uses: actions/cache@v2
 | 
					      uses: actions/cache@v2
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
@ -79,7 +107,16 @@ jobs:
 | 
				
			|||||||
    - name: Tests
 | 
					    - name: Tests
 | 
				
			||||||
      run: GORM_DIALECT=mysql GORM_DSN="gorm:gorm@tcp(localhost:9910)/gorm?charset=utf8&parseTime=True" ./tests/tests_all.sh
 | 
					      run: GORM_DIALECT=mysql GORM_DSN="gorm:gorm@tcp(localhost:9910)/gorm?charset=utf8&parseTime=True" ./tests/tests_all.sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    - name: Upload Code Coverage
 | 
				
			||||||
 | 
					      uses: codecov/codecov-action@v2
 | 
				
			||||||
 | 
					      with:
 | 
				
			||||||
 | 
					        name: mysql
 | 
				
			||||||
 | 
					        flags: mysql,go-${{ matrix.go }}
 | 
				
			||||||
 | 
					        fail_ci_if_error: true
 | 
				
			||||||
 | 
					        token: ${{ secrets.CODECOV_TOKEN }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  postgres:
 | 
					  postgres:
 | 
				
			||||||
 | 
					    needs: lint
 | 
				
			||||||
    strategy:
 | 
					    strategy:
 | 
				
			||||||
      matrix:
 | 
					      matrix:
 | 
				
			||||||
        dbversion: ['postgres:latest', 'postgres:13', 'postgres:12', 'postgres:11', 'postgres:10']
 | 
					        dbversion: ['postgres:latest', 'postgres:13', 'postgres:12', 'postgres:11', 'postgres:10']
 | 
				
			||||||
@ -105,7 +142,7 @@ jobs:
 | 
				
			|||||||
          --health-retries 5
 | 
					          --health-retries 5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
    - name: Set up Go 1.x
 | 
					    - name: Set up Go ${{ matrix.go }}
 | 
				
			||||||
      uses: actions/setup-go@v2
 | 
					      uses: actions/setup-go@v2
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
        go-version: ${{ matrix.go }}
 | 
					        go-version: ${{ matrix.go }}
 | 
				
			||||||
@ -122,7 +159,16 @@ jobs:
 | 
				
			|||||||
    - name: Tests
 | 
					    - name: Tests
 | 
				
			||||||
      run: GORM_DIALECT=postgres GORM_DSN="user=gorm password=gorm dbname=gorm host=localhost port=9920 sslmode=disable TimeZone=Asia/Shanghai" ./tests/tests_all.sh
 | 
					      run: GORM_DIALECT=postgres GORM_DSN="user=gorm password=gorm dbname=gorm host=localhost port=9920 sslmode=disable TimeZone=Asia/Shanghai" ./tests/tests_all.sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    - name: Upload Code Coverage
 | 
				
			||||||
 | 
					      uses: codecov/codecov-action@v2
 | 
				
			||||||
 | 
					      with:
 | 
				
			||||||
 | 
					        name: postgres
 | 
				
			||||||
 | 
					        flags: postgres,go-${{ matrix.go }}
 | 
				
			||||||
 | 
					        fail_ci_if_error: true
 | 
				
			||||||
 | 
					        token: ${{ secrets.CODECOV_TOKEN }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  sqlserver:
 | 
					  sqlserver:
 | 
				
			||||||
 | 
					    needs: lint
 | 
				
			||||||
    strategy:
 | 
					    strategy:
 | 
				
			||||||
      matrix:
 | 
					      matrix:
 | 
				
			||||||
        go: ['1.17', '1.16']
 | 
					        go: ['1.17', '1.16']
 | 
				
			||||||
@ -148,7 +194,7 @@ jobs:
 | 
				
			|||||||
          --health-retries 10
 | 
					          --health-retries 10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    steps:
 | 
					    steps:
 | 
				
			||||||
    - name: Set up Go 1.x
 | 
					    - name: Set up Go ${{ matrix.go }}
 | 
				
			||||||
      uses: actions/setup-go@v2
 | 
					      uses: actions/setup-go@v2
 | 
				
			||||||
      with:
 | 
					      with:
 | 
				
			||||||
        go-version: ${{ matrix.go }}
 | 
					        go-version: ${{ matrix.go }}
 | 
				
			||||||
@ -164,3 +210,11 @@ jobs:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    - name: Tests
 | 
					    - name: Tests
 | 
				
			||||||
      run: GORM_DIALECT=sqlserver GORM_DSN="sqlserver://gorm:LoremIpsum86@localhost:9930?database=gorm" ./tests/tests_all.sh
 | 
					      run: GORM_DIALECT=sqlserver GORM_DSN="sqlserver://gorm:LoremIpsum86@localhost:9930?database=gorm" ./tests/tests_all.sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    - name: Upload Code Coverage
 | 
				
			||||||
 | 
					      uses: codecov/codecov-action@v2
 | 
				
			||||||
 | 
					      with:
 | 
				
			||||||
 | 
					        name: sqlserver
 | 
				
			||||||
 | 
					        flags: sqlserver,go-${{ matrix.go }}
 | 
				
			||||||
 | 
					        fail_ci_if_error: true
 | 
				
			||||||
 | 
					        token: ${{ secrets.CODECOV_TOKEN }}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,11 +1,33 @@
 | 
				
			|||||||
linters:
 | 
					linters:
 | 
				
			||||||
  enable:
 | 
					  disable:
 | 
				
			||||||
    - cyclop
 | 
					    - cyclop
 | 
				
			||||||
    - exportloopref
 | 
					    - errcheck
 | 
				
			||||||
    - gocritic
 | 
					 | 
				
			||||||
    - gosec
 | 
					    - gosec
 | 
				
			||||||
    - ineffassign
 | 
					    - ineffassign
 | 
				
			||||||
 | 
					    - staticcheck
 | 
				
			||||||
 | 
					    - structcheck
 | 
				
			||||||
 | 
					  enable:
 | 
				
			||||||
 | 
					    - errorlint
 | 
				
			||||||
 | 
					    - exportloopref
 | 
				
			||||||
 | 
					    - gci 
 | 
				
			||||||
 | 
					    - gocritic
 | 
				
			||||||
 | 
					    - gofumpt
 | 
				
			||||||
    - misspell
 | 
					    - misspell
 | 
				
			||||||
    - prealloc
 | 
					    - prealloc
 | 
				
			||||||
    - unconvert
 | 
					    - unconvert
 | 
				
			||||||
    - unparam
 | 
					    - unparam
 | 
				
			||||||
 | 
					issues:  
 | 
				
			||||||
 | 
					  # Maximum issues count per one linter. Set to 0 to disable. Default is 50.
 | 
				
			||||||
 | 
					  max-issues-per-linter: 0
 | 
				
			||||||
 | 
					  # Maximum count of issues with the same text. Set to 0 to disable. Default is 3.
 | 
				
			||||||
 | 
					  max-same-issues: 0
 | 
				
			||||||
 | 
					  exclude-rules:
 | 
				
			||||||
 | 
					  - linters:
 | 
				
			||||||
 | 
					      - gocritic
 | 
				
			||||||
 | 
					    text: "singleCaseSwitch"
 | 
				
			||||||
 | 
					  - linters:
 | 
				
			||||||
 | 
					      - gocritic
 | 
				
			||||||
 | 
					    text: "ifElseChain"
 | 
				
			||||||
 | 
					linters-settings:
 | 
				
			||||||
 | 
					  gci:
 | 
				
			||||||
 | 
					    local-prefixes: gorm.io/gorm
 | 
				
			||||||
@ -241,8 +241,9 @@ func getRIndex(strs []string, str string) int {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func sortCallbacks(cs []*callback) (fns []func(*DB), err error) {
 | 
					func sortCallbacks(cs []*callback) (fns []func(*DB), err error) {
 | 
				
			||||||
 | 
						names := make([]string, 0)
 | 
				
			||||||
	var (
 | 
						var (
 | 
				
			||||||
		names, sorted []string
 | 
							sorted       []string
 | 
				
			||||||
		sortCallback func(*callback) error
 | 
							sortCallback func(*callback) error
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
	sort.Slice(cs, func(i, j int) bool {
 | 
						sort.Slice(cs, func(i, j int) bool {
 | 
				
			||||||
 | 
				
			|||||||
@ -323,7 +323,7 @@ func SaveAfterAssociations(create bool) func(db *gorm.DB) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func onConflictOption(stmt *gorm.Statement, s *schema.Schema, selectColumns map[string]bool, restricted bool, defaultUpdatingColumns []string) (onConflict clause.OnConflict) {
 | 
					func onConflictOption(stmt *gorm.Statement, s *schema.Schema, defaultUpdatingColumns []string) (onConflict clause.OnConflict) {
 | 
				
			||||||
	if len(defaultUpdatingColumns) > 0 || stmt.DB.FullSaveAssociations {
 | 
						if len(defaultUpdatingColumns) > 0 || stmt.DB.FullSaveAssociations {
 | 
				
			||||||
		onConflict.Columns = make([]clause.Column, 0, len(s.PrimaryFieldDBNames))
 | 
							onConflict.Columns = make([]clause.Column, 0, len(s.PrimaryFieldDBNames))
 | 
				
			||||||
		for _, dbName := range s.PrimaryFieldDBNames {
 | 
							for _, dbName := range s.PrimaryFieldDBNames {
 | 
				
			||||||
@ -344,7 +344,7 @@ func onConflictOption(stmt *gorm.Statement, s *schema.Schema, selectColumns map[
 | 
				
			|||||||
func saveAssociations(db *gorm.DB, rel *schema.Relationship, values interface{}, selectColumns map[string]bool, restricted bool, defaultUpdatingColumns []string) error {
 | 
					func saveAssociations(db *gorm.DB, rel *schema.Relationship, values interface{}, selectColumns map[string]bool, restricted bool, defaultUpdatingColumns []string) error {
 | 
				
			||||||
	var (
 | 
						var (
 | 
				
			||||||
		selects, omits []string
 | 
							selects, omits []string
 | 
				
			||||||
		onConflict     = onConflictOption(db.Statement, rel.FieldSchema, selectColumns, restricted, defaultUpdatingColumns)
 | 
							onConflict     = onConflictOption(db.Statement, rel.FieldSchema, defaultUpdatingColumns)
 | 
				
			||||||
		refName        = rel.Name + "."
 | 
							refName        = rel.Name + "."
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -12,7 +12,7 @@ func ConvertMapToValuesForCreate(stmt *gorm.Statement, mapValue map[string]inter
 | 
				
			|||||||
	values.Columns = make([]clause.Column, 0, len(mapValue))
 | 
						values.Columns = make([]clause.Column, 0, len(mapValue))
 | 
				
			||||||
	selectColumns, restricted := stmt.SelectAndOmitColumns(true, false)
 | 
						selectColumns, restricted := stmt.SelectAndOmitColumns(true, false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var keys = make([]string, 0, len(mapValue))
 | 
						keys := make([]string, 0, len(mapValue))
 | 
				
			||||||
	for k := range mapValue {
 | 
						for k := range mapValue {
 | 
				
			||||||
		keys = append(keys, k)
 | 
							keys = append(keys, k)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -40,9 +40,7 @@ func ConvertMapToValuesForCreate(stmt *gorm.Statement, mapValue map[string]inter
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// ConvertSliceOfMapToValuesForCreate convert slice of map to values
 | 
					// ConvertSliceOfMapToValuesForCreate convert slice of map to values
 | 
				
			||||||
func ConvertSliceOfMapToValuesForCreate(stmt *gorm.Statement, mapValues []map[string]interface{}) (values clause.Values) {
 | 
					func ConvertSliceOfMapToValuesForCreate(stmt *gorm.Statement, mapValues []map[string]interface{}) (values clause.Values) {
 | 
				
			||||||
	var (
 | 
						columns := make([]string, 0, len(mapValues))
 | 
				
			||||||
		columns = make([]string, 0, len(mapValues))
 | 
					 | 
				
			||||||
	)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// when the length of mapValues is zero,return directly here
 | 
						// when the length of mapValues is zero,return directly here
 | 
				
			||||||
	// no need to call stmt.SelectAndOmitColumns method
 | 
						// no need to call stmt.SelectAndOmitColumns method
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,8 @@
 | 
				
			|||||||
package callbacks
 | 
					package callbacks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"gorm.io/gorm"
 | 
						"gorm.io/gorm"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -9,7 +11,7 @@ func BeginTransaction(db *gorm.DB) {
 | 
				
			|||||||
		if tx := db.Begin(); tx.Error == nil {
 | 
							if tx := db.Begin(); tx.Error == nil {
 | 
				
			||||||
			db.Statement.ConnPool = tx.Statement.ConnPool
 | 
								db.Statement.ConnPool = tx.Statement.ConnPool
 | 
				
			||||||
			db.InstanceSet("gorm:started_transaction", true)
 | 
								db.InstanceSet("gorm:started_transaction", true)
 | 
				
			||||||
		} else if tx.Error == gorm.ErrInvalidTransaction {
 | 
							} else if errors.Is(tx.Error, gorm.ErrInvalidTransaction) {
 | 
				
			||||||
			tx.Error = nil
 | 
								tx.Error = nil
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			db.Error = tx.Error
 | 
								db.Error = tx.Error
 | 
				
			||||||
 | 
				
			|||||||
@ -162,7 +162,7 @@ func ConvertToAssignments(stmt *gorm.Statement) (set clause.Set) {
 | 
				
			|||||||
			if size := stmt.ReflectValue.Len(); size > 0 {
 | 
								if size := stmt.ReflectValue.Len(); size > 0 {
 | 
				
			||||||
				var primaryKeyExprs []clause.Expression
 | 
									var primaryKeyExprs []clause.Expression
 | 
				
			||||||
				for i := 0; i < size; i++ {
 | 
									for i := 0; i < size; i++ {
 | 
				
			||||||
					var exprs = make([]clause.Expression, len(stmt.Schema.PrimaryFields))
 | 
										exprs := make([]clause.Expression, len(stmt.Schema.PrimaryFields))
 | 
				
			||||||
					var notZero bool
 | 
										var notZero bool
 | 
				
			||||||
					for idx, field := range stmt.Schema.PrimaryFields {
 | 
										for idx, field := range stmt.Schema.PrimaryFields {
 | 
				
			||||||
						value, isZero := field.ValueOf(stmt.ReflectValue.Index(i))
 | 
											value, isZero := field.ValueOf(stmt.ReflectValue.Index(i))
 | 
				
			||||||
@ -242,7 +242,7 @@ func ConvertToAssignments(stmt *gorm.Statement) (set clause.Set) {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		var updatingSchema = stmt.Schema
 | 
							updatingSchema := stmt.Schema
 | 
				
			||||||
		if !updatingValue.CanAddr() || stmt.Dest != stmt.Model {
 | 
							if !updatingValue.CanAddr() || stmt.Dest != stmt.Model {
 | 
				
			||||||
			// different schema
 | 
								// different schema
 | 
				
			||||||
			updatingStmt := &gorm.Statement{DB: stmt.DB}
 | 
								updatingStmt := &gorm.Statement{DB: stmt.DB}
 | 
				
			||||||
 | 
				
			|||||||
@ -32,7 +32,8 @@ func BenchmarkComplexSelect(b *testing.B) {
 | 
				
			|||||||
	for i := 0; i < b.N; i++ {
 | 
						for i := 0; i < b.N; i++ {
 | 
				
			||||||
		stmt := gorm.Statement{DB: db, Table: user.Table, Schema: user, Clauses: map[string]clause.Clause{}}
 | 
							stmt := gorm.Statement{DB: db, Table: user.Table, Schema: user, Clauses: map[string]clause.Clause{}}
 | 
				
			||||||
		clauses := []clause.Interface{
 | 
							clauses := []clause.Interface{
 | 
				
			||||||
			clause.Select{}, clause.From{},
 | 
								clause.Select{},
 | 
				
			||||||
 | 
								clause.From{},
 | 
				
			||||||
			clause.Where{Exprs: []clause.Expression{
 | 
								clause.Where{Exprs: []clause.Expression{
 | 
				
			||||||
				clause.Eq{Column: clause.PrimaryColumn, Value: "1"},
 | 
									clause.Eq{Column: clause.PrimaryColumn, Value: "1"},
 | 
				
			||||||
				clause.Gt{Column: "age", Value: 18},
 | 
									clause.Gt{Column: "age", Value: 18},
 | 
				
			||||||
 | 
				
			|||||||
@ -18,7 +18,8 @@ func TestGroupBy(t *testing.T) {
 | 
				
			|||||||
				Columns: []clause.Column{{Name: "role"}},
 | 
									Columns: []clause.Column{{Name: "role"}},
 | 
				
			||||||
				Having:  []clause.Expression{clause.Eq{"role", "admin"}},
 | 
									Having:  []clause.Expression{clause.Eq{"role", "admin"}},
 | 
				
			||||||
			}},
 | 
								}},
 | 
				
			||||||
			"SELECT * FROM `users` GROUP BY `role` HAVING `role` = ?", []interface{}{"admin"},
 | 
								"SELECT * FROM `users` GROUP BY `role` HAVING `role` = ?",
 | 
				
			||||||
 | 
								[]interface{}{"admin"},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			[]clause.Interface{clause.Select{}, clause.From{}, clause.GroupBy{
 | 
								[]clause.Interface{clause.Select{}, clause.From{}, clause.GroupBy{
 | 
				
			||||||
@ -28,7 +29,8 @@ func TestGroupBy(t *testing.T) {
 | 
				
			|||||||
				Columns: []clause.Column{{Name: "gender"}},
 | 
									Columns: []clause.Column{{Name: "gender"}},
 | 
				
			||||||
				Having:  []clause.Expression{clause.Neq{"gender", "U"}},
 | 
									Having:  []clause.Expression{clause.Neq{"gender", "U"}},
 | 
				
			||||||
			}},
 | 
								}},
 | 
				
			||||||
			"SELECT * FROM `users` GROUP BY `role`,`gender` HAVING `role` = ? AND `gender` <> ?", []interface{}{"admin", "U"},
 | 
								"SELECT * FROM `users` GROUP BY `role`,`gender` HAVING `role` = ? AND `gender` <> ?",
 | 
				
			||||||
 | 
								[]interface{}{"admin", "U"},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -45,7 +45,8 @@ func TestOrderBy(t *testing.T) {
 | 
				
			|||||||
					Expression: clause.Expr{SQL: "FIELD(id, ?)", Vars: []interface{}{[]int{1, 2, 3}}, WithoutParentheses: true},
 | 
										Expression: clause.Expr{SQL: "FIELD(id, ?)", Vars: []interface{}{[]int{1, 2, 3}}, WithoutParentheses: true},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			"SELECT * FROM `users` ORDER BY FIELD(id, ?,?,?)", []interface{}{1, 2, 3},
 | 
								"SELECT * FROM `users` ORDER BY FIELD(id, ?,?,?)",
 | 
				
			||||||
 | 
								[]interface{}{1, 2, 3},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -20,7 +20,8 @@ func TestSet(t *testing.T) {
 | 
				
			|||||||
				clause.Update{},
 | 
									clause.Update{},
 | 
				
			||||||
				clause.Set([]clause.Assignment{{clause.PrimaryColumn, 1}}),
 | 
									clause.Set([]clause.Assignment{{clause.PrimaryColumn, 1}}),
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			"UPDATE `users` SET `users`.`id`=?", []interface{}{1},
 | 
								"UPDATE `users` SET `users`.`id`=?",
 | 
				
			||||||
 | 
								[]interface{}{1},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			[]clause.Interface{
 | 
								[]clause.Interface{
 | 
				
			||||||
@ -28,7 +29,8 @@ func TestSet(t *testing.T) {
 | 
				
			|||||||
				clause.Set([]clause.Assignment{{clause.PrimaryColumn, 1}}),
 | 
									clause.Set([]clause.Assignment{{clause.PrimaryColumn, 1}}),
 | 
				
			||||||
				clause.Set([]clause.Assignment{{clause.Column{Name: "name"}, "jinzhu"}}),
 | 
									clause.Set([]clause.Assignment{{clause.Column{Name: "name"}, "jinzhu"}}),
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			"UPDATE `users` SET `name`=?", []interface{}{"jinzhu"},
 | 
								"UPDATE `users` SET `name`=?",
 | 
				
			||||||
 | 
								[]interface{}{"jinzhu"},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -21,7 +21,8 @@ func TestValues(t *testing.T) {
 | 
				
			|||||||
					Values:  [][]interface{}{{"jinzhu", 18}, {"josh", 1}},
 | 
										Values:  [][]interface{}{{"jinzhu", 18}, {"josh", 1}},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			"INSERT INTO `users` (`name`,`age`) VALUES (?,?),(?,?)", []interface{}{"jinzhu", 18, "josh", 1},
 | 
								"INSERT INTO `users` (`name`,`age`) VALUES (?,?),(?,?)",
 | 
				
			||||||
 | 
								[]interface{}{"jinzhu", 18, "josh", 1},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -17,25 +17,29 @@ func TestWhere(t *testing.T) {
 | 
				
			|||||||
			[]clause.Interface{clause.Select{}, clause.From{}, clause.Where{
 | 
								[]clause.Interface{clause.Select{}, clause.From{}, clause.Where{
 | 
				
			||||||
				Exprs: []clause.Expression{clause.Eq{Column: clause.PrimaryColumn, Value: "1"}, clause.Gt{Column: "age", Value: 18}, clause.Or(clause.Neq{Column: "name", Value: "jinzhu"})},
 | 
									Exprs: []clause.Expression{clause.Eq{Column: clause.PrimaryColumn, Value: "1"}, clause.Gt{Column: "age", Value: 18}, clause.Or(clause.Neq{Column: "name", Value: "jinzhu"})},
 | 
				
			||||||
			}},
 | 
								}},
 | 
				
			||||||
			"SELECT * FROM `users` WHERE `users`.`id` = ? AND `age` > ? OR `name` <> ?", []interface{}{"1", 18, "jinzhu"},
 | 
								"SELECT * FROM `users` WHERE `users`.`id` = ? AND `age` > ? OR `name` <> ?",
 | 
				
			||||||
 | 
								[]interface{}{"1", 18, "jinzhu"},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			[]clause.Interface{clause.Select{}, clause.From{}, clause.Where{
 | 
								[]clause.Interface{clause.Select{}, clause.From{}, clause.Where{
 | 
				
			||||||
				Exprs: []clause.Expression{clause.Or(clause.Neq{Column: "name", Value: "jinzhu"}), clause.Eq{Column: clause.PrimaryColumn, Value: "1"}, clause.Gt{Column: "age", Value: 18}},
 | 
									Exprs: []clause.Expression{clause.Or(clause.Neq{Column: "name", Value: "jinzhu"}), clause.Eq{Column: clause.PrimaryColumn, Value: "1"}, clause.Gt{Column: "age", Value: 18}},
 | 
				
			||||||
			}},
 | 
								}},
 | 
				
			||||||
			"SELECT * FROM `users` WHERE `users`.`id` = ? OR `name` <> ? AND `age` > ?", []interface{}{"1", "jinzhu", 18},
 | 
								"SELECT * FROM `users` WHERE `users`.`id` = ? OR `name` <> ? AND `age` > ?",
 | 
				
			||||||
 | 
								[]interface{}{"1", "jinzhu", 18},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			[]clause.Interface{clause.Select{}, clause.From{}, clause.Where{
 | 
								[]clause.Interface{clause.Select{}, clause.From{}, clause.Where{
 | 
				
			||||||
				Exprs: []clause.Expression{clause.Or(clause.Neq{Column: "name", Value: "jinzhu"}), clause.Eq{Column: clause.PrimaryColumn, Value: "1"}, clause.Gt{Column: "age", Value: 18}},
 | 
									Exprs: []clause.Expression{clause.Or(clause.Neq{Column: "name", Value: "jinzhu"}), clause.Eq{Column: clause.PrimaryColumn, Value: "1"}, clause.Gt{Column: "age", Value: 18}},
 | 
				
			||||||
			}},
 | 
								}},
 | 
				
			||||||
			"SELECT * FROM `users` WHERE `users`.`id` = ? OR `name` <> ? AND `age` > ?", []interface{}{"1", "jinzhu", 18},
 | 
								"SELECT * FROM `users` WHERE `users`.`id` = ? OR `name` <> ? AND `age` > ?",
 | 
				
			||||||
 | 
								[]interface{}{"1", "jinzhu", 18},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			[]clause.Interface{clause.Select{}, clause.From{}, clause.Where{
 | 
								[]clause.Interface{clause.Select{}, clause.From{}, clause.Where{
 | 
				
			||||||
				Exprs: []clause.Expression{clause.Or(clause.Eq{Column: clause.PrimaryColumn, Value: "1"}), clause.Or(clause.Neq{Column: "name", Value: "jinzhu"})},
 | 
									Exprs: []clause.Expression{clause.Or(clause.Eq{Column: clause.PrimaryColumn, Value: "1"}), clause.Or(clause.Neq{Column: "name", Value: "jinzhu"})},
 | 
				
			||||||
			}},
 | 
								}},
 | 
				
			||||||
			"SELECT * FROM `users` WHERE `users`.`id` = ? OR `name` <> ?", []interface{}{"1", "jinzhu"},
 | 
								"SELECT * FROM `users` WHERE `users`.`id` = ? OR `name` <> ?",
 | 
				
			||||||
 | 
								[]interface{}{"1", "jinzhu"},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			[]clause.Interface{clause.Select{}, clause.From{}, clause.Where{
 | 
								[]clause.Interface{clause.Select{}, clause.From{}, clause.Where{
 | 
				
			||||||
@ -43,7 +47,8 @@ func TestWhere(t *testing.T) {
 | 
				
			|||||||
			}, clause.Where{
 | 
								}, clause.Where{
 | 
				
			||||||
				Exprs: []clause.Expression{clause.Or(clause.Gt{Column: "score", Value: 100}, clause.Like{Column: "name", Value: "%linus%"})},
 | 
									Exprs: []clause.Expression{clause.Or(clause.Gt{Column: "score", Value: 100}, clause.Like{Column: "name", Value: "%linus%"})},
 | 
				
			||||||
			}},
 | 
								}},
 | 
				
			||||||
			"SELECT * FROM `users` WHERE `users`.`id` = ? AND `age` > ? OR `name` <> ? AND (`score` > ? OR `name` LIKE ?)", []interface{}{"1", 18, "jinzhu", 100, "%linus%"},
 | 
								"SELECT * FROM `users` WHERE `users`.`id` = ? AND `age` > ? OR `name` <> ? AND (`score` > ? OR `name` LIKE ?)",
 | 
				
			||||||
 | 
								[]interface{}{"1", 18, "jinzhu", 100, "%linus%"},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			[]clause.Interface{clause.Select{}, clause.From{}, clause.Where{
 | 
								[]clause.Interface{clause.Select{}, clause.From{}, clause.Where{
 | 
				
			||||||
@ -51,13 +56,15 @@ func TestWhere(t *testing.T) {
 | 
				
			|||||||
			}, clause.Where{
 | 
								}, clause.Where{
 | 
				
			||||||
				Exprs: []clause.Expression{clause.Or(clause.Not(clause.Gt{Column: "score", Value: 100}), clause.Like{Column: "name", Value: "%linus%"})},
 | 
									Exprs: []clause.Expression{clause.Or(clause.Not(clause.Gt{Column: "score", Value: 100}), clause.Like{Column: "name", Value: "%linus%"})},
 | 
				
			||||||
			}},
 | 
								}},
 | 
				
			||||||
			"SELECT * FROM `users` WHERE (`users`.`id` <> ? AND `age` <= ?) OR `name` <> ? AND (`score` <= ? OR `name` LIKE ?)", []interface{}{"1", 18, "jinzhu", 100, "%linus%"},
 | 
								"SELECT * FROM `users` WHERE (`users`.`id` <> ? AND `age` <= ?) OR `name` <> ? AND (`score` <= ? OR `name` LIKE ?)",
 | 
				
			||||||
 | 
								[]interface{}{"1", 18, "jinzhu", 100, "%linus%"},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			[]clause.Interface{clause.Select{}, clause.From{}, clause.Where{
 | 
								[]clause.Interface{clause.Select{}, clause.From{}, clause.Where{
 | 
				
			||||||
				Exprs: []clause.Expression{clause.And(clause.Eq{Column: "age", Value: 18}, clause.Or(clause.Neq{Column: "name", Value: "jinzhu"}))},
 | 
									Exprs: []clause.Expression{clause.And(clause.Eq{Column: "age", Value: 18}, clause.Or(clause.Neq{Column: "name", Value: "jinzhu"}))},
 | 
				
			||||||
			}},
 | 
								}},
 | 
				
			||||||
			"SELECT * FROM `users` WHERE (`age` = ? OR `name` <> ?)", []interface{}{18, "jinzhu"},
 | 
								"SELECT * FROM `users` WHERE (`age` = ? OR `name` <> ?)",
 | 
				
			||||||
 | 
								[]interface{}{18, "jinzhu"},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,3 @@
 | 
				
			|||||||
package clause
 | 
					package clause
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type With struct {
 | 
					type With struct{}
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -32,7 +32,7 @@ var convertibleTypes = []reflect.Type{reflect.TypeOf(time.Time{}), reflect.TypeO
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func ExplainSQL(sql string, numericPlaceholder *regexp.Regexp, escaper string, avars ...interface{}) string {
 | 
					func ExplainSQL(sql string, numericPlaceholder *regexp.Regexp, escaper string, avars ...interface{}) string {
 | 
				
			||||||
	var convertParams func(interface{}, int)
 | 
						var convertParams func(interface{}, int)
 | 
				
			||||||
	var vars = make([]string, len(avars))
 | 
						vars := make([]string, len(avars))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	convertParams = func(v interface{}, idx int) {
 | 
						convertParams = func(v interface{}, idx int) {
 | 
				
			||||||
		switch v := v.(type) {
 | 
							switch v := v.(type) {
 | 
				
			||||||
@ -65,13 +65,13 @@ func ExplainSQL(sql string, numericPlaceholder *regexp.Regexp, escaper string, a
 | 
				
			|||||||
		case fmt.Stringer:
 | 
							case fmt.Stringer:
 | 
				
			||||||
			reflectValue := reflect.ValueOf(v)
 | 
								reflectValue := reflect.ValueOf(v)
 | 
				
			||||||
			if v != nil && reflectValue.IsValid() && ((reflectValue.Kind() == reflect.Ptr && !reflectValue.IsNil()) || reflectValue.Kind() != reflect.Ptr) {
 | 
								if v != nil && reflectValue.IsValid() && ((reflectValue.Kind() == reflect.Ptr && !reflectValue.IsNil()) || reflectValue.Kind() != reflect.Ptr) {
 | 
				
			||||||
				vars[idx] = escaper + strings.Replace(fmt.Sprintf("%v", v), escaper, "\\"+escaper, -1) + escaper
 | 
									vars[idx] = escaper + strings.ReplaceAll(fmt.Sprintf("%v", v), escaper, "\\"+escaper) + escaper
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				vars[idx] = nullStr
 | 
									vars[idx] = nullStr
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		case []byte:
 | 
							case []byte:
 | 
				
			||||||
			if isPrintable(v) {
 | 
								if isPrintable(v) {
 | 
				
			||||||
				vars[idx] = escaper + strings.Replace(string(v), escaper, "\\"+escaper, -1) + escaper
 | 
									vars[idx] = escaper + strings.ReplaceAll(string(v), escaper, "\\"+escaper) + escaper
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				vars[idx] = escaper + "<binary>" + escaper
 | 
									vars[idx] = escaper + "<binary>" + escaper
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@ -80,7 +80,7 @@ func ExplainSQL(sql string, numericPlaceholder *regexp.Regexp, escaper string, a
 | 
				
			|||||||
		case float64, float32:
 | 
							case float64, float32:
 | 
				
			||||||
			vars[idx] = fmt.Sprintf("%.6f", v)
 | 
								vars[idx] = fmt.Sprintf("%.6f", v)
 | 
				
			||||||
		case string:
 | 
							case string:
 | 
				
			||||||
			vars[idx] = escaper + strings.Replace(v, escaper, "\\"+escaper, -1) + escaper
 | 
								vars[idx] = escaper + strings.ReplaceAll(v, escaper, "\\"+escaper) + escaper
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			rv := reflect.ValueOf(v)
 | 
								rv := reflect.ValueOf(v)
 | 
				
			||||||
			if v == nil || !rv.IsValid() || rv.Kind() == reflect.Ptr && rv.IsNil() {
 | 
								if v == nil || !rv.IsValid() || rv.Kind() == reflect.Ptr && rv.IsNil() {
 | 
				
			||||||
@ -97,7 +97,7 @@ func ExplainSQL(sql string, numericPlaceholder *regexp.Regexp, escaper string, a
 | 
				
			|||||||
						return
 | 
											return
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				vars[idx] = escaper + strings.Replace(fmt.Sprint(v), escaper, "\\"+escaper, -1) + escaper
 | 
									vars[idx] = escaper + strings.ReplaceAll(fmt.Sprint(v), escaper, "\\"+escaper) + escaper
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
@ -9,6 +9,7 @@ import (
 | 
				
			|||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/jinzhu/now"
 | 
						"github.com/jinzhu/now"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"gorm.io/gorm/logger"
 | 
						"gorm.io/gorm/logger"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -30,8 +31,9 @@ func (s ExampleStruct) Value() (driver.Value, error) {
 | 
				
			|||||||
	return json.Marshal(s)
 | 
						return json.Marshal(s)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func format(v []byte, escaper string) string {
 | 
					func format(v []byte) string {
 | 
				
			||||||
	return escaper + strings.Replace(string(v), escaper, "\\"+escaper, -1) + escaper
 | 
						escaper := `"`
 | 
				
			||||||
 | 
						return escaper + strings.ReplaceAll(string(v), escaper, "\\"+escaper) + escaper
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestExplainSQL(t *testing.T) {
 | 
					func TestExplainSQL(t *testing.T) {
 | 
				
			||||||
@ -87,13 +89,13 @@ func TestExplainSQL(t *testing.T) {
 | 
				
			|||||||
			SQL:           "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
 | 
								SQL:           "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
 | 
				
			||||||
			NumericRegexp: nil,
 | 
								NumericRegexp: nil,
 | 
				
			||||||
			Vars:          []interface{}{"jinzhu", 1, 999.99, true, []byte("12345"), tt, &tt, nil, "w@g.\"com", myrole, pwd, js, es},
 | 
								Vars:          []interface{}{"jinzhu", 1, 999.99, true, []byte("12345"), tt, &tt, nil, "w@g.\"com", myrole, pwd, js, es},
 | 
				
			||||||
			Result:        fmt.Sprintf(`create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values ("jinzhu", 1, 999.990000, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.\"com", "admin", "pass", %v, %v)`, format(jsVal, `"`), format(esVal, `"`)),
 | 
								Result:        fmt.Sprintf(`create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values ("jinzhu", 1, 999.990000, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.\"com", "admin", "pass", %v, %v)`, format(jsVal), format(esVal)),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			SQL:           "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
 | 
								SQL:           "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
 | 
				
			||||||
			NumericRegexp: nil,
 | 
								NumericRegexp: nil,
 | 
				
			||||||
			Vars:          []interface{}{"jinzhu", 1, 999.99, true, []byte("12345"), tt, &tt, nil, "w@g.\"com", myrole, pwd, &js, &es},
 | 
								Vars:          []interface{}{"jinzhu", 1, 999.99, true, []byte("12345"), tt, &tt, nil, "w@g.\"com", myrole, pwd, &js, &es},
 | 
				
			||||||
			Result:        fmt.Sprintf(`create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values ("jinzhu", 1, 999.990000, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.\"com", "admin", "pass", %v, %v)`, format(jsVal, `"`), format(esVal, `"`)),
 | 
								Result:        fmt.Sprintf(`create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values ("jinzhu", 1, 999.990000, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.\"com", "admin", "pass", %v, %v)`, format(jsVal), format(esVal)),
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -474,7 +474,8 @@ func buildConstraint(constraint *schema.Constraint) (sql string, results []inter
 | 
				
			|||||||
		sql += " ON UPDATE " + constraint.OnUpdate
 | 
							sql += " ON UPDATE " + constraint.OnUpdate
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var foreignKeys, references []interface{}
 | 
						foreignKeys := make([]interface{}, 0)
 | 
				
			||||||
 | 
						references := make([]interface{}, 0)
 | 
				
			||||||
	for _, field := range constraint.ForeignKeys {
 | 
						for _, field := range constraint.ForeignKeys {
 | 
				
			||||||
		foreignKeys = append(foreignKeys, clause.Column{Name: field.DBName})
 | 
							foreignKeys = append(foreignKeys, clause.Column{Name: field.DBName})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -541,7 +542,7 @@ func (m Migrator) CreateConstraint(value interface{}, name string) error {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if constraint != nil {
 | 
							if constraint != nil {
 | 
				
			||||||
			var vars = []interface{}{clause.Table{Name: table}}
 | 
								vars := []interface{}{clause.Table{Name: table}}
 | 
				
			||||||
			if stmt.TableExpr != nil {
 | 
								if stmt.TableExpr != nil {
 | 
				
			||||||
				vars[0] = stmt.TableExpr
 | 
									vars[0] = stmt.TableExpr
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										9
									
								
								scan.go
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								scan.go
									
									
									
									
									
								
							@ -3,6 +3,7 @@ package gorm
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"database/sql"
 | 
						"database/sql"
 | 
				
			||||||
	"database/sql/driver"
 | 
						"database/sql/driver"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
	"reflect"
 | 
						"reflect"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
@ -49,7 +50,7 @@ func scanIntoMap(mapValue map[string]interface{}, values []interface{}, columns
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (db *DB) scanIntoStruct(sch *schema.Schema, rows *sql.Rows, reflectValue reflect.Value, values []interface{}, columns []string, fields []*schema.Field, joinFields [][2]*schema.Field) {
 | 
					func (db *DB) scanIntoStruct(sch *schema.Schema, rows *sql.Rows, reflectValue reflect.Value, values []interface{}, columns []string) {
 | 
				
			||||||
	for idx, column := range columns {
 | 
						for idx, column := range columns {
 | 
				
			||||||
		if sch == nil {
 | 
							if sch == nil {
 | 
				
			||||||
			values[idx] = reflectValue.Interface()
 | 
								values[idx] = reflectValue.Interface()
 | 
				
			||||||
@ -254,7 +255,7 @@ func Scan(rows *sql.Rows, db *DB, mode ScanMode) {
 | 
				
			|||||||
					elem = reflect.New(reflectValueType)
 | 
										elem = reflect.New(reflectValueType)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				db.scanIntoStruct(sch, rows, elem, values, columns, fields, joinFields)
 | 
									db.scanIntoStruct(sch, rows, elem, values, columns)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if !update {
 | 
									if !update {
 | 
				
			||||||
					if isPtr {
 | 
										if isPtr {
 | 
				
			||||||
@ -270,14 +271,14 @@ func Scan(rows *sql.Rows, db *DB, mode ScanMode) {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		case reflect.Struct, reflect.Ptr:
 | 
							case reflect.Struct, reflect.Ptr:
 | 
				
			||||||
			if initialized || rows.Next() {
 | 
								if initialized || rows.Next() {
 | 
				
			||||||
				db.scanIntoStruct(sch, rows, reflectValue, values, columns, fields, joinFields)
 | 
									db.scanIntoStruct(sch, rows, reflectValue, values, columns)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			db.AddError(rows.Scan(dest))
 | 
								db.AddError(rows.Scan(dest))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := rows.Err(); err != nil && err != db.Error {
 | 
						if err := rows.Err(); err != nil && !errors.Is(err, db.Error) {
 | 
				
			||||||
		db.AddError(err)
 | 
							db.AddError(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -9,8 +9,7 @@ import (
 | 
				
			|||||||
	"gorm.io/gorm/schema"
 | 
						"gorm.io/gorm/schema"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type UserWithCallback struct {
 | 
					type UserWithCallback struct{}
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (UserWithCallback) BeforeSave(*gorm.DB) error {
 | 
					func (UserWithCallback) BeforeSave(*gorm.DB) error {
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
 | 
				
			|||||||
@ -5,10 +5,8 @@ import (
 | 
				
			|||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var (
 | 
					 | 
				
			||||||
// reg match english letters and midline
 | 
					// reg match english letters and midline
 | 
				
			||||||
	regEnLetterAndMidline = regexp.MustCompile("^[A-Za-z-_]+$")
 | 
					var regEnLetterAndMidline = regexp.MustCompile("^[A-Za-z-_]+$")
 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Check struct {
 | 
					type Check struct {
 | 
				
			||||||
	Name       string
 | 
						Name       string
 | 
				
			||||||
@ -18,7 +16,7 @@ type Check struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// ParseCheckConstraints parse schema check constraints
 | 
					// ParseCheckConstraints parse schema check constraints
 | 
				
			||||||
func (schema *Schema) ParseCheckConstraints() map[string]Check {
 | 
					func (schema *Schema) ParseCheckConstraints() map[string]Check {
 | 
				
			||||||
	var checks = map[string]Check{}
 | 
						checks := map[string]Check{}
 | 
				
			||||||
	for _, field := range schema.FieldsByDBName {
 | 
						for _, field := range schema.FieldsByDBName {
 | 
				
			||||||
		if chk := field.TagSettings["CHECK"]; chk != "" {
 | 
							if chk := field.TagSettings["CHECK"]; chk != "" {
 | 
				
			||||||
			names := strings.Split(chk, ",")
 | 
								names := strings.Split(chk, ",")
 | 
				
			||||||
 | 
				
			|||||||
@ -11,6 +11,7 @@ import (
 | 
				
			|||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/jinzhu/now"
 | 
						"github.com/jinzhu/now"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"gorm.io/gorm/utils"
 | 
						"gorm.io/gorm/utils"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -199,28 +200,28 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
 | 
				
			|||||||
		field.DataType = Bool
 | 
							field.DataType = Bool
 | 
				
			||||||
		if field.HasDefaultValue && !skipParseDefaultValue {
 | 
							if field.HasDefaultValue && !skipParseDefaultValue {
 | 
				
			||||||
			if field.DefaultValueInterface, err = strconv.ParseBool(field.DefaultValue); err != nil {
 | 
								if field.DefaultValueInterface, err = strconv.ParseBool(field.DefaultValue); err != nil {
 | 
				
			||||||
				schema.err = fmt.Errorf("failed to parse %s as default value for bool, got error: %v", field.DefaultValue, err)
 | 
									schema.err = fmt.Errorf("failed to parse %s as default value for bool, got error: %w", field.DefaultValue, err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 | 
						case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 | 
				
			||||||
		field.DataType = Int
 | 
							field.DataType = Int
 | 
				
			||||||
		if field.HasDefaultValue && !skipParseDefaultValue {
 | 
							if field.HasDefaultValue && !skipParseDefaultValue {
 | 
				
			||||||
			if field.DefaultValueInterface, err = strconv.ParseInt(field.DefaultValue, 0, 64); err != nil {
 | 
								if field.DefaultValueInterface, err = strconv.ParseInt(field.DefaultValue, 0, 64); err != nil {
 | 
				
			||||||
				schema.err = fmt.Errorf("failed to parse %s as default value for int, got error: %v", field.DefaultValue, err)
 | 
									schema.err = fmt.Errorf("failed to parse %s as default value for int, got error: %w", field.DefaultValue, err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
 | 
						case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
 | 
				
			||||||
		field.DataType = Uint
 | 
							field.DataType = Uint
 | 
				
			||||||
		if field.HasDefaultValue && !skipParseDefaultValue {
 | 
							if field.HasDefaultValue && !skipParseDefaultValue {
 | 
				
			||||||
			if field.DefaultValueInterface, err = strconv.ParseUint(field.DefaultValue, 0, 64); err != nil {
 | 
								if field.DefaultValueInterface, err = strconv.ParseUint(field.DefaultValue, 0, 64); err != nil {
 | 
				
			||||||
				schema.err = fmt.Errorf("failed to parse %s as default value for uint, got error: %v", field.DefaultValue, err)
 | 
									schema.err = fmt.Errorf("failed to parse %s as default value for uint, got error: %w", field.DefaultValue, err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	case reflect.Float32, reflect.Float64:
 | 
						case reflect.Float32, reflect.Float64:
 | 
				
			||||||
		field.DataType = Float
 | 
							field.DataType = Float
 | 
				
			||||||
		if field.HasDefaultValue && !skipParseDefaultValue {
 | 
							if field.HasDefaultValue && !skipParseDefaultValue {
 | 
				
			||||||
			if field.DefaultValueInterface, err = strconv.ParseFloat(field.DefaultValue, 64); err != nil {
 | 
								if field.DefaultValueInterface, err = strconv.ParseFloat(field.DefaultValue, 64); err != nil {
 | 
				
			||||||
				schema.err = fmt.Errorf("failed to parse %s as default value for float, got error: %v", field.DefaultValue, err)
 | 
									schema.err = fmt.Errorf("failed to parse %s as default value for float, got error: %w", field.DefaultValue, err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	case reflect.String:
 | 
						case reflect.String:
 | 
				
			||||||
@ -745,7 +746,7 @@ func (field *Field) setupValuerAndSetter() {
 | 
				
			|||||||
					if t, err := now.Parse(data); err == nil {
 | 
										if t, err := now.Parse(data); err == nil {
 | 
				
			||||||
						field.ReflectValueOf(value).Set(reflect.ValueOf(t))
 | 
											field.ReflectValueOf(value).Set(reflect.ValueOf(t))
 | 
				
			||||||
					} else {
 | 
										} else {
 | 
				
			||||||
						return fmt.Errorf("failed to set string %v to time.Time field %s, failed to parse it as time, got error %v", v, field.Name, err)
 | 
											return fmt.Errorf("failed to set string %v to time.Time field %s, failed to parse it as time, got error %w", v, field.Name, err)
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				default:
 | 
									default:
 | 
				
			||||||
					return fallbackSetter(value, v, field.Set)
 | 
										return fallbackSetter(value, v, field.Set)
 | 
				
			||||||
@ -774,7 +775,7 @@ func (field *Field) setupValuerAndSetter() {
 | 
				
			|||||||
						}
 | 
											}
 | 
				
			||||||
						fieldValue.Elem().Set(reflect.ValueOf(t))
 | 
											fieldValue.Elem().Set(reflect.ValueOf(t))
 | 
				
			||||||
					} else {
 | 
										} else {
 | 
				
			||||||
						return fmt.Errorf("failed to set string %v to time.Time field %s, failed to parse it as time, got error %v", v, field.Name, err)
 | 
											return fmt.Errorf("failed to set string %v to time.Time field %s, failed to parse it as time, got error %w", v, field.Name, err)
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				default:
 | 
									default:
 | 
				
			||||||
					return fallbackSetter(value, v, field.Set)
 | 
										return fallbackSetter(value, v, field.Set)
 | 
				
			||||||
 | 
				
			|||||||
@ -261,22 +261,23 @@ func TestParseFieldWithPermission(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type ID int64
 | 
					type (
 | 
				
			||||||
type INT int
 | 
						ID        int64
 | 
				
			||||||
type INT8 int8
 | 
						INT       int
 | 
				
			||||||
type INT16 int16
 | 
						INT8      int8
 | 
				
			||||||
type INT32 int32
 | 
						INT16     int16
 | 
				
			||||||
type INT64 int64
 | 
						INT32     int32
 | 
				
			||||||
type UINT uint
 | 
						INT64     int64
 | 
				
			||||||
type UINT8 uint8
 | 
						UINT      uint
 | 
				
			||||||
type UINT16 uint16
 | 
						UINT8     uint8
 | 
				
			||||||
type UINT32 uint32
 | 
						UINT16    uint16
 | 
				
			||||||
type UINT64 uint64
 | 
						UINT32    uint32
 | 
				
			||||||
type FLOAT32 float32
 | 
						UINT64    uint64
 | 
				
			||||||
type FLOAT64 float64
 | 
						FLOAT32   float32
 | 
				
			||||||
type BOOL bool
 | 
						FLOAT64   float64
 | 
				
			||||||
type STRING string
 | 
						BOOL      bool
 | 
				
			||||||
type TypeAlias struct {
 | 
						STRING    string
 | 
				
			||||||
 | 
						TypeAlias struct {
 | 
				
			||||||
		ID
 | 
							ID
 | 
				
			||||||
		INT     `gorm:"column:fint"`
 | 
							INT     `gorm:"column:fint"`
 | 
				
			||||||
		INT8    `gorm:"column:fint8"`
 | 
							INT8    `gorm:"column:fint8"`
 | 
				
			||||||
@ -293,6 +294,7 @@ type TypeAlias struct {
 | 
				
			|||||||
		BOOL    `gorm:"column:fbool"`
 | 
							BOOL    `gorm:"column:fbool"`
 | 
				
			||||||
		STRING  `gorm:"column:fstring"`
 | 
							STRING  `gorm:"column:fstring"`
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestTypeAliasField(t *testing.T) {
 | 
					func TestTypeAliasField(t *testing.T) {
 | 
				
			||||||
	alias, err := schema.Parse(&TypeAlias{}, &sync.Map{}, schema.NamingStrategy{})
 | 
						alias, err := schema.Parse(&TypeAlias{}, &sync.Map{}, schema.NamingStrategy{})
 | 
				
			||||||
 | 
				
			|||||||
@ -27,7 +27,7 @@ type IndexOption struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// ParseIndexes parse schema indexes
 | 
					// ParseIndexes parse schema indexes
 | 
				
			||||||
func (schema *Schema) ParseIndexes() map[string]Index {
 | 
					func (schema *Schema) ParseIndexes() map[string]Index {
 | 
				
			||||||
	var indexes = map[string]Index{}
 | 
						indexes := map[string]Index{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, field := range schema.Fields {
 | 
						for _, field := range schema.Fields {
 | 
				
			||||||
		if field.TagSettings["INDEX"] != "" || field.TagSettings["UNIQUEINDEX"] != "" {
 | 
							if field.TagSettings["INDEX"] != "" || field.TagSettings["UNIQUEINDEX"] != "" {
 | 
				
			||||||
 | 
				
			|||||||
@ -26,9 +26,11 @@ type User struct {
 | 
				
			|||||||
	Active    *bool
 | 
						Active    *bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type mytime time.Time
 | 
					type (
 | 
				
			||||||
type myint int
 | 
						mytime time.Time
 | 
				
			||||||
type mybool = bool
 | 
						myint  int
 | 
				
			||||||
 | 
						mybool = bool
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type AdvancedDataTypeUser struct {
 | 
					type AdvancedDataTypeUser struct {
 | 
				
			||||||
	ID           sql.NullInt64
 | 
						ID           sql.NullInt64
 | 
				
			||||||
 | 
				
			|||||||
@ -86,9 +86,9 @@ func (ns NamingStrategy) IndexName(table, column string) string {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ns NamingStrategy) formatName(prefix, table, name string) string {
 | 
					func (ns NamingStrategy) formatName(prefix, table, name string) string {
 | 
				
			||||||
	formattedName := strings.Replace(strings.Join([]string{
 | 
						formattedName := strings.ReplaceAll(strings.Join([]string{
 | 
				
			||||||
		prefix, table, name,
 | 
							prefix, table, name,
 | 
				
			||||||
	}, "_"), ".", "_", -1)
 | 
						}, "_"), ".", "_")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if utf8.RuneCountInString(formattedName) > 64 {
 | 
						if utf8.RuneCountInString(formattedName) > 64 {
 | 
				
			||||||
		h := sha1.New()
 | 
							h := sha1.New()
 | 
				
			||||||
@ -168,7 +168,7 @@ func (ns NamingStrategy) toDBName(name string) string {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (ns NamingStrategy) toSchemaName(name string) string {
 | 
					func (ns NamingStrategy) toSchemaName(name string) string {
 | 
				
			||||||
	result := strings.Replace(strings.Title(strings.Replace(name, "_", " ", -1)), " ", "", -1)
 | 
						result := strings.ReplaceAll(strings.Title(strings.ReplaceAll(name, "_", " ")), " ", "")
 | 
				
			||||||
	for _, initialism := range commonInitialisms {
 | 
						for _, initialism := range commonInitialisms {
 | 
				
			||||||
		result = regexp.MustCompile(strings.Title(strings.ToLower(initialism))+"([A-Z]|$|_)").ReplaceAllString(result, initialism+"$1")
 | 
							result = regexp.MustCompile(strings.Title(strings.ToLower(initialism))+"([A-Z]|$|_)").ReplaceAllString(result, initialism+"$1")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
@ -6,7 +6,7 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestToDBName(t *testing.T) {
 | 
					func TestToDBName(t *testing.T) {
 | 
				
			||||||
	var maps = map[string]string{
 | 
						maps := map[string]string{
 | 
				
			||||||
		"":                          "",
 | 
							"":                          "",
 | 
				
			||||||
		"x":                         "x",
 | 
							"x":                         "x",
 | 
				
			||||||
		"X":                         "x",
 | 
							"X":                         "x",
 | 
				
			||||||
@ -56,7 +56,7 @@ func TestToDBName(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestNamingStrategy(t *testing.T) {
 | 
					func TestNamingStrategy(t *testing.T) {
 | 
				
			||||||
	var ns = NamingStrategy{
 | 
						ns := NamingStrategy{
 | 
				
			||||||
		TablePrefix:   "public.",
 | 
							TablePrefix:   "public.",
 | 
				
			||||||
		SingularTable: true,
 | 
							SingularTable: true,
 | 
				
			||||||
		NameReplacer:  strings.NewReplacer("CID", "Cid"),
 | 
							NameReplacer:  strings.NewReplacer("CID", "Cid"),
 | 
				
			||||||
@ -102,7 +102,7 @@ func (r CustomReplacer) Replace(name string) string {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestCustomReplacer(t *testing.T) {
 | 
					func TestCustomReplacer(t *testing.T) {
 | 
				
			||||||
	var ns = NamingStrategy{
 | 
						ns := NamingStrategy{
 | 
				
			||||||
		TablePrefix:   "public.",
 | 
							TablePrefix:   "public.",
 | 
				
			||||||
		SingularTable: true,
 | 
							SingularTable: true,
 | 
				
			||||||
		NameReplacer: CustomReplacer{
 | 
							NameReplacer: CustomReplacer{
 | 
				
			||||||
@ -146,7 +146,7 @@ func TestCustomReplacer(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestCustomReplacerWithNoLowerCase(t *testing.T) {
 | 
					func TestCustomReplacerWithNoLowerCase(t *testing.T) {
 | 
				
			||||||
	var ns = NamingStrategy{
 | 
						ns := NamingStrategy{
 | 
				
			||||||
		TablePrefix:   "public.",
 | 
							TablePrefix:   "public.",
 | 
				
			||||||
		SingularTable: true,
 | 
							SingularTable: true,
 | 
				
			||||||
		NameReplacer: CustomReplacer{
 | 
							NameReplacer: CustomReplacer{
 | 
				
			||||||
@ -190,7 +190,7 @@ func TestCustomReplacerWithNoLowerCase(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestFormatNameWithStringLongerThan64Characters(t *testing.T) {
 | 
					func TestFormatNameWithStringLongerThan64Characters(t *testing.T) {
 | 
				
			||||||
	var ns = NamingStrategy{}
 | 
						ns := NamingStrategy{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	formattedName := ns.formatName("prefix", "table", "thisIsAVeryVeryVeryVeryVeryVeryVeryVeryVeryLongString")
 | 
						formattedName := ns.formatName("prefix", "table", "thisIsAVeryVeryVeryVeryVeryVeryVeryVeryVeryLongString")
 | 
				
			||||||
	if formattedName != "prefixtablethisIsAVeryVeryVeryVeryVeryVeryVeryVeryVeryLo180f2c67" {
 | 
						if formattedName != "prefixtablethisIsAVeryVeryVeryVeryVeryVeryVeryVeryVeryLo180f2c67" {
 | 
				
			||||||
 | 
				
			|||||||
@ -6,6 +6,7 @@ import (
 | 
				
			|||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/jinzhu/inflection"
 | 
						"github.com/jinzhu/inflection"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"gorm.io/gorm/clause"
 | 
						"gorm.io/gorm/clause"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -186,9 +187,9 @@ func (schema *Schema) buildPolymorphicRelation(relation *Relationship, field *Fi
 | 
				
			|||||||
func (schema *Schema) buildMany2ManyRelation(relation *Relationship, field *Field, many2many string) {
 | 
					func (schema *Schema) buildMany2ManyRelation(relation *Relationship, field *Field, many2many string) {
 | 
				
			||||||
	relation.Type = Many2Many
 | 
						relation.Type = Many2Many
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						joinTableFields := make([]reflect.StructField, 0)
 | 
				
			||||||
	var (
 | 
						var (
 | 
				
			||||||
		err             error
 | 
							err             error
 | 
				
			||||||
		joinTableFields []reflect.StructField
 | 
					 | 
				
			||||||
		fieldsMap       = map[string]*Field{}
 | 
							fieldsMap       = map[string]*Field{}
 | 
				
			||||||
		ownFieldsMap    = map[string]bool{} // fix self join many2many
 | 
							ownFieldsMap    = map[string]bool{} // fix self join many2many
 | 
				
			||||||
		joinForeignKeys = toColumns(field.TagSettings["JOINFOREIGNKEY"])
 | 
							joinForeignKeys = toColumns(field.TagSettings["JOINFOREIGNKEY"])
 | 
				
			||||||
 | 
				
			|||||||
@ -105,7 +105,6 @@ func TestSelfReferentialBelongsTo(t *testing.T) {
 | 
				
			|||||||
		Name: "Creator", Type: schema.BelongsTo, Schema: "User", FieldSchema: "User",
 | 
							Name: "Creator", Type: schema.BelongsTo, Schema: "User", FieldSchema: "User",
 | 
				
			||||||
		References: []Reference{{"ID", "User", "CreatorID", "User", "", false}},
 | 
							References: []Reference{{"ID", "User", "CreatorID", "User", "", false}},
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestSelfReferentialBelongsToOverrideReferences(t *testing.T) {
 | 
					func TestSelfReferentialBelongsToOverrideReferences(t *testing.T) {
 | 
				
			||||||
@ -160,7 +159,6 @@ func TestHasOneOverrideReferences(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestHasOneOverrideReferences2(t *testing.T) {
 | 
					func TestHasOneOverrideReferences2(t *testing.T) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
	type Profile struct {
 | 
						type Profile struct {
 | 
				
			||||||
		gorm.Model
 | 
							gorm.Model
 | 
				
			||||||
		Name string
 | 
							Name string
 | 
				
			||||||
@ -518,7 +516,6 @@ func TestSameForeignKey(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestBelongsToSameForeignKey(t *testing.T) {
 | 
					func TestBelongsToSameForeignKey(t *testing.T) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
	type User struct {
 | 
						type User struct {
 | 
				
			||||||
		gorm.Model
 | 
							gorm.Model
 | 
				
			||||||
		Name string
 | 
							Name string
 | 
				
			||||||
 | 
				
			|||||||
@ -145,8 +145,7 @@ func TestParseSchemaWithAdvancedDataType(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type CustomizeTable struct {
 | 
					type CustomizeTable struct{}
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (CustomizeTable) TableName() string {
 | 
					func (CustomizeTable) TableName() string {
 | 
				
			||||||
	return "customize"
 | 
						return "customize"
 | 
				
			||||||
@ -165,7 +164,6 @@ func TestCustomizeTableName(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func TestNestedModel(t *testing.T) {
 | 
					func TestNestedModel(t *testing.T) {
 | 
				
			||||||
	versionUser, err := schema.Parse(&VersionUser{}, &sync.Map{}, schema.NamingStrategy{})
 | 
						versionUser, err := schema.Parse(&VersionUser{}, &sync.Map{}, schema.NamingStrategy{})
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatalf("failed to parse nested user, got error %v", err)
 | 
							t.Fatalf("failed to parse nested user, got error %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -204,7 +202,6 @@ func TestEmbeddedStruct(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cropSchema, err := schema.Parse(&Corp{}, &sync.Map{}, schema.NamingStrategy{})
 | 
						cropSchema, err := schema.Parse(&Corp{}, &sync.Map{}, schema.NamingStrategy{})
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatalf("failed to parse embedded struct with primary key, got error %v", err)
 | 
							t.Fatalf("failed to parse embedded struct with primary key, got error %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -273,7 +270,6 @@ func TestEmbeddedStructForCustomizedNamingStrategy(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cropSchema, err := schema.Parse(&Corp{}, &sync.Map{}, CustomizedNamingStrategy{schema.NamingStrategy{}})
 | 
						cropSchema, err := schema.Parse(&Corp{}, &sync.Map{}, CustomizedNamingStrategy{schema.NamingStrategy{}})
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatalf("failed to parse embedded struct with primary key, got error %v", err)
 | 
							t.Fatalf("failed to parse embedded struct with primary key, got error %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
@ -328,7 +328,7 @@ func (stmt *Statement) BuildCondition(query interface{}, args ...interface{}) []
 | 
				
			|||||||
				conds = append(conds, clause.Eq{Column: i, Value: j})
 | 
									conds = append(conds, clause.Eq{Column: i, Value: j})
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		case map[string]string:
 | 
							case map[string]string:
 | 
				
			||||||
			var keys = make([]string, 0, len(v))
 | 
								keys := make([]string, 0, len(v))
 | 
				
			||||||
			for i := range v {
 | 
								for i := range v {
 | 
				
			||||||
				keys = append(keys, i)
 | 
									keys = append(keys, i)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@ -338,7 +338,7 @@ func (stmt *Statement) BuildCondition(query interface{}, args ...interface{}) []
 | 
				
			|||||||
				conds = append(conds, clause.Eq{Column: key, Value: v[key]})
 | 
									conds = append(conds, clause.Eq{Column: key, Value: v[key]})
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		case map[string]interface{}:
 | 
							case map[string]interface{}:
 | 
				
			||||||
			var keys = make([]string, 0, len(v))
 | 
								keys := make([]string, 0, len(v))
 | 
				
			||||||
			for i := range v {
 | 
								for i := range v {
 | 
				
			||||||
				keys = append(keys, i)
 | 
									keys = append(keys, i)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
				
			|||||||
@ -7,7 +7,7 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestBelongsToAssociation(t *testing.T) {
 | 
					func TestBelongsToAssociation(t *testing.T) {
 | 
				
			||||||
	var user = *GetUser("belongs-to", Config{Company: true, Manager: true})
 | 
						user := *GetUser("belongs-to", Config{Company: true, Manager: true})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Create(&user).Error; err != nil {
 | 
						if err := DB.Create(&user).Error; err != nil {
 | 
				
			||||||
		t.Fatalf("errors happened when create: %v", err)
 | 
							t.Fatalf("errors happened when create: %v", err)
 | 
				
			||||||
@ -31,8 +31,8 @@ func TestBelongsToAssociation(t *testing.T) {
 | 
				
			|||||||
	AssertAssociationCount(t, user, "Manager", 1, "")
 | 
						AssertAssociationCount(t, user, "Manager", 1, "")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Append
 | 
						// Append
 | 
				
			||||||
	var company = Company{Name: "company-belongs-to-append"}
 | 
						company := Company{Name: "company-belongs-to-append"}
 | 
				
			||||||
	var manager = GetUser("manager-belongs-to-append", Config{})
 | 
						manager := GetUser("manager-belongs-to-append", Config{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Model(&user2).Association("Company").Append(&company); err != nil {
 | 
						if err := DB.Model(&user2).Association("Company").Append(&company); err != nil {
 | 
				
			||||||
		t.Fatalf("Error happened when append Company, got %v", err)
 | 
							t.Fatalf("Error happened when append Company, got %v", err)
 | 
				
			||||||
@ -60,8 +60,8 @@ func TestBelongsToAssociation(t *testing.T) {
 | 
				
			|||||||
	AssertAssociationCount(t, user2, "Manager", 1, "AfterAppend")
 | 
						AssertAssociationCount(t, user2, "Manager", 1, "AfterAppend")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Replace
 | 
						// Replace
 | 
				
			||||||
	var company2 = Company{Name: "company-belongs-to-replace"}
 | 
						company2 := Company{Name: "company-belongs-to-replace"}
 | 
				
			||||||
	var manager2 = GetUser("manager-belongs-to-replace", Config{})
 | 
						manager2 := GetUser("manager-belongs-to-replace", Config{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Model(&user2).Association("Company").Replace(&company2); err != nil {
 | 
						if err := DB.Model(&user2).Association("Company").Replace(&company2); err != nil {
 | 
				
			||||||
		t.Fatalf("Error happened when replace Company, got %v", err)
 | 
							t.Fatalf("Error happened when replace Company, got %v", err)
 | 
				
			||||||
@ -142,7 +142,7 @@ func TestBelongsToAssociation(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestBelongsToAssociationForSlice(t *testing.T) {
 | 
					func TestBelongsToAssociationForSlice(t *testing.T) {
 | 
				
			||||||
	var users = []User{
 | 
						users := []User{
 | 
				
			||||||
		*GetUser("slice-belongs-to-1", Config{Company: true, Manager: true}),
 | 
							*GetUser("slice-belongs-to-1", Config{Company: true, Manager: true}),
 | 
				
			||||||
		*GetUser("slice-belongs-to-2", Config{Company: true, Manager: false}),
 | 
							*GetUser("slice-belongs-to-2", Config{Company: true, Manager: false}),
 | 
				
			||||||
		*GetUser("slice-belongs-to-3", Config{Company: true, Manager: true}),
 | 
							*GetUser("slice-belongs-to-3", Config{Company: true, Manager: true}),
 | 
				
			||||||
 | 
				
			|||||||
@ -7,7 +7,7 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestHasManyAssociation(t *testing.T) {
 | 
					func TestHasManyAssociation(t *testing.T) {
 | 
				
			||||||
	var user = *GetUser("hasmany", Config{Pets: 2})
 | 
						user := *GetUser("hasmany", Config{Pets: 2})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Create(&user).Error; err != nil {
 | 
						if err := DB.Create(&user).Error; err != nil {
 | 
				
			||||||
		t.Fatalf("errors happened when create: %v", err)
 | 
							t.Fatalf("errors happened when create: %v", err)
 | 
				
			||||||
@ -42,7 +42,7 @@ func TestHasManyAssociation(t *testing.T) {
 | 
				
			|||||||
	AssertAssociationCount(t, user, "Pets", 2, "")
 | 
						AssertAssociationCount(t, user, "Pets", 2, "")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Append
 | 
						// Append
 | 
				
			||||||
	var pet = Pet{Name: "pet-has-many-append"}
 | 
						pet := Pet{Name: "pet-has-many-append"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Model(&user2).Association("Pets").Append(&pet); err != nil {
 | 
						if err := DB.Model(&user2).Association("Pets").Append(&pet); err != nil {
 | 
				
			||||||
		t.Fatalf("Error happened when append account, got %v", err)
 | 
							t.Fatalf("Error happened when append account, got %v", err)
 | 
				
			||||||
@ -57,14 +57,14 @@ func TestHasManyAssociation(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	AssertAssociationCount(t, user, "Pets", 3, "AfterAppend")
 | 
						AssertAssociationCount(t, user, "Pets", 3, "AfterAppend")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var pets2 = []Pet{{Name: "pet-has-many-append-1-1"}, {Name: "pet-has-many-append-1-1"}}
 | 
						pets2 := []Pet{{Name: "pet-has-many-append-1-1"}, {Name: "pet-has-many-append-1-1"}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Model(&user2).Association("Pets").Append(&pets2); err != nil {
 | 
						if err := DB.Model(&user2).Association("Pets").Append(&pets2); err != nil {
 | 
				
			||||||
		t.Fatalf("Error happened when append pet, got %v", err)
 | 
							t.Fatalf("Error happened when append pet, got %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, pet := range pets2 {
 | 
						for _, pet := range pets2 {
 | 
				
			||||||
		var pet = pet
 | 
							pet := pet
 | 
				
			||||||
		if pet.ID == 0 {
 | 
							if pet.ID == 0 {
 | 
				
			||||||
			t.Fatalf("Pet's ID should be created")
 | 
								t.Fatalf("Pet's ID should be created")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -77,7 +77,7 @@ func TestHasManyAssociation(t *testing.T) {
 | 
				
			|||||||
	AssertAssociationCount(t, user, "Pets", 5, "AfterAppendSlice")
 | 
						AssertAssociationCount(t, user, "Pets", 5, "AfterAppendSlice")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Replace
 | 
						// Replace
 | 
				
			||||||
	var pet2 = Pet{Name: "pet-has-many-replace"}
 | 
						pet2 := Pet{Name: "pet-has-many-replace"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Model(&user2).Association("Pets").Replace(&pet2); err != nil {
 | 
						if err := DB.Model(&user2).Association("Pets").Replace(&pet2); err != nil {
 | 
				
			||||||
		t.Fatalf("Error happened when append pet, got %v", err)
 | 
							t.Fatalf("Error happened when append pet, got %v", err)
 | 
				
			||||||
@ -119,7 +119,7 @@ func TestHasManyAssociation(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestSingleTableHasManyAssociation(t *testing.T) {
 | 
					func TestSingleTableHasManyAssociation(t *testing.T) {
 | 
				
			||||||
	var user = *GetUser("hasmany", Config{Team: 2})
 | 
						user := *GetUser("hasmany", Config{Team: 2})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Create(&user).Error; err != nil {
 | 
						if err := DB.Create(&user).Error; err != nil {
 | 
				
			||||||
		t.Fatalf("errors happened when create: %v", err)
 | 
							t.Fatalf("errors happened when create: %v", err)
 | 
				
			||||||
@ -137,7 +137,7 @@ func TestSingleTableHasManyAssociation(t *testing.T) {
 | 
				
			|||||||
	AssertAssociationCount(t, user, "Team", 2, "")
 | 
						AssertAssociationCount(t, user, "Team", 2, "")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Append
 | 
						// Append
 | 
				
			||||||
	var team = *GetUser("team", Config{})
 | 
						team := *GetUser("team", Config{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Model(&user2).Association("Team").Append(&team); err != nil {
 | 
						if err := DB.Model(&user2).Association("Team").Append(&team); err != nil {
 | 
				
			||||||
		t.Fatalf("Error happened when append account, got %v", err)
 | 
							t.Fatalf("Error happened when append account, got %v", err)
 | 
				
			||||||
@ -152,14 +152,14 @@ func TestSingleTableHasManyAssociation(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	AssertAssociationCount(t, user, "Team", 3, "AfterAppend")
 | 
						AssertAssociationCount(t, user, "Team", 3, "AfterAppend")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var teams = []User{*GetUser("team-append-1", Config{}), *GetUser("team-append-2", Config{})}
 | 
						teams := []User{*GetUser("team-append-1", Config{}), *GetUser("team-append-2", Config{})}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Model(&user2).Association("Team").Append(&teams); err != nil {
 | 
						if err := DB.Model(&user2).Association("Team").Append(&teams); err != nil {
 | 
				
			||||||
		t.Fatalf("Error happened when append team, got %v", err)
 | 
							t.Fatalf("Error happened when append team, got %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, team := range teams {
 | 
						for _, team := range teams {
 | 
				
			||||||
		var team = team
 | 
							team := team
 | 
				
			||||||
		if team.ID == 0 {
 | 
							if team.ID == 0 {
 | 
				
			||||||
			t.Fatalf("Team's ID should be created")
 | 
								t.Fatalf("Team's ID should be created")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -172,7 +172,7 @@ func TestSingleTableHasManyAssociation(t *testing.T) {
 | 
				
			|||||||
	AssertAssociationCount(t, user, "Team", 5, "AfterAppendSlice")
 | 
						AssertAssociationCount(t, user, "Team", 5, "AfterAppendSlice")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Replace
 | 
						// Replace
 | 
				
			||||||
	var team2 = *GetUser("team-replace", Config{})
 | 
						team2 := *GetUser("team-replace", Config{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Model(&user2).Association("Team").Replace(&team2); err != nil {
 | 
						if err := DB.Model(&user2).Association("Team").Replace(&team2); err != nil {
 | 
				
			||||||
		t.Fatalf("Error happened when append team, got %v", err)
 | 
							t.Fatalf("Error happened when append team, got %v", err)
 | 
				
			||||||
@ -214,7 +214,7 @@ func TestSingleTableHasManyAssociation(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestHasManyAssociationForSlice(t *testing.T) {
 | 
					func TestHasManyAssociationForSlice(t *testing.T) {
 | 
				
			||||||
	var users = []User{
 | 
						users := []User{
 | 
				
			||||||
		*GetUser("slice-hasmany-1", Config{Pets: 2}),
 | 
							*GetUser("slice-hasmany-1", Config{Pets: 2}),
 | 
				
			||||||
		*GetUser("slice-hasmany-2", Config{Pets: 0}),
 | 
							*GetUser("slice-hasmany-2", Config{Pets: 0}),
 | 
				
			||||||
		*GetUser("slice-hasmany-3", Config{Pets: 4}),
 | 
							*GetUser("slice-hasmany-3", Config{Pets: 4}),
 | 
				
			||||||
@ -268,7 +268,7 @@ func TestHasManyAssociationForSlice(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestSingleTableHasManyAssociationForSlice(t *testing.T) {
 | 
					func TestSingleTableHasManyAssociationForSlice(t *testing.T) {
 | 
				
			||||||
	var users = []User{
 | 
						users := []User{
 | 
				
			||||||
		*GetUser("slice-hasmany-1", Config{Team: 2}),
 | 
							*GetUser("slice-hasmany-1", Config{Team: 2}),
 | 
				
			||||||
		*GetUser("slice-hasmany-2", Config{Team: 0}),
 | 
							*GetUser("slice-hasmany-2", Config{Team: 0}),
 | 
				
			||||||
		*GetUser("slice-hasmany-3", Config{Team: 4}),
 | 
							*GetUser("slice-hasmany-3", Config{Team: 4}),
 | 
				
			||||||
@ -324,7 +324,7 @@ func TestSingleTableHasManyAssociationForSlice(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPolymorphicHasManyAssociation(t *testing.T) {
 | 
					func TestPolymorphicHasManyAssociation(t *testing.T) {
 | 
				
			||||||
	var user = *GetUser("hasmany", Config{Toys: 2})
 | 
						user := *GetUser("hasmany", Config{Toys: 2})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Create(&user).Error; err != nil {
 | 
						if err := DB.Create(&user).Error; err != nil {
 | 
				
			||||||
		t.Fatalf("errors happened when create: %v", err)
 | 
							t.Fatalf("errors happened when create: %v", err)
 | 
				
			||||||
@ -342,7 +342,7 @@ func TestPolymorphicHasManyAssociation(t *testing.T) {
 | 
				
			|||||||
	AssertAssociationCount(t, user, "Toys", 2, "")
 | 
						AssertAssociationCount(t, user, "Toys", 2, "")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Append
 | 
						// Append
 | 
				
			||||||
	var toy = Toy{Name: "toy-has-many-append"}
 | 
						toy := Toy{Name: "toy-has-many-append"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Model(&user2).Association("Toys").Append(&toy); err != nil {
 | 
						if err := DB.Model(&user2).Association("Toys").Append(&toy); err != nil {
 | 
				
			||||||
		t.Fatalf("Error happened when append account, got %v", err)
 | 
							t.Fatalf("Error happened when append account, got %v", err)
 | 
				
			||||||
@ -357,14 +357,14 @@ func TestPolymorphicHasManyAssociation(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	AssertAssociationCount(t, user, "Toys", 3, "AfterAppend")
 | 
						AssertAssociationCount(t, user, "Toys", 3, "AfterAppend")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var toys = []Toy{{Name: "toy-has-many-append-1-1"}, {Name: "toy-has-many-append-1-1"}}
 | 
						toys := []Toy{{Name: "toy-has-many-append-1-1"}, {Name: "toy-has-many-append-1-1"}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Model(&user2).Association("Toys").Append(&toys); err != nil {
 | 
						if err := DB.Model(&user2).Association("Toys").Append(&toys); err != nil {
 | 
				
			||||||
		t.Fatalf("Error happened when append toy, got %v", err)
 | 
							t.Fatalf("Error happened when append toy, got %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, toy := range toys {
 | 
						for _, toy := range toys {
 | 
				
			||||||
		var toy = toy
 | 
							toy := toy
 | 
				
			||||||
		if toy.ID == 0 {
 | 
							if toy.ID == 0 {
 | 
				
			||||||
			t.Fatalf("Toy's ID should be created")
 | 
								t.Fatalf("Toy's ID should be created")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -377,7 +377,7 @@ func TestPolymorphicHasManyAssociation(t *testing.T) {
 | 
				
			|||||||
	AssertAssociationCount(t, user, "Toys", 5, "AfterAppendSlice")
 | 
						AssertAssociationCount(t, user, "Toys", 5, "AfterAppendSlice")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Replace
 | 
						// Replace
 | 
				
			||||||
	var toy2 = Toy{Name: "toy-has-many-replace"}
 | 
						toy2 := Toy{Name: "toy-has-many-replace"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Model(&user2).Association("Toys").Replace(&toy2); err != nil {
 | 
						if err := DB.Model(&user2).Association("Toys").Replace(&toy2); err != nil {
 | 
				
			||||||
		t.Fatalf("Error happened when append toy, got %v", err)
 | 
							t.Fatalf("Error happened when append toy, got %v", err)
 | 
				
			||||||
@ -419,7 +419,7 @@ func TestPolymorphicHasManyAssociation(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPolymorphicHasManyAssociationForSlice(t *testing.T) {
 | 
					func TestPolymorphicHasManyAssociationForSlice(t *testing.T) {
 | 
				
			||||||
	var users = []User{
 | 
						users := []User{
 | 
				
			||||||
		*GetUser("slice-hasmany-1", Config{Toys: 2}),
 | 
							*GetUser("slice-hasmany-1", Config{Toys: 2}),
 | 
				
			||||||
		*GetUser("slice-hasmany-2", Config{Toys: 0}),
 | 
							*GetUser("slice-hasmany-2", Config{Toys: 0}),
 | 
				
			||||||
		*GetUser("slice-hasmany-3", Config{Toys: 4}),
 | 
							*GetUser("slice-hasmany-3", Config{Toys: 4}),
 | 
				
			||||||
 | 
				
			|||||||
@ -7,7 +7,7 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestHasOneAssociation(t *testing.T) {
 | 
					func TestHasOneAssociation(t *testing.T) {
 | 
				
			||||||
	var user = *GetUser("hasone", Config{Account: true})
 | 
						user := *GetUser("hasone", Config{Account: true})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Create(&user).Error; err != nil {
 | 
						if err := DB.Create(&user).Error; err != nil {
 | 
				
			||||||
		t.Fatalf("errors happened when create: %v", err)
 | 
							t.Fatalf("errors happened when create: %v", err)
 | 
				
			||||||
@ -25,7 +25,7 @@ func TestHasOneAssociation(t *testing.T) {
 | 
				
			|||||||
	AssertAssociationCount(t, user, "Account", 1, "")
 | 
						AssertAssociationCount(t, user, "Account", 1, "")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Append
 | 
						// Append
 | 
				
			||||||
	var account = Account{Number: "account-has-one-append"}
 | 
						account := Account{Number: "account-has-one-append"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Model(&user2).Association("Account").Append(&account); err != nil {
 | 
						if err := DB.Model(&user2).Association("Account").Append(&account); err != nil {
 | 
				
			||||||
		t.Fatalf("Error happened when append account, got %v", err)
 | 
							t.Fatalf("Error happened when append account, got %v", err)
 | 
				
			||||||
@ -41,7 +41,7 @@ func TestHasOneAssociation(t *testing.T) {
 | 
				
			|||||||
	AssertAssociationCount(t, user, "Account", 1, "AfterAppend")
 | 
						AssertAssociationCount(t, user, "Account", 1, "AfterAppend")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Replace
 | 
						// Replace
 | 
				
			||||||
	var account2 = Account{Number: "account-has-one-replace"}
 | 
						account2 := Account{Number: "account-has-one-replace"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Model(&user2).Association("Account").Replace(&account2); err != nil {
 | 
						if err := DB.Model(&user2).Association("Account").Replace(&account2); err != nil {
 | 
				
			||||||
		t.Fatalf("Error happened when append Account, got %v", err)
 | 
							t.Fatalf("Error happened when append Account, got %v", err)
 | 
				
			||||||
@ -84,7 +84,7 @@ func TestHasOneAssociation(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestHasOneAssociationWithSelect(t *testing.T) {
 | 
					func TestHasOneAssociationWithSelect(t *testing.T) {
 | 
				
			||||||
	var user = *GetUser("hasone", Config{Account: true})
 | 
						user := *GetUser("hasone", Config{Account: true})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	DB.Omit("Account.Number").Create(&user)
 | 
						DB.Omit("Account.Number").Create(&user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -98,7 +98,7 @@ func TestHasOneAssociationWithSelect(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestHasOneAssociationForSlice(t *testing.T) {
 | 
					func TestHasOneAssociationForSlice(t *testing.T) {
 | 
				
			||||||
	var users = []User{
 | 
						users := []User{
 | 
				
			||||||
		*GetUser("slice-hasone-1", Config{Account: true}),
 | 
							*GetUser("slice-hasone-1", Config{Account: true}),
 | 
				
			||||||
		*GetUser("slice-hasone-2", Config{Account: false}),
 | 
							*GetUser("slice-hasone-2", Config{Account: false}),
 | 
				
			||||||
		*GetUser("slice-hasone-3", Config{Account: true}),
 | 
							*GetUser("slice-hasone-3", Config{Account: true}),
 | 
				
			||||||
@ -139,7 +139,7 @@ func TestHasOneAssociationForSlice(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPolymorphicHasOneAssociation(t *testing.T) {
 | 
					func TestPolymorphicHasOneAssociation(t *testing.T) {
 | 
				
			||||||
	var pet = Pet{Name: "hasone", Toy: Toy{Name: "toy-has-one"}}
 | 
						pet := Pet{Name: "hasone", Toy: Toy{Name: "toy-has-one"}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Create(&pet).Error; err != nil {
 | 
						if err := DB.Create(&pet).Error; err != nil {
 | 
				
			||||||
		t.Fatalf("errors happened when create: %v", err)
 | 
							t.Fatalf("errors happened when create: %v", err)
 | 
				
			||||||
@ -157,7 +157,7 @@ func TestPolymorphicHasOneAssociation(t *testing.T) {
 | 
				
			|||||||
	AssertAssociationCount(t, pet, "Toy", 1, "")
 | 
						AssertAssociationCount(t, pet, "Toy", 1, "")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Append
 | 
						// Append
 | 
				
			||||||
	var toy = Toy{Name: "toy-has-one-append"}
 | 
						toy := Toy{Name: "toy-has-one-append"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Model(&pet2).Association("Toy").Append(&toy); err != nil {
 | 
						if err := DB.Model(&pet2).Association("Toy").Append(&toy); err != nil {
 | 
				
			||||||
		t.Fatalf("Error happened when append toy, got %v", err)
 | 
							t.Fatalf("Error happened when append toy, got %v", err)
 | 
				
			||||||
@ -173,7 +173,7 @@ func TestPolymorphicHasOneAssociation(t *testing.T) {
 | 
				
			|||||||
	AssertAssociationCount(t, pet, "Toy", 1, "AfterAppend")
 | 
						AssertAssociationCount(t, pet, "Toy", 1, "AfterAppend")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Replace
 | 
						// Replace
 | 
				
			||||||
	var toy2 = Toy{Name: "toy-has-one-replace"}
 | 
						toy2 := Toy{Name: "toy-has-one-replace"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Model(&pet2).Association("Toy").Replace(&toy2); err != nil {
 | 
						if err := DB.Model(&pet2).Association("Toy").Replace(&toy2); err != nil {
 | 
				
			||||||
		t.Fatalf("Error happened when append Toy, got %v", err)
 | 
							t.Fatalf("Error happened when append Toy, got %v", err)
 | 
				
			||||||
@ -216,7 +216,7 @@ func TestPolymorphicHasOneAssociation(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPolymorphicHasOneAssociationForSlice(t *testing.T) {
 | 
					func TestPolymorphicHasOneAssociationForSlice(t *testing.T) {
 | 
				
			||||||
	var pets = []Pet{
 | 
						pets := []Pet{
 | 
				
			||||||
		{Name: "hasone-1", Toy: Toy{Name: "toy-has-one"}},
 | 
							{Name: "hasone-1", Toy: Toy{Name: "toy-has-one"}},
 | 
				
			||||||
		{Name: "hasone-2", Toy: Toy{}},
 | 
							{Name: "hasone-2", Toy: Toy{}},
 | 
				
			||||||
		{Name: "hasone-3", Toy: Toy{Name: "toy-has-one"}},
 | 
							{Name: "hasone-3", Toy: Toy{Name: "toy-has-one"}},
 | 
				
			||||||
 | 
				
			|||||||
@ -7,7 +7,7 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestMany2ManyAssociation(t *testing.T) {
 | 
					func TestMany2ManyAssociation(t *testing.T) {
 | 
				
			||||||
	var user = *GetUser("many2many", Config{Languages: 2})
 | 
						user := *GetUser("many2many", Config{Languages: 2})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Create(&user).Error; err != nil {
 | 
						if err := DB.Create(&user).Error; err != nil {
 | 
				
			||||||
		t.Fatalf("errors happened when create: %v", err)
 | 
							t.Fatalf("errors happened when create: %v", err)
 | 
				
			||||||
@ -26,7 +26,7 @@ func TestMany2ManyAssociation(t *testing.T) {
 | 
				
			|||||||
	AssertAssociationCount(t, user, "Languages", 2, "")
 | 
						AssertAssociationCount(t, user, "Languages", 2, "")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Append
 | 
						// Append
 | 
				
			||||||
	var language = Language{Code: "language-many2many-append", Name: "language-many2many-append"}
 | 
						language := Language{Code: "language-many2many-append", Name: "language-many2many-append"}
 | 
				
			||||||
	DB.Create(&language)
 | 
						DB.Create(&language)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Model(&user2).Association("Languages").Append(&language); err != nil {
 | 
						if err := DB.Model(&user2).Association("Languages").Append(&language); err != nil {
 | 
				
			||||||
@ -38,7 +38,7 @@ func TestMany2ManyAssociation(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	AssertAssociationCount(t, user, "Languages", 3, "AfterAppend")
 | 
						AssertAssociationCount(t, user, "Languages", 3, "AfterAppend")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var languages = []Language{
 | 
						languages := []Language{
 | 
				
			||||||
		{Code: "language-many2many-append-1-1", Name: "language-many2many-append-1-1"},
 | 
							{Code: "language-many2many-append-1-1", Name: "language-many2many-append-1-1"},
 | 
				
			||||||
		{Code: "language-many2many-append-2-1", Name: "language-many2many-append-2-1"},
 | 
							{Code: "language-many2many-append-2-1", Name: "language-many2many-append-2-1"},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -55,7 +55,7 @@ func TestMany2ManyAssociation(t *testing.T) {
 | 
				
			|||||||
	AssertAssociationCount(t, user, "Languages", 5, "AfterAppendSlice")
 | 
						AssertAssociationCount(t, user, "Languages", 5, "AfterAppendSlice")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Replace
 | 
						// Replace
 | 
				
			||||||
	var language2 = Language{Code: "language-many2many-replace", Name: "language-many2many-replace"}
 | 
						language2 := Language{Code: "language-many2many-replace", Name: "language-many2many-replace"}
 | 
				
			||||||
	DB.Create(&language2)
 | 
						DB.Create(&language2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Model(&user2).Association("Languages").Replace(&language2); err != nil {
 | 
						if err := DB.Model(&user2).Association("Languages").Replace(&language2); err != nil {
 | 
				
			||||||
@ -94,7 +94,7 @@ func TestMany2ManyAssociation(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestMany2ManyOmitAssociations(t *testing.T) {
 | 
					func TestMany2ManyOmitAssociations(t *testing.T) {
 | 
				
			||||||
	var user = *GetUser("many2many_omit_associations", Config{Languages: 2})
 | 
						user := *GetUser("many2many_omit_associations", Config{Languages: 2})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Omit("Languages.*").Create(&user).Error; err == nil {
 | 
						if err := DB.Omit("Languages.*").Create(&user).Error; err == nil {
 | 
				
			||||||
		t.Fatalf("should raise error when create users without languages reference")
 | 
							t.Fatalf("should raise error when create users without languages reference")
 | 
				
			||||||
@ -114,14 +114,14 @@ func TestMany2ManyOmitAssociations(t *testing.T) {
 | 
				
			|||||||
		t.Errorf("languages count should be %v, but got %v", 2, len(languages))
 | 
							t.Errorf("languages count should be %v, but got %v", 2, len(languages))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var newLang = Language{Code: "omitmany2many", Name: "omitmany2many"}
 | 
						newLang := Language{Code: "omitmany2many", Name: "omitmany2many"}
 | 
				
			||||||
	if err := DB.Model(&user).Omit("Languages.*").Association("Languages").Replace(&newLang); err == nil {
 | 
						if err := DB.Model(&user).Omit("Languages.*").Association("Languages").Replace(&newLang); err == nil {
 | 
				
			||||||
		t.Errorf("should failed to insert languages due to constraint failed, error: %v", err)
 | 
							t.Errorf("should failed to insert languages due to constraint failed, error: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestMany2ManyAssociationForSlice(t *testing.T) {
 | 
					func TestMany2ManyAssociationForSlice(t *testing.T) {
 | 
				
			||||||
	var users = []User{
 | 
						users := []User{
 | 
				
			||||||
		*GetUser("slice-many2many-1", Config{Languages: 2}),
 | 
							*GetUser("slice-many2many-1", Config{Languages: 2}),
 | 
				
			||||||
		*GetUser("slice-many2many-2", Config{Languages: 0}),
 | 
							*GetUser("slice-many2many-2", Config{Languages: 0}),
 | 
				
			||||||
		*GetUser("slice-many2many-3", Config{Languages: 4}),
 | 
							*GetUser("slice-many2many-3", Config{Languages: 4}),
 | 
				
			||||||
@ -139,11 +139,11 @@ func TestMany2ManyAssociationForSlice(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Append
 | 
						// Append
 | 
				
			||||||
	var languages1 = []Language{
 | 
						languages1 := []Language{
 | 
				
			||||||
		{Code: "language-many2many-append-1", Name: "language-many2many-append-1"},
 | 
							{Code: "language-many2many-append-1", Name: "language-many2many-append-1"},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	var languages2 = []Language{}
 | 
						languages2 := []Language{}
 | 
				
			||||||
	var languages3 = []Language{
 | 
						languages3 := []Language{
 | 
				
			||||||
		{Code: "language-many2many-append-3-1", Name: "language-many2many-append-3-1"},
 | 
							{Code: "language-many2many-append-3-1", Name: "language-many2many-append-3-1"},
 | 
				
			||||||
		{Code: "language-many2many-append-3-2", Name: "language-many2many-append-3-2"},
 | 
							{Code: "language-many2many-append-3-2", Name: "language-many2many-append-3-2"},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -191,7 +191,7 @@ func TestMany2ManyAssociationForSlice(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestSingleTableMany2ManyAssociation(t *testing.T) {
 | 
					func TestSingleTableMany2ManyAssociation(t *testing.T) {
 | 
				
			||||||
	var user = *GetUser("many2many", Config{Friends: 2})
 | 
						user := *GetUser("many2many", Config{Friends: 2})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Create(&user).Error; err != nil {
 | 
						if err := DB.Create(&user).Error; err != nil {
 | 
				
			||||||
		t.Fatalf("errors happened when create: %v", err)
 | 
							t.Fatalf("errors happened when create: %v", err)
 | 
				
			||||||
@ -210,7 +210,7 @@ func TestSingleTableMany2ManyAssociation(t *testing.T) {
 | 
				
			|||||||
	AssertAssociationCount(t, user, "Friends", 2, "")
 | 
						AssertAssociationCount(t, user, "Friends", 2, "")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Append
 | 
						// Append
 | 
				
			||||||
	var friend = *GetUser("friend", Config{})
 | 
						friend := *GetUser("friend", Config{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Model(&user2).Association("Friends").Append(&friend); err != nil {
 | 
						if err := DB.Model(&user2).Association("Friends").Append(&friend); err != nil {
 | 
				
			||||||
		t.Fatalf("Error happened when append account, got %v", err)
 | 
							t.Fatalf("Error happened when append account, got %v", err)
 | 
				
			||||||
@ -221,7 +221,7 @@ func TestSingleTableMany2ManyAssociation(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	AssertAssociationCount(t, user, "Friends", 3, "AfterAppend")
 | 
						AssertAssociationCount(t, user, "Friends", 3, "AfterAppend")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var friends = []*User{GetUser("friend-append-1", Config{}), GetUser("friend-append-2", Config{})}
 | 
						friends := []*User{GetUser("friend-append-1", Config{}), GetUser("friend-append-2", Config{})}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Model(&user2).Association("Friends").Append(&friends); err != nil {
 | 
						if err := DB.Model(&user2).Association("Friends").Append(&friends); err != nil {
 | 
				
			||||||
		t.Fatalf("Error happened when append friend, got %v", err)
 | 
							t.Fatalf("Error happened when append friend, got %v", err)
 | 
				
			||||||
@ -234,7 +234,7 @@ func TestSingleTableMany2ManyAssociation(t *testing.T) {
 | 
				
			|||||||
	AssertAssociationCount(t, user, "Friends", 5, "AfterAppendSlice")
 | 
						AssertAssociationCount(t, user, "Friends", 5, "AfterAppendSlice")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Replace
 | 
						// Replace
 | 
				
			||||||
	var friend2 = *GetUser("friend-replace-2", Config{})
 | 
						friend2 := *GetUser("friend-replace-2", Config{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Model(&user2).Association("Friends").Replace(&friend2); err != nil {
 | 
						if err := DB.Model(&user2).Association("Friends").Replace(&friend2); err != nil {
 | 
				
			||||||
		t.Fatalf("Error happened when append friend, got %v", err)
 | 
							t.Fatalf("Error happened when append friend, got %v", err)
 | 
				
			||||||
@ -272,7 +272,7 @@ func TestSingleTableMany2ManyAssociation(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestSingleTableMany2ManyAssociationForSlice(t *testing.T) {
 | 
					func TestSingleTableMany2ManyAssociationForSlice(t *testing.T) {
 | 
				
			||||||
	var users = []User{
 | 
						users := []User{
 | 
				
			||||||
		*GetUser("slice-many2many-1", Config{Team: 2}),
 | 
							*GetUser("slice-many2many-1", Config{Team: 2}),
 | 
				
			||||||
		*GetUser("slice-many2many-2", Config{Team: 0}),
 | 
							*GetUser("slice-many2many-2", Config{Team: 0}),
 | 
				
			||||||
		*GetUser("slice-many2many-3", Config{Team: 4}),
 | 
							*GetUser("slice-many2many-3", Config{Team: 4}),
 | 
				
			||||||
@ -290,17 +290,17 @@ func TestSingleTableMany2ManyAssociationForSlice(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Append
 | 
						// Append
 | 
				
			||||||
	var teams1 = []User{*GetUser("friend-append-1", Config{})}
 | 
						teams1 := []User{*GetUser("friend-append-1", Config{})}
 | 
				
			||||||
	var teams2 = []User{}
 | 
						teams2 := []User{}
 | 
				
			||||||
	var teams3 = []*User{GetUser("friend-append-3-1", Config{}), GetUser("friend-append-3-2", Config{})}
 | 
						teams3 := []*User{GetUser("friend-append-3-1", Config{}), GetUser("friend-append-3-2", Config{})}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	DB.Model(&users).Association("Team").Append(&teams1, &teams2, &teams3)
 | 
						DB.Model(&users).Association("Team").Append(&teams1, &teams2, &teams3)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	AssertAssociationCount(t, users, "Team", 9, "After Append")
 | 
						AssertAssociationCount(t, users, "Team", 9, "After Append")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var teams2_1 = []User{*GetUser("friend-replace-1", Config{}), *GetUser("friend-replace-2", Config{})}
 | 
						teams2_1 := []User{*GetUser("friend-replace-1", Config{}), *GetUser("friend-replace-2", Config{})}
 | 
				
			||||||
	var teams2_2 = []User{*GetUser("friend-replace-2-1", Config{}), *GetUser("friend-replace-2-2", Config{})}
 | 
						teams2_2 := []User{*GetUser("friend-replace-2-1", Config{}), *GetUser("friend-replace-2-2", Config{})}
 | 
				
			||||||
	var teams2_3 = GetUser("friend-replace-3-1", Config{})
 | 
						teams2_3 := GetUser("friend-replace-3-1", Config{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Replace
 | 
						// Replace
 | 
				
			||||||
	DB.Model(&users).Association("Team").Replace(&teams2_1, &teams2_2, teams2_3)
 | 
						DB.Model(&users).Association("Team").Replace(&teams2_1, &teams2_2, teams2_3)
 | 
				
			||||||
 | 
				
			|||||||
@ -27,7 +27,7 @@ func AssertAssociationCount(t *testing.T, data interface{}, name string, result
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestInvalidAssociation(t *testing.T) {
 | 
					func TestInvalidAssociation(t *testing.T) {
 | 
				
			||||||
	var user = *GetUser("invalid", Config{Company: true, Manager: true})
 | 
						user := *GetUser("invalid", Config{Company: true, Manager: true})
 | 
				
			||||||
	if err := DB.Model(&user).Association("Invalid").Find(&user.Company).Error; err == nil {
 | 
						if err := DB.Model(&user).Association("Invalid").Find(&user.Company).Error; err == nil {
 | 
				
			||||||
		t.Fatalf("should return errors for invalid association, but got nil")
 | 
							t.Fatalf("should return errors for invalid association, but got nil")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -189,7 +189,6 @@ func TestFullSaveAssociations(t *testing.T) {
 | 
				
			|||||||
	err := DB.
 | 
						err := DB.
 | 
				
			||||||
		Session(&gorm.Session{FullSaveAssociations: true}).
 | 
							Session(&gorm.Session{FullSaveAssociations: true}).
 | 
				
			||||||
		Create(coupon).Error
 | 
							Create(coupon).Error
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Errorf("Failed, got error: %v", err)
 | 
							t.Errorf("Failed, got error: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
@ -7,7 +7,7 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func BenchmarkCreate(b *testing.B) {
 | 
					func BenchmarkCreate(b *testing.B) {
 | 
				
			||||||
	var user = *GetUser("bench", Config{})
 | 
						user := *GetUser("bench", Config{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for x := 0; x < b.N; x++ {
 | 
						for x := 0; x < b.N; x++ {
 | 
				
			||||||
		user.ID = 0
 | 
							user.ID = 0
 | 
				
			||||||
@ -16,7 +16,7 @@ func BenchmarkCreate(b *testing.B) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func BenchmarkFind(b *testing.B) {
 | 
					func BenchmarkFind(b *testing.B) {
 | 
				
			||||||
	var user = *GetUser("find", Config{})
 | 
						user := *GetUser("find", Config{})
 | 
				
			||||||
	DB.Create(&user)
 | 
						DB.Create(&user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for x := 0; x < b.N; x++ {
 | 
						for x := 0; x < b.N; x++ {
 | 
				
			||||||
@ -25,7 +25,7 @@ func BenchmarkFind(b *testing.B) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func BenchmarkUpdate(b *testing.B) {
 | 
					func BenchmarkUpdate(b *testing.B) {
 | 
				
			||||||
	var user = *GetUser("find", Config{})
 | 
						user := *GetUser("find", Config{})
 | 
				
			||||||
	DB.Create(&user)
 | 
						DB.Create(&user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for x := 0; x < b.N; x++ {
 | 
						for x := 0; x < b.N; x++ {
 | 
				
			||||||
@ -34,7 +34,7 @@ func BenchmarkUpdate(b *testing.B) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func BenchmarkDelete(b *testing.B) {
 | 
					func BenchmarkDelete(b *testing.B) {
 | 
				
			||||||
	var user = *GetUser("find", Config{})
 | 
						user := *GetUser("find", Config{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for x := 0; x < b.N; x++ {
 | 
						for x := 0; x < b.N; x++ {
 | 
				
			||||||
		user.ID = 0
 | 
							user.ID = 0
 | 
				
			||||||
 | 
				
			|||||||
@ -87,7 +87,7 @@ func TestCount(t *testing.T) {
 | 
				
			|||||||
		t.Fatalf(fmt.Sprintf("Count should work, but got err %v", err))
 | 
							t.Fatalf(fmt.Sprintf("Count should work, but got err %v", err))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	expects := []User{User{Name: "main"}, {Name: "other"}, {Name: "other"}}
 | 
						expects := []User{{Name: "main"}, {Name: "other"}, {Name: "other"}}
 | 
				
			||||||
	sort.SliceStable(users, func(i, j int) bool {
 | 
						sort.SliceStable(users, func(i, j int) bool {
 | 
				
			||||||
		return strings.Compare(users[i].Name, users[j].Name) < 0
 | 
							return strings.Compare(users[i].Name, users[j].Name) < 0
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
@ -101,7 +101,7 @@ func TestCount(t *testing.T) {
 | 
				
			|||||||
		t.Fatalf(fmt.Sprintf("Count should work, but got err %v", err))
 | 
							t.Fatalf(fmt.Sprintf("Count should work, but got err %v", err))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	expects = []User{User{Name: "main", Age: 18}, {Name: "other", Age: 18}, {Name: "other", Age: 18}}
 | 
						expects = []User{{Name: "main", Age: 18}, {Name: "other", Age: 18}, {Name: "other", Age: 18}}
 | 
				
			||||||
	sort.SliceStable(users, func(i, j int) bool {
 | 
						sort.SliceStable(users, func(i, j int) bool {
 | 
				
			||||||
		return strings.Compare(users[i].Name, users[j].Name) < 0
 | 
							return strings.Compare(users[i].Name, users[j].Name) < 0
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
@ -115,7 +115,7 @@ func TestCount(t *testing.T) {
 | 
				
			|||||||
		t.Fatalf("Count should work, but got err %v", err)
 | 
							t.Fatalf("Count should work, but got err %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	expects = []User{User{Name: "count-1", Age: 1}, {Name: "count-2", Age: 1}, {Name: "count-3", Age: 1}}
 | 
						expects = []User{{Name: "count-1", Age: 1}, {Name: "count-2", Age: 1}, {Name: "count-3", Age: 1}}
 | 
				
			||||||
	sort.SliceStable(users, func(i, j int) bool {
 | 
						sort.SliceStable(users, func(i, j int) bool {
 | 
				
			||||||
		return strings.Compare(users[i].Name, users[j].Name) < 0
 | 
							return strings.Compare(users[i].Name, users[j].Name) < 0
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
@ -144,5 +144,4 @@ func TestCount(t *testing.T) {
 | 
				
			|||||||
	if err := DB.Model(&User{}).Where("name = ?", "count-4").Group("name").Count(&count11).Error; err != nil || count11 != 1 {
 | 
						if err := DB.Model(&User{}).Where("name = ?", "count-4").Group("name").Count(&count11).Error; err != nil || count11 != 1 {
 | 
				
			||||||
		t.Fatalf("Count should be 3, but got count: %v err %v", count11, err)
 | 
							t.Fatalf("Count should be 3, but got count: %v err %v", count11, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -7,13 +7,14 @@ import (
 | 
				
			|||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/jinzhu/now"
 | 
						"github.com/jinzhu/now"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"gorm.io/gorm"
 | 
						"gorm.io/gorm"
 | 
				
			||||||
	"gorm.io/gorm/clause"
 | 
						"gorm.io/gorm/clause"
 | 
				
			||||||
	. "gorm.io/gorm/utils/tests"
 | 
						. "gorm.io/gorm/utils/tests"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestCreate(t *testing.T) {
 | 
					func TestCreate(t *testing.T) {
 | 
				
			||||||
	var user = *GetUser("create", Config{})
 | 
						user := *GetUser("create", Config{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if results := DB.Create(&user); results.Error != nil {
 | 
						if results := DB.Create(&user); results.Error != nil {
 | 
				
			||||||
		t.Fatalf("errors happened when create: %v", results.Error)
 | 
							t.Fatalf("errors happened when create: %v", results.Error)
 | 
				
			||||||
@ -139,7 +140,7 @@ func TestCreateFromMap(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestCreateWithAssociations(t *testing.T) {
 | 
					func TestCreateWithAssociations(t *testing.T) {
 | 
				
			||||||
	var user = *GetUser("create_with_associations", Config{
 | 
						user := *GetUser("create_with_associations", Config{
 | 
				
			||||||
		Account:   true,
 | 
							Account:   true,
 | 
				
			||||||
		Pets:      2,
 | 
							Pets:      2,
 | 
				
			||||||
		Toys:      3,
 | 
							Toys:      3,
 | 
				
			||||||
@ -223,7 +224,7 @@ func TestBulkCreatePtrDataWithAssociations(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func TestPolymorphicHasOne(t *testing.T) {
 | 
					func TestPolymorphicHasOne(t *testing.T) {
 | 
				
			||||||
	t.Run("Struct", func(t *testing.T) {
 | 
						t.Run("Struct", func(t *testing.T) {
 | 
				
			||||||
		var pet = Pet{
 | 
							pet := Pet{
 | 
				
			||||||
			Name: "PolymorphicHasOne",
 | 
								Name: "PolymorphicHasOne",
 | 
				
			||||||
			Toy:  Toy{Name: "Toy-PolymorphicHasOne"},
 | 
								Toy:  Toy{Name: "Toy-PolymorphicHasOne"},
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -240,7 +241,7 @@ func TestPolymorphicHasOne(t *testing.T) {
 | 
				
			|||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t.Run("Slice", func(t *testing.T) {
 | 
						t.Run("Slice", func(t *testing.T) {
 | 
				
			||||||
		var pets = []Pet{{
 | 
							pets := []Pet{{
 | 
				
			||||||
			Name: "PolymorphicHasOne-Slice-1",
 | 
								Name: "PolymorphicHasOne-Slice-1",
 | 
				
			||||||
			Toy:  Toy{Name: "Toy-PolymorphicHasOne-Slice-1"},
 | 
								Toy:  Toy{Name: "Toy-PolymorphicHasOne-Slice-1"},
 | 
				
			||||||
		}, {
 | 
							}, {
 | 
				
			||||||
@ -269,7 +270,7 @@ func TestPolymorphicHasOne(t *testing.T) {
 | 
				
			|||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t.Run("SliceOfPtr", func(t *testing.T) {
 | 
						t.Run("SliceOfPtr", func(t *testing.T) {
 | 
				
			||||||
		var pets = []*Pet{{
 | 
							pets := []*Pet{{
 | 
				
			||||||
			Name: "PolymorphicHasOne-Slice-1",
 | 
								Name: "PolymorphicHasOne-Slice-1",
 | 
				
			||||||
			Toy:  Toy{Name: "Toy-PolymorphicHasOne-Slice-1"},
 | 
								Toy:  Toy{Name: "Toy-PolymorphicHasOne-Slice-1"},
 | 
				
			||||||
		}, {
 | 
							}, {
 | 
				
			||||||
@ -290,7 +291,7 @@ func TestPolymorphicHasOne(t *testing.T) {
 | 
				
			|||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t.Run("Array", func(t *testing.T) {
 | 
						t.Run("Array", func(t *testing.T) {
 | 
				
			||||||
		var pets = [...]Pet{{
 | 
							pets := [...]Pet{{
 | 
				
			||||||
			Name: "PolymorphicHasOne-Array-1",
 | 
								Name: "PolymorphicHasOne-Array-1",
 | 
				
			||||||
			Toy:  Toy{Name: "Toy-PolymorphicHasOne-Array-1"},
 | 
								Toy:  Toy{Name: "Toy-PolymorphicHasOne-Array-1"},
 | 
				
			||||||
		}, {
 | 
							}, {
 | 
				
			||||||
@ -311,7 +312,7 @@ func TestPolymorphicHasOne(t *testing.T) {
 | 
				
			|||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t.Run("ArrayPtr", func(t *testing.T) {
 | 
						t.Run("ArrayPtr", func(t *testing.T) {
 | 
				
			||||||
		var pets = [...]*Pet{{
 | 
							pets := [...]*Pet{{
 | 
				
			||||||
			Name: "PolymorphicHasOne-Array-1",
 | 
								Name: "PolymorphicHasOne-Array-1",
 | 
				
			||||||
			Toy:  Toy{Name: "Toy-PolymorphicHasOne-Array-1"},
 | 
								Toy:  Toy{Name: "Toy-PolymorphicHasOne-Array-1"},
 | 
				
			||||||
		}, {
 | 
							}, {
 | 
				
			||||||
@ -348,12 +349,12 @@ func TestCreateEmptyStruct(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestCreateEmptySlice(t *testing.T) {
 | 
					func TestCreateEmptySlice(t *testing.T) {
 | 
				
			||||||
	var data = []User{}
 | 
						data := []User{}
 | 
				
			||||||
	if err := DB.Create(&data).Error; err != gorm.ErrEmptySlice {
 | 
						if err := DB.Create(&data).Error; err != gorm.ErrEmptySlice {
 | 
				
			||||||
		t.Errorf("no data should be created, got %v", err)
 | 
							t.Errorf("no data should be created, got %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var sliceMap = []map[string]interface{}{}
 | 
						sliceMap := []map[string]interface{}{}
 | 
				
			||||||
	if err := DB.Model(&User{}).Create(&sliceMap).Error; err != gorm.ErrEmptySlice {
 | 
						if err := DB.Model(&User{}).Create(&sliceMap).Error; err != gorm.ErrEmptySlice {
 | 
				
			||||||
		t.Errorf("no data should be created, got %v", err)
 | 
							t.Errorf("no data should be created, got %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
@ -23,7 +23,7 @@ func TestDefaultValue(t *testing.T) {
 | 
				
			|||||||
		t.Fatalf("Failed to migrate with default value, got error: %v", err)
 | 
							t.Fatalf("Failed to migrate with default value, got error: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var harumph = Harumph{Email: "hello@gorm.io"}
 | 
						harumph := Harumph{Email: "hello@gorm.io"}
 | 
				
			||||||
	if err := DB.Create(&harumph).Error; err != nil {
 | 
						if err := DB.Create(&harumph).Error; err != nil {
 | 
				
			||||||
		t.Fatalf("Failed to create data with default value, got error: %v", err)
 | 
							t.Fatalf("Failed to create data with default value, got error: %v", err)
 | 
				
			||||||
	} else if harumph.Name != "foo" || harumph.Name2 != "foo" || harumph.Name3 != "" || harumph.Age != 18 || !harumph.Enabled {
 | 
						} else if harumph.Name != "foo" || harumph.Name2 != "foo" || harumph.Name3 != "" || harumph.Age != 18 || !harumph.Enabled {
 | 
				
			||||||
 | 
				
			|||||||
@ -10,7 +10,7 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestDelete(t *testing.T) {
 | 
					func TestDelete(t *testing.T) {
 | 
				
			||||||
	var users = []User{*GetUser("delete", Config{}), *GetUser("delete", Config{}), *GetUser("delete", Config{})}
 | 
						users := []User{*GetUser("delete", Config{}), *GetUser("delete", Config{}), *GetUser("delete", Config{})}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Create(&users).Error; err != nil {
 | 
						if err := DB.Create(&users).Error; err != nil {
 | 
				
			||||||
		t.Errorf("errors happened when create: %v", err)
 | 
							t.Errorf("errors happened when create: %v", err)
 | 
				
			||||||
 | 
				
			|||||||
@ -9,7 +9,7 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestDistinct(t *testing.T) {
 | 
					func TestDistinct(t *testing.T) {
 | 
				
			||||||
	var users = []User{
 | 
						users := []User{
 | 
				
			||||||
		*GetUser("distinct", Config{}),
 | 
							*GetUser("distinct", Config{}),
 | 
				
			||||||
		*GetUser("distinct", Config{}),
 | 
							*GetUser("distinct", Config{}),
 | 
				
			||||||
		*GetUser("distinct", Config{}),
 | 
							*GetUser("distinct", Config{}),
 | 
				
			||||||
 | 
				
			|||||||
@ -7,7 +7,7 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestGroupBy(t *testing.T) {
 | 
					func TestGroupBy(t *testing.T) {
 | 
				
			||||||
	var users = []User{{
 | 
						users := []User{{
 | 
				
			||||||
		Name:     "groupby",
 | 
							Name:     "groupby",
 | 
				
			||||||
		Age:      10,
 | 
							Age:      10,
 | 
				
			||||||
		Birthday: Now(),
 | 
							Birthday: Now(),
 | 
				
			||||||
@ -67,7 +67,7 @@ func TestGroupBy(t *testing.T) {
 | 
				
			|||||||
		t.Errorf("name should be groupby, but got %v, total should be 660, but got %v", name, total)
 | 
							t.Errorf("name should be groupby, but got %v, total should be 660, but got %v", name, total)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var result = struct {
 | 
						result := struct {
 | 
				
			||||||
		Name  string
 | 
							Name  string
 | 
				
			||||||
		Total int64
 | 
							Total int64
 | 
				
			||||||
	}{}
 | 
						}{}
 | 
				
			||||||
 | 
				
			|||||||
@ -57,7 +57,7 @@ func TestJoinsForSlice(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestJoinConds(t *testing.T) {
 | 
					func TestJoinConds(t *testing.T) {
 | 
				
			||||||
	var user = *GetUser("joins-conds", Config{Account: true, Pets: 3})
 | 
						user := *GetUser("joins-conds", Config{Account: true, Pets: 3})
 | 
				
			||||||
	DB.Save(&user)
 | 
						DB.Save(&user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var users1 []User
 | 
						var users1 []User
 | 
				
			||||||
@ -111,7 +111,7 @@ func TestJoinConds(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestJoinOn(t *testing.T) {
 | 
					func TestJoinOn(t *testing.T) {
 | 
				
			||||||
	var user = *GetUser("joins-on", Config{Pets: 2})
 | 
						user := *GetUser("joins-on", Config{Pets: 2})
 | 
				
			||||||
	DB.Save(&user)
 | 
						DB.Save(&user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var user1 User
 | 
						var user1 User
 | 
				
			||||||
 | 
				
			|||||||
@ -174,7 +174,6 @@ func TestSmartMigrateColumn(t *testing.T) {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestMigrateWithColumnComment(t *testing.T) {
 | 
					func TestMigrateWithColumnComment(t *testing.T) {
 | 
				
			||||||
 | 
				
			|||||||
@ -71,7 +71,7 @@ func TestManyToManyWithMultiPrimaryKeys(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Append
 | 
						// Append
 | 
				
			||||||
	var tag3 = &Tag{Locale: "ZH", Value: "tag3"}
 | 
						tag3 := &Tag{Locale: "ZH", Value: "tag3"}
 | 
				
			||||||
	DB.Model(&blog).Association("Tags").Append([]*Tag{tag3})
 | 
						DB.Model(&blog).Association("Tags").Append([]*Tag{tag3})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if !compareTags(blog.Tags, []string{"tag1", "tag2", "tag3"}) {
 | 
						if !compareTags(blog.Tags, []string{"tag1", "tag2", "tag3"}) {
 | 
				
			||||||
@ -95,8 +95,8 @@ func TestManyToManyWithMultiPrimaryKeys(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Replace
 | 
						// Replace
 | 
				
			||||||
	var tag5 = &Tag{Locale: "ZH", Value: "tag5"}
 | 
						tag5 := &Tag{Locale: "ZH", Value: "tag5"}
 | 
				
			||||||
	var tag6 = &Tag{Locale: "ZH", Value: "tag6"}
 | 
						tag6 := &Tag{Locale: "ZH", Value: "tag6"}
 | 
				
			||||||
	DB.Model(&blog).Association("Tags").Replace(tag5, tag6)
 | 
						DB.Model(&blog).Association("Tags").Replace(tag5, tag6)
 | 
				
			||||||
	var tags2 []Tag
 | 
						var tags2 []Tag
 | 
				
			||||||
	DB.Model(&blog).Association("Tags").Find(&tags2)
 | 
						DB.Model(&blog).Association("Tags").Find(&tags2)
 | 
				
			||||||
@ -170,7 +170,7 @@ func TestManyToManyWithCustomizedForeignKeys(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Append
 | 
						// Append
 | 
				
			||||||
	var tag3 = &Tag{Locale: "ZH", Value: "tag3"}
 | 
						tag3 := &Tag{Locale: "ZH", Value: "tag3"}
 | 
				
			||||||
	DB.Model(&blog).Association("SharedTags").Append([]*Tag{tag3})
 | 
						DB.Model(&blog).Association("SharedTags").Append([]*Tag{tag3})
 | 
				
			||||||
	if !compareTags(blog.SharedTags, []string{"tag1", "tag2", "tag3"}) {
 | 
						if !compareTags(blog.SharedTags, []string{"tag1", "tag2", "tag3"}) {
 | 
				
			||||||
		t.Fatalf("Blog should has three tags after Append")
 | 
							t.Fatalf("Blog should has three tags after Append")
 | 
				
			||||||
@ -201,7 +201,7 @@ func TestManyToManyWithCustomizedForeignKeys(t *testing.T) {
 | 
				
			|||||||
		t.Fatalf("Preload many2many relations")
 | 
							t.Fatalf("Preload many2many relations")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var tag4 = &Tag{Locale: "ZH", Value: "tag4"}
 | 
						tag4 := &Tag{Locale: "ZH", Value: "tag4"}
 | 
				
			||||||
	DB.Model(&blog2).Association("SharedTags").Append(tag4)
 | 
						DB.Model(&blog2).Association("SharedTags").Append(tag4)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	DB.Model(&blog).Association("SharedTags").Find(&tags)
 | 
						DB.Model(&blog).Association("SharedTags").Find(&tags)
 | 
				
			||||||
@ -215,8 +215,8 @@ func TestManyToManyWithCustomizedForeignKeys(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Replace
 | 
						// Replace
 | 
				
			||||||
	var tag5 = &Tag{Locale: "ZH", Value: "tag5"}
 | 
						tag5 := &Tag{Locale: "ZH", Value: "tag5"}
 | 
				
			||||||
	var tag6 = &Tag{Locale: "ZH", Value: "tag6"}
 | 
						tag6 := &Tag{Locale: "ZH", Value: "tag6"}
 | 
				
			||||||
	DB.Model(&blog2).Association("SharedTags").Replace(tag5, tag6)
 | 
						DB.Model(&blog2).Association("SharedTags").Replace(tag5, tag6)
 | 
				
			||||||
	var tags2 []Tag
 | 
						var tags2 []Tag
 | 
				
			||||||
	DB.Model(&blog).Association("SharedTags").Find(&tags2)
 | 
						DB.Model(&blog).Association("SharedTags").Find(&tags2)
 | 
				
			||||||
@ -291,7 +291,7 @@ func TestManyToManyWithCustomizedForeignKeys2(t *testing.T) {
 | 
				
			|||||||
	DB.Create(&blog2)
 | 
						DB.Create(&blog2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Append
 | 
						// Append
 | 
				
			||||||
	var tag3 = &Tag{Locale: "ZH", Value: "tag3"}
 | 
						tag3 := &Tag{Locale: "ZH", Value: "tag3"}
 | 
				
			||||||
	DB.Model(&blog).Association("LocaleTags").Append([]*Tag{tag3})
 | 
						DB.Model(&blog).Association("LocaleTags").Append([]*Tag{tag3})
 | 
				
			||||||
	if !compareTags(blog.LocaleTags, []string{"tag1", "tag2", "tag3"}) {
 | 
						if !compareTags(blog.LocaleTags, []string{"tag1", "tag2", "tag3"}) {
 | 
				
			||||||
		t.Fatalf("Blog should has three tags after Append")
 | 
							t.Fatalf("Blog should has three tags after Append")
 | 
				
			||||||
@ -322,7 +322,7 @@ func TestManyToManyWithCustomizedForeignKeys2(t *testing.T) {
 | 
				
			|||||||
		t.Fatalf("Preload many2many relations")
 | 
							t.Fatalf("Preload many2many relations")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var tag4 = &Tag{Locale: "ZH", Value: "tag4"}
 | 
						tag4 := &Tag{Locale: "ZH", Value: "tag4"}
 | 
				
			||||||
	DB.Model(&blog2).Association("LocaleTags").Append(tag4)
 | 
						DB.Model(&blog2).Association("LocaleTags").Append(tag4)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	DB.Model(&blog).Association("LocaleTags").Find(&tags)
 | 
						DB.Model(&blog).Association("LocaleTags").Find(&tags)
 | 
				
			||||||
@ -336,8 +336,8 @@ func TestManyToManyWithCustomizedForeignKeys2(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Replace
 | 
						// Replace
 | 
				
			||||||
	var tag5 = &Tag{Locale: "ZH", Value: "tag5"}
 | 
						tag5 := &Tag{Locale: "ZH", Value: "tag5"}
 | 
				
			||||||
	var tag6 = &Tag{Locale: "ZH", Value: "tag6"}
 | 
						tag6 := &Tag{Locale: "ZH", Value: "tag6"}
 | 
				
			||||||
	DB.Model(&blog2).Association("LocaleTags").Replace(tag5, tag6)
 | 
						DB.Model(&blog2).Association("LocaleTags").Replace(tag5, tag6)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var tags2 []Tag
 | 
						var tags2 []Tag
 | 
				
			||||||
 | 
				
			|||||||
@ -5,6 +5,7 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	"github.com/google/uuid"
 | 
						"github.com/google/uuid"
 | 
				
			||||||
	"github.com/lib/pq"
 | 
						"github.com/lib/pq"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"gorm.io/gorm"
 | 
						"gorm.io/gorm"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -14,7 +14,7 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPreloadWithAssociations(t *testing.T) {
 | 
					func TestPreloadWithAssociations(t *testing.T) {
 | 
				
			||||||
	var user = *GetUser("preload_with_associations", Config{
 | 
						user := *GetUser("preload_with_associations", Config{
 | 
				
			||||||
		Account:   true,
 | 
							Account:   true,
 | 
				
			||||||
		Pets:      2,
 | 
							Pets:      2,
 | 
				
			||||||
		Toys:      3,
 | 
							Toys:      3,
 | 
				
			||||||
@ -35,7 +35,7 @@ func TestPreloadWithAssociations(t *testing.T) {
 | 
				
			|||||||
	DB.Preload(clause.Associations).Find(&user2, "id = ?", user.ID)
 | 
						DB.Preload(clause.Associations).Find(&user2, "id = ?", user.ID)
 | 
				
			||||||
	CheckUser(t, user2, user)
 | 
						CheckUser(t, user2, user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var user3 = *GetUser("preload_with_associations_new", Config{
 | 
						user3 := *GetUser("preload_with_associations_new", Config{
 | 
				
			||||||
		Account:   true,
 | 
							Account:   true,
 | 
				
			||||||
		Pets:      2,
 | 
							Pets:      2,
 | 
				
			||||||
		Toys:      3,
 | 
							Toys:      3,
 | 
				
			||||||
@ -51,7 +51,7 @@ func TestPreloadWithAssociations(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestNestedPreload(t *testing.T) {
 | 
					func TestNestedPreload(t *testing.T) {
 | 
				
			||||||
	var user = *GetUser("nested_preload", Config{Pets: 2})
 | 
						user := *GetUser("nested_preload", Config{Pets: 2})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for idx, pet := range user.Pets {
 | 
						for idx, pet := range user.Pets {
 | 
				
			||||||
		pet.Toy = Toy{Name: "toy_nested_preload_" + strconv.Itoa(idx+1)}
 | 
							pet.Toy = Toy{Name: "toy_nested_preload_" + strconv.Itoa(idx+1)}
 | 
				
			||||||
@ -75,7 +75,7 @@ func TestNestedPreload(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestNestedPreloadForSlice(t *testing.T) {
 | 
					func TestNestedPreloadForSlice(t *testing.T) {
 | 
				
			||||||
	var users = []User{
 | 
						users := []User{
 | 
				
			||||||
		*GetUser("slice_nested_preload_1", Config{Pets: 2}),
 | 
							*GetUser("slice_nested_preload_1", Config{Pets: 2}),
 | 
				
			||||||
		*GetUser("slice_nested_preload_2", Config{Pets: 0}),
 | 
							*GetUser("slice_nested_preload_2", Config{Pets: 0}),
 | 
				
			||||||
		*GetUser("slice_nested_preload_3", Config{Pets: 3}),
 | 
							*GetUser("slice_nested_preload_3", Config{Pets: 3}),
 | 
				
			||||||
@ -105,7 +105,7 @@ func TestNestedPreloadForSlice(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPreloadWithConds(t *testing.T) {
 | 
					func TestPreloadWithConds(t *testing.T) {
 | 
				
			||||||
	var users = []User{
 | 
						users := []User{
 | 
				
			||||||
		*GetUser("slice_nested_preload_1", Config{Account: true}),
 | 
							*GetUser("slice_nested_preload_1", Config{Account: true}),
 | 
				
			||||||
		*GetUser("slice_nested_preload_2", Config{Account: false}),
 | 
							*GetUser("slice_nested_preload_2", Config{Account: false}),
 | 
				
			||||||
		*GetUser("slice_nested_preload_3", Config{Account: true}),
 | 
							*GetUser("slice_nested_preload_3", Config{Account: true}),
 | 
				
			||||||
@ -163,7 +163,7 @@ func TestPreloadWithConds(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestNestedPreloadWithConds(t *testing.T) {
 | 
					func TestNestedPreloadWithConds(t *testing.T) {
 | 
				
			||||||
	var users = []User{
 | 
						users := []User{
 | 
				
			||||||
		*GetUser("slice_nested_preload_1", Config{Pets: 2}),
 | 
							*GetUser("slice_nested_preload_1", Config{Pets: 2}),
 | 
				
			||||||
		*GetUser("slice_nested_preload_2", Config{Pets: 0}),
 | 
							*GetUser("slice_nested_preload_2", Config{Pets: 0}),
 | 
				
			||||||
		*GetUser("slice_nested_preload_3", Config{Pets: 3}),
 | 
							*GetUser("slice_nested_preload_3", Config{Pets: 3}),
 | 
				
			||||||
@ -213,7 +213,7 @@ func TestNestedPreloadWithConds(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPreloadEmptyData(t *testing.T) {
 | 
					func TestPreloadEmptyData(t *testing.T) {
 | 
				
			||||||
	var user = *GetUser("user_without_associations", Config{})
 | 
						user := *GetUser("user_without_associations", Config{})
 | 
				
			||||||
	DB.Create(&user)
 | 
						DB.Create(&user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	DB.Preload("Team").Preload("Languages").Preload("Friends").First(&user, "name = ?", user.Name)
 | 
						DB.Preload("Team").Preload("Languages").Preload("Friends").First(&user, "name = ?", user.Name)
 | 
				
			||||||
 | 
				
			|||||||
@ -17,7 +17,7 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestFind(t *testing.T) {
 | 
					func TestFind(t *testing.T) {
 | 
				
			||||||
	var users = []User{
 | 
						users := []User{
 | 
				
			||||||
		*GetUser("find", Config{}),
 | 
							*GetUser("find", Config{}),
 | 
				
			||||||
		*GetUser("find", Config{}),
 | 
							*GetUser("find", Config{}),
 | 
				
			||||||
		*GetUser("find", Config{}),
 | 
							*GetUser("find", Config{}),
 | 
				
			||||||
@ -57,7 +57,7 @@ func TestFind(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t.Run("FirstMap", func(t *testing.T) {
 | 
						t.Run("FirstMap", func(t *testing.T) {
 | 
				
			||||||
		var first = map[string]interface{}{}
 | 
							first := map[string]interface{}{}
 | 
				
			||||||
		if err := DB.Model(&User{}).Where("name = ?", "find").First(first).Error; err != nil {
 | 
							if err := DB.Model(&User{}).Where("name = ?", "find").First(first).Error; err != nil {
 | 
				
			||||||
			t.Errorf("errors happened when query first: %v", err)
 | 
								t.Errorf("errors happened when query first: %v", err)
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
@ -88,7 +88,7 @@ func TestFind(t *testing.T) {
 | 
				
			|||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t.Run("FirstMapWithTable", func(t *testing.T) {
 | 
						t.Run("FirstMapWithTable", func(t *testing.T) {
 | 
				
			||||||
		var first = map[string]interface{}{}
 | 
							first := map[string]interface{}{}
 | 
				
			||||||
		if err := DB.Table("users").Where("name = ?", "find").Find(first).Error; err != nil {
 | 
							if err := DB.Table("users").Where("name = ?", "find").Find(first).Error; err != nil {
 | 
				
			||||||
			t.Errorf("errors happened when query first: %v", err)
 | 
								t.Errorf("errors happened when query first: %v", err)
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
@ -120,7 +120,7 @@ func TestFind(t *testing.T) {
 | 
				
			|||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t.Run("FirstPtrMap", func(t *testing.T) {
 | 
						t.Run("FirstPtrMap", func(t *testing.T) {
 | 
				
			||||||
		var first = map[string]interface{}{}
 | 
							first := map[string]interface{}{}
 | 
				
			||||||
		if err := DB.Model(&User{}).Where("name = ?", "find").First(&first).Error; err != nil {
 | 
							if err := DB.Model(&User{}).Where("name = ?", "find").First(&first).Error; err != nil {
 | 
				
			||||||
			t.Errorf("errors happened when query first: %v", err)
 | 
								t.Errorf("errors happened when query first: %v", err)
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
@ -135,7 +135,7 @@ func TestFind(t *testing.T) {
 | 
				
			|||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t.Run("FirstSliceOfMap", func(t *testing.T) {
 | 
						t.Run("FirstSliceOfMap", func(t *testing.T) {
 | 
				
			||||||
		var allMap = []map[string]interface{}{}
 | 
							allMap := []map[string]interface{}{}
 | 
				
			||||||
		if err := DB.Model(&User{}).Where("name = ?", "find").Find(&allMap).Error; err != nil {
 | 
							if err := DB.Model(&User{}).Where("name = ?", "find").Find(&allMap).Error; err != nil {
 | 
				
			||||||
			t.Errorf("errors happened when query find: %v", err)
 | 
								t.Errorf("errors happened when query find: %v", err)
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
@ -170,7 +170,7 @@ func TestFind(t *testing.T) {
 | 
				
			|||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t.Run("FindSliceOfMapWithTable", func(t *testing.T) {
 | 
						t.Run("FindSliceOfMapWithTable", func(t *testing.T) {
 | 
				
			||||||
		var allMap = []map[string]interface{}{}
 | 
							allMap := []map[string]interface{}{}
 | 
				
			||||||
		if err := DB.Table("users").Where("name = ?", "find").Find(&allMap).Error; err != nil {
 | 
							if err := DB.Table("users").Where("name = ?", "find").Find(&allMap).Error; err != nil {
 | 
				
			||||||
			t.Errorf("errors happened when query find: %v", err)
 | 
								t.Errorf("errors happened when query find: %v", err)
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
@ -241,7 +241,7 @@ func TestQueryWithAssociation(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestFindInBatches(t *testing.T) {
 | 
					func TestFindInBatches(t *testing.T) {
 | 
				
			||||||
	var users = []User{
 | 
						users := []User{
 | 
				
			||||||
		*GetUser("find_in_batches", Config{}),
 | 
							*GetUser("find_in_batches", Config{}),
 | 
				
			||||||
		*GetUser("find_in_batches", Config{}),
 | 
							*GetUser("find_in_batches", Config{}),
 | 
				
			||||||
		*GetUser("find_in_batches", Config{}),
 | 
							*GetUser("find_in_batches", Config{}),
 | 
				
			||||||
@ -297,7 +297,7 @@ func TestFindInBatchesWithError(t *testing.T) {
 | 
				
			|||||||
		t.Skip("skip sqlserver due to it will raise data race for invalid sql")
 | 
							t.Skip("skip sqlserver due to it will raise data race for invalid sql")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var users = []User{
 | 
						users := []User{
 | 
				
			||||||
		*GetUser("find_in_batches_with_error", Config{}),
 | 
							*GetUser("find_in_batches_with_error", Config{}),
 | 
				
			||||||
		*GetUser("find_in_batches_with_error", Config{}),
 | 
							*GetUser("find_in_batches_with_error", Config{}),
 | 
				
			||||||
		*GetUser("find_in_batches_with_error", Config{}),
 | 
							*GetUser("find_in_batches_with_error", Config{}),
 | 
				
			||||||
 | 
				
			|||||||
@ -45,7 +45,7 @@ func TestScan(t *testing.T) {
 | 
				
			|||||||
		t.Fatalf("Scan into struct should work, got %#v, should %#v", res, user3)
 | 
							t.Fatalf("Scan into struct should work, got %#v, should %#v", res, user3)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var doubleAgeRes = &result{}
 | 
						doubleAgeRes := &result{}
 | 
				
			||||||
	if err := DB.Table("users").Select("age + age as age").Where("id = ?", user3.ID).Scan(&doubleAgeRes).Error; err != nil {
 | 
						if err := DB.Table("users").Select("age + age as age").Where("id = ?", user3.ID).Scan(&doubleAgeRes).Error; err != nil {
 | 
				
			||||||
		t.Errorf("Scan to pointer of pointer")
 | 
							t.Errorf("Scan to pointer of pointer")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
				
			|||||||
@ -23,7 +23,7 @@ func NameIn(names []string) func(d *gorm.DB) *gorm.DB {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestScopes(t *testing.T) {
 | 
					func TestScopes(t *testing.T) {
 | 
				
			||||||
	var users = []*User{
 | 
						users := []*User{
 | 
				
			||||||
		GetUser("ScopeUser1", Config{}),
 | 
							GetUser("ScopeUser1", Config{}),
 | 
				
			||||||
		GetUser("ScopeUser2", Config{}),
 | 
							GetUser("ScopeUser2", Config{}),
 | 
				
			||||||
		GetUser("ScopeUser3", Config{}),
 | 
							GetUser("ScopeUser3", Config{}),
 | 
				
			||||||
 | 
				
			|||||||
@ -4,12 +4,11 @@ import (
 | 
				
			|||||||
	"regexp"
 | 
						"regexp"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"gorm.io/gorm"
 | 
						"gorm.io/gorm"
 | 
				
			||||||
	"gorm.io/gorm/clause"
 | 
						"gorm.io/gorm/clause"
 | 
				
			||||||
	. "gorm.io/gorm/utils/tests"
 | 
						. "gorm.io/gorm/utils/tests"
 | 
				
			||||||
 | 
					 | 
				
			||||||
	"time"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestRow(t *testing.T) {
 | 
					func TestRow(t *testing.T) {
 | 
				
			||||||
@ -389,12 +388,12 @@ func assertEqualSQL(t *testing.T, expected string, actually string) {
 | 
				
			|||||||
	actually = replaceQuoteInSQL(actually)
 | 
						actually = replaceQuoteInSQL(actually)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// ignore updated_at value, becase it's generated in Gorm inernal, can't to mock value on update.
 | 
						// ignore updated_at value, becase it's generated in Gorm inernal, can't to mock value on update.
 | 
				
			||||||
	var updatedAtRe = regexp.MustCompile(`(?i)"updated_at"=".+?"`)
 | 
						updatedAtRe := regexp.MustCompile(`(?i)"updated_at"=".+?"`)
 | 
				
			||||||
	actually = updatedAtRe.ReplaceAllString(actually, `"updated_at"=?`)
 | 
						actually = updatedAtRe.ReplaceAllString(actually, `"updated_at"=?`)
 | 
				
			||||||
	expected = updatedAtRe.ReplaceAllString(expected, `"updated_at"=?`)
 | 
						expected = updatedAtRe.ReplaceAllString(expected, `"updated_at"=?`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// ignore RETURNING "id" (only in PostgreSQL)
 | 
						// ignore RETURNING "id" (only in PostgreSQL)
 | 
				
			||||||
	var returningRe = regexp.MustCompile(`(?i)RETURNING "id"`)
 | 
						returningRe := regexp.MustCompile(`(?i)RETURNING "id"`)
 | 
				
			||||||
	actually = returningRe.ReplaceAllString(actually, ``)
 | 
						actually = returningRe.ReplaceAllString(actually, ``)
 | 
				
			||||||
	expected = returningRe.ReplaceAllString(expected, ``)
 | 
						expected = returningRe.ReplaceAllString(expected, ``)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -408,16 +407,16 @@ func assertEqualSQL(t *testing.T, expected string, actually string) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func replaceQuoteInSQL(sql string) string {
 | 
					func replaceQuoteInSQL(sql string) string {
 | 
				
			||||||
	// convert single quote into double quote
 | 
						// convert single quote into double quote
 | 
				
			||||||
	sql = strings.Replace(sql, `'`, `"`, -1)
 | 
						sql = strings.ReplaceAll(sql, `'`, `"`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// convert dialect speical quote into double quote
 | 
						// convert dialect speical quote into double quote
 | 
				
			||||||
	switch DB.Dialector.Name() {
 | 
						switch DB.Dialector.Name() {
 | 
				
			||||||
	case "postgres":
 | 
						case "postgres":
 | 
				
			||||||
		sql = strings.Replace(sql, `"`, `"`, -1)
 | 
							sql = strings.ReplaceAll(sql, `"`, `"`)
 | 
				
			||||||
	case "mysql", "sqlite":
 | 
						case "mysql", "sqlite":
 | 
				
			||||||
		sql = strings.Replace(sql, "`", `"`, -1)
 | 
							sql = strings.ReplaceAll(sql, "`", `"`)
 | 
				
			||||||
	case "sqlserver":
 | 
						case "sqlserver":
 | 
				
			||||||
		sql = strings.Replace(sql, `'`, `"`, -1)
 | 
							sql = strings.ReplaceAll(sql, `'`, `"`)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return sql
 | 
						return sql
 | 
				
			||||||
 | 
				
			|||||||
@ -22,19 +22,19 @@ for dialect in "${dialects[@]}" ; do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if [ "$GORM_VERBOSE" = "" ]
 | 
					    if [ "$GORM_VERBOSE" = "" ]
 | 
				
			||||||
    then
 | 
					    then
 | 
				
			||||||
      GORM_DIALECT=${dialect} go test -race -count=1 ./...
 | 
					      GORM_DIALECT=${dialect} go test -race -count=1 -coverprofile=coverage.out ./...
 | 
				
			||||||
      if [ -d tests ]
 | 
					      if [ -d tests ]
 | 
				
			||||||
      then
 | 
					      then
 | 
				
			||||||
        cd tests
 | 
					        cd tests
 | 
				
			||||||
        GORM_DIALECT=${dialect} go test -race -count=1 ./...
 | 
					        GORM_DIALECT=${dialect} go test -race -count=1 -coverprofile=../coverage.out ./...
 | 
				
			||||||
        cd ..
 | 
					        cd ..
 | 
				
			||||||
      fi
 | 
					      fi
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
      GORM_DIALECT=${dialect} go test -race -count=1 -v ./...
 | 
					      GORM_DIALECT=${dialect} go test -race -count=1 -v -coverprofile=coverage.out ./...
 | 
				
			||||||
      if [ -d tests ]
 | 
					      if [ -d tests ]
 | 
				
			||||||
      then
 | 
					      then
 | 
				
			||||||
        cd tests
 | 
					        cd tests
 | 
				
			||||||
        GORM_DIALECT=${dialect} go test -race -count=1 -v ./...
 | 
					        GORM_DIALECT=${dialect} go test -race -count=1 -v -coverprofile=../coverage.out ./...
 | 
				
			||||||
        cd ..
 | 
					        cd ..
 | 
				
			||||||
      fi
 | 
					      fi
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
 | 
				
			|||||||
@ -11,6 +11,7 @@ import (
 | 
				
			|||||||
	"gorm.io/driver/postgres"
 | 
						"gorm.io/driver/postgres"
 | 
				
			||||||
	"gorm.io/driver/sqlite"
 | 
						"gorm.io/driver/sqlite"
 | 
				
			||||||
	"gorm.io/driver/sqlserver"
 | 
						"gorm.io/driver/sqlserver"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"gorm.io/gorm"
 | 
						"gorm.io/gorm"
 | 
				
			||||||
	"gorm.io/gorm/logger"
 | 
						"gorm.io/gorm/logger"
 | 
				
			||||||
	. "gorm.io/gorm/utils/tests"
 | 
						. "gorm.io/gorm/utils/tests"
 | 
				
			||||||
 | 
				
			|||||||
@ -8,7 +8,7 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestUpdateBelongsTo(t *testing.T) {
 | 
					func TestUpdateBelongsTo(t *testing.T) {
 | 
				
			||||||
	var user = *GetUser("update-belongs-to", Config{})
 | 
						user := *GetUser("update-belongs-to", Config{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Create(&user).Error; err != nil {
 | 
						if err := DB.Create(&user).Error; err != nil {
 | 
				
			||||||
		t.Fatalf("errors happened when create: %v", err)
 | 
							t.Fatalf("errors happened when create: %v", err)
 | 
				
			||||||
 | 
				
			|||||||
@ -8,7 +8,7 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestUpdateHasManyAssociations(t *testing.T) {
 | 
					func TestUpdateHasManyAssociations(t *testing.T) {
 | 
				
			||||||
	var user = *GetUser("update-has-many", Config{})
 | 
						user := *GetUser("update-has-many", Config{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Create(&user).Error; err != nil {
 | 
						if err := DB.Create(&user).Error; err != nil {
 | 
				
			||||||
		t.Fatalf("errors happened when create: %v", err)
 | 
							t.Fatalf("errors happened when create: %v", err)
 | 
				
			||||||
@ -44,7 +44,7 @@ func TestUpdateHasManyAssociations(t *testing.T) {
 | 
				
			|||||||
	CheckUser(t, user4, user)
 | 
						CheckUser(t, user4, user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t.Run("Polymorphic", func(t *testing.T) {
 | 
						t.Run("Polymorphic", func(t *testing.T) {
 | 
				
			||||||
		var user = *GetUser("update-has-many", Config{})
 | 
							user := *GetUser("update-has-many", Config{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if err := DB.Create(&user).Error; err != nil {
 | 
							if err := DB.Create(&user).Error; err != nil {
 | 
				
			||||||
			t.Fatalf("errors happened when create: %v", err)
 | 
								t.Fatalf("errors happened when create: %v", err)
 | 
				
			||||||
 | 
				
			|||||||
@ -10,7 +10,7 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestUpdateHasOne(t *testing.T) {
 | 
					func TestUpdateHasOne(t *testing.T) {
 | 
				
			||||||
	var user = *GetUser("update-has-one", Config{})
 | 
						user := *GetUser("update-has-one", Config{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Create(&user).Error; err != nil {
 | 
						if err := DB.Create(&user).Error; err != nil {
 | 
				
			||||||
		t.Fatalf("errors happened when create: %v", err)
 | 
							t.Fatalf("errors happened when create: %v", err)
 | 
				
			||||||
@ -35,7 +35,7 @@ func TestUpdateHasOne(t *testing.T) {
 | 
				
			|||||||
	DB.Preload("Account").Find(&user3, "id = ?", user.ID)
 | 
						DB.Preload("Account").Find(&user3, "id = ?", user.ID)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CheckUser(t, user2, user3)
 | 
						CheckUser(t, user2, user3)
 | 
				
			||||||
	var lastUpdatedAt = user2.Account.UpdatedAt
 | 
						lastUpdatedAt := user2.Account.UpdatedAt
 | 
				
			||||||
	time.Sleep(time.Second)
 | 
						time.Sleep(time.Second)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Session(&gorm.Session{FullSaveAssociations: true}).Save(&user).Error; err != nil {
 | 
						if err := DB.Session(&gorm.Session{FullSaveAssociations: true}).Save(&user).Error; err != nil {
 | 
				
			||||||
@ -53,7 +53,7 @@ func TestUpdateHasOne(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t.Run("Polymorphic", func(t *testing.T) {
 | 
						t.Run("Polymorphic", func(t *testing.T) {
 | 
				
			||||||
		var pet = Pet{Name: "create"}
 | 
							pet := Pet{Name: "create"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if err := DB.Create(&pet).Error; err != nil {
 | 
							if err := DB.Create(&pet).Error; err != nil {
 | 
				
			||||||
			t.Fatalf("errors happened when create: %v", err)
 | 
								t.Fatalf("errors happened when create: %v", err)
 | 
				
			||||||
 | 
				
			|||||||
@ -8,7 +8,7 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestUpdateMany2ManyAssociations(t *testing.T) {
 | 
					func TestUpdateMany2ManyAssociations(t *testing.T) {
 | 
				
			||||||
	var user = *GetUser("update-many2many", Config{})
 | 
						user := *GetUser("update-many2many", Config{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := DB.Create(&user).Error; err != nil {
 | 
						if err := DB.Create(&user).Error; err != nil {
 | 
				
			||||||
		t.Fatalf("errors happened when create: %v", err)
 | 
							t.Fatalf("errors happened when create: %v", err)
 | 
				
			||||||
 | 
				
			|||||||
@ -125,7 +125,7 @@ func TestUpdate(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestUpdates(t *testing.T) {
 | 
					func TestUpdates(t *testing.T) {
 | 
				
			||||||
	var users = []*User{
 | 
						users := []*User{
 | 
				
			||||||
		GetUser("updates_01", Config{}),
 | 
							GetUser("updates_01", Config{}),
 | 
				
			||||||
		GetUser("updates_02", Config{}),
 | 
							GetUser("updates_02", Config{}),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -178,7 +178,7 @@ func TestUpdates(t *testing.T) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestUpdateColumn(t *testing.T) {
 | 
					func TestUpdateColumn(t *testing.T) {
 | 
				
			||||||
	var users = []*User{
 | 
						users := []*User{
 | 
				
			||||||
		GetUser("update_column_01", Config{}),
 | 
							GetUser("update_column_01", Config{}),
 | 
				
			||||||
		GetUser("update_column_02", Config{}),
 | 
							GetUser("update_column_02", Config{}),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -622,7 +622,7 @@ func TestSave(t *testing.T) {
 | 
				
			|||||||
	time.Sleep(time.Second)
 | 
						time.Sleep(time.Second)
 | 
				
			||||||
	user1UpdatedAt := result.UpdatedAt
 | 
						user1UpdatedAt := result.UpdatedAt
 | 
				
			||||||
	user2UpdatedAt := user2.UpdatedAt
 | 
						user2UpdatedAt := user2.UpdatedAt
 | 
				
			||||||
	var users = []*User{&result, &user2}
 | 
						users := []*User{&result, &user2}
 | 
				
			||||||
	DB.Save(&users)
 | 
						DB.Save(&users)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if user1UpdatedAt.Format(time.RFC1123Z) == result.UpdatedAt.Format(time.RFC1123Z) {
 | 
						if user1UpdatedAt.Format(time.RFC1123Z) == result.UpdatedAt.Format(time.RFC1123Z) {
 | 
				
			||||||
 | 
				
			|||||||
@ -67,7 +67,7 @@ func TestUpsert(t *testing.T) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var user = *GetUser("upsert_on_conflict", Config{})
 | 
						user := *GetUser("upsert_on_conflict", Config{})
 | 
				
			||||||
	user.Age = 20
 | 
						user.Age = 20
 | 
				
			||||||
	if err := DB.Create(&user).Error; err != nil {
 | 
						if err := DB.Create(&user).Error; err != nil {
 | 
				
			||||||
		t.Errorf("failed to create user, got error %v", err)
 | 
							t.Errorf("failed to create user, got error %v", err)
 | 
				
			||||||
@ -320,11 +320,9 @@ func TestUpdateWithMissWhere(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if err := tx.Error; err != nil {
 | 
						if err := tx.Error; err != nil {
 | 
				
			||||||
		t.Fatalf("failed to update user,missing where condtion,err=%+v", err)
 | 
							t.Fatalf("failed to update user,missing where condtion,err=%+v", err)
 | 
				
			||||||
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if !regexp.MustCompile("WHERE .id. = [^ ]+$").MatchString(tx.Statement.SQL.String()) {
 | 
						if !regexp.MustCompile("WHERE .id. = [^ ]+$").MatchString(tx.Statement.SQL.String()) {
 | 
				
			||||||
		t.Fatalf("invalid updating SQL, got %v", tx.Statement.SQL.String())
 | 
							t.Fatalf("invalid updating SQL, got %v", tx.Statement.SQL.String())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -7,8 +7,7 @@ import (
 | 
				
			|||||||
	"gorm.io/gorm/schema"
 | 
						"gorm.io/gorm/schema"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type DummyDialector struct {
 | 
					type DummyDialector struct{}
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (DummyDialector) Name() string {
 | 
					func (DummyDialector) Name() string {
 | 
				
			||||||
	return "dummy"
 | 
						return "dummy"
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user