github.com/ecodeclub/eorm@v0.0.2-0.20231001112437-dae71da914d0/db_test.go (about)

     1  // Copyright 2021 ecodeclub
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  // http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package eorm
    16  
    17  import (
    18  	"context"
    19  	"database/sql"
    20  	"errors"
    21  	"fmt"
    22  	"testing"
    23  
    24  	"github.com/DATA-DOG/go-sqlmock"
    25  	"github.com/ecodeclub/eorm/internal/datasource/single"
    26  	"github.com/stretchr/testify/assert"
    27  
    28  	"github.com/ecodeclub/eorm/internal/datasource/masterslave"
    29  
    30  	"github.com/ecodeclub/eorm/internal/valuer"
    31  	_ "github.com/mattn/go-sqlite3"
    32  )
    33  
    34  func TestDB_BeginTx(t *testing.T) {
    35  	mockDB, mock, err := sqlmock.New()
    36  	if err != nil {
    37  		t.Fatal(err)
    38  	}
    39  	defer func() { _ = mockDB.Close() }()
    40  
    41  	db, err := OpenDS("mysql", single.NewDB(mockDB))
    42  	if err != nil {
    43  		t.Fatal(err)
    44  	}
    45  	// Begin 失败
    46  	mock.ExpectBegin().WillReturnError(errors.New("begin failed"))
    47  	tx, err := db.BeginTx(context.Background(), &sql.TxOptions{})
    48  	assert.Equal(t, errors.New("begin failed"), err)
    49  	assert.Nil(t, tx)
    50  
    51  	mock.ExpectBegin()
    52  	tx, err = db.BeginTx(context.Background(), &sql.TxOptions{})
    53  	assert.Nil(t, err)
    54  	assert.NotNil(t, tx)
    55  }
    56  
    57  func ExampleMiddleware() {
    58  	db, _ := Open("sqlite3", "file:test.db?cache=shared&mode=memory",
    59  		DBWithMiddlewares(func(next HandleFunc) HandleFunc {
    60  			return func(ctx context.Context, queryContext *QueryContext) *QueryResult {
    61  				return &QueryResult{Result: "mdl1"}
    62  			}
    63  		}, func(next HandleFunc) HandleFunc {
    64  			return func(ctx context.Context, queryContext *QueryContext) *QueryResult {
    65  				return &QueryResult{Result: "mdl2"}
    66  			}
    67  		}))
    68  	defer func() {
    69  		_ = db.Close()
    70  	}()
    71  	fmt.Println(len(db.ms))
    72  	// Output:
    73  	// 2
    74  }
    75  
    76  func ExampleDB_BeginTx() {
    77  	db, _ := Open("sqlite3", "file:test.db?cache=shared&mode=memory")
    78  	defer func() {
    79  		_ = db.Close()
    80  	}()
    81  	tx, err := db.BeginTx(context.Background(), &sql.TxOptions{})
    82  	if err == nil {
    83  		fmt.Println("Begin")
    84  	}
    85  	// 或者 tx.Rollback()
    86  	err = tx.Commit()
    87  	if err == nil {
    88  		fmt.Println("Commit")
    89  	}
    90  	// Output:
    91  	// Begin
    92  	// Commit
    93  }
    94  
    95  func ExampleOpen() {
    96  	// case1 without DBOption
    97  	db, _ := Open("sqlite3", "file:test.db?cache=shared&mode=memory")
    98  	fmt.Printf("case1 dialect: %s\n", db.dialect.Name)
    99  
   100  	// Output:
   101  	// case1 dialect: SQLite
   102  }
   103  
   104  func ExampleNewDeleter() {
   105  	tm := &TestModel{}
   106  	db := memoryDB()
   107  	query, _ := NewDeleter[TestModel](db).From(tm).Build()
   108  	fmt.Printf("SQL: %s", query.SQL)
   109  	// Output:
   110  	// SQL: DELETE FROM `test_model`;
   111  }
   112  
   113  func ExampleNewUpdater() {
   114  	tm := &TestModel{
   115  		Age: 18,
   116  	}
   117  	db := memoryDB()
   118  	query, _ := NewUpdater[TestModel](db).Update(tm).Build()
   119  	fmt.Printf("SQL: %s", query.SQL)
   120  	// Output:
   121  	// SQL: UPDATE `test_model` SET `id`=?,`first_name`=?,`age`=?,`last_name`=?;
   122  }
   123  
   124  // memoryDB 返回一个基于内存的 ORM,它使用的是 sqlite3 内存模式。
   125  func memoryDB() *DB {
   126  	db, err := Open("sqlite3", "file:test.db?cache=shared&mode=memory")
   127  	if err != nil {
   128  		panic(err)
   129  	}
   130  	return db
   131  }
   132  
   133  func memoryDBWithDB(dbName string) *DB {
   134  	db, err := Open("sqlite3", fmt.Sprintf("file:%s.db?cache=shared&mode=memory", dbName))
   135  	if err != nil {
   136  		panic(err)
   137  	}
   138  	return db
   139  }
   140  
   141  // go test -bench=BenchmarkQuerier_Get -benchmem -benchtime=10000x
   142  // goos: linux
   143  // goarch: amd64
   144  // pkg: github.com/ecodeclub/eorm
   145  // cpu: Intel(R) Core(TM) i5-10400F CPU @ 2.90GHz
   146  // BenchmarkQuerier_Get/unsafe-12             10000            446263 ns/op            3849 B/op        116 allocs/op
   147  // BenchmarkQuerier_Get/reflect-12            10000            854557 ns/op            4062 B/op        128 allocs/op
   148  // PASS
   149  // ok      github.com/ecodeclub/eorm       13.072s
   150  func BenchmarkQuerier_Get(b *testing.B) {
   151  	b.ReportAllocs()
   152  	db := memoryDBWithDB("benchmarkQuerierGet")
   153  	defer func() {
   154  		_ = db.Close()
   155  	}()
   156  	_ = RawQuery[any](db, TestModel{}.CreateSQL()).Exec(context.Background())
   157  	res := NewInserter[TestModel](db).Values(&TestModel{
   158  		Id:        12,
   159  		FirstName: "Deng",
   160  		Age:       18,
   161  		LastName:  &sql.NullString{String: "Ming", Valid: true},
   162  	}).Exec(context.Background())
   163  	if res.Err() != nil {
   164  		b.Fatal(res.Err())
   165  	}
   166  	affected, err := res.RowsAffected()
   167  	if err != nil {
   168  		b.Fatal(err)
   169  	}
   170  	if affected == 0 {
   171  		b.Fatal()
   172  	}
   173  
   174  	b.Run("unsafe", func(b *testing.B) {
   175  		db.valCreator = valuer.PrimitiveCreator{
   176  			Creator: valuer.NewUnsafeValue,
   177  		}
   178  		for i := 0; i < b.N; i++ {
   179  			_, err = NewSelector[TestModel](db).From(TableOf(&TestModel{}, "t1")).Get(context.Background())
   180  			if err != nil {
   181  				b.Fatal(err)
   182  			}
   183  		}
   184  	})
   185  
   186  	b.Run("reflect", func(b *testing.B) {
   187  		db.valCreator = valuer.PrimitiveCreator{
   188  			Creator: valuer.NewReflectValue,
   189  		}
   190  		for i := 0; i < b.N; i++ {
   191  			_, err = NewSelector[TestModel](db).From(TableOf(&TestModel{}, "t1")).Get(context.Background())
   192  			if err != nil {
   193  				b.Fatal(err)
   194  			}
   195  		}
   196  	})
   197  }
   198  
   199  // MasterSlavesMemoryDB 返回一个基于内存的 MasterSlaveDB,它使用的是 sqlite3 内存模式。
   200  func MasterSlavesMemoryDB() *masterslave.MasterSlavesDB {
   201  	db, err := sql.Open("sqlite3", "file:test.db?cache=shared&mode=memory")
   202  	if err != nil {
   203  		panic(err)
   204  	}
   205  	masterSlaveDB := masterslave.NewMasterSlavesDB(db)
   206  	return masterSlaveDB
   207  }