github.com/yongjacky/phoenix-go-orm-builder@v0.3.5/builder_b_test.go (about)

     1  // Copyright 2018 The Xorm Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package builder
     6  
     7  import (
     8  	"fmt"
     9  	"math/rand"
    10  	"testing"
    11  )
    12  
    13  type randGenConf struct {
    14  	allowCond     bool
    15  	allowJoin     bool
    16  	allowLimit    bool
    17  	allowUnion    bool
    18  	allowHaving   bool
    19  	allowGroupBy  bool
    20  	allowOrderBy  bool
    21  	allowSubQuery bool
    22  }
    23  
    24  var expectedValues = []interface{}{
    25  	"dangerous", "fun", "degree", "hospital", "horseshoe", "summit", "parallel", "height", "recommend", "invite",
    26  	0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    27  
    28  var queryFields = []string{"f1", "f2", "f2", "f4", "f5", "f6", "f7", "f8", "f9"}
    29  
    30  func BenchmarkSelect_Simple(b *testing.B) {
    31  	rgc := randGenConf{allowCond: true}
    32  	b.ResetTimer()
    33  	for i := 0; i < b.N; i++ {
    34  		randQuery("", &rgc).ToSQL()
    35  	}
    36  }
    37  
    38  func BenchmarkSelect_SubQuery(b *testing.B) {
    39  	rgc := randGenConf{allowSubQuery: true, allowCond: true, allowGroupBy: true, allowHaving: true, allowOrderBy: true}
    40  	b.ResetTimer()
    41  	for i := 0; i < b.N; i++ {
    42  		randQuery("", &rgc).ToSQL()
    43  	}
    44  }
    45  
    46  func BenchmarkSelect_SelectConditional4Oracle(b *testing.B) {
    47  	rgc := randGenConf{allowLimit: true, allowCond: true, allowGroupBy: true, allowHaving: true, allowOrderBy: true}
    48  	for i := 0; i < b.N; i++ {
    49  		randQuery(ORACLE, &rgc).ToSQL()
    50  	}
    51  }
    52  
    53  func BenchmarkSelect_SelectConditional4Mssql(b *testing.B) {
    54  	rgc := randGenConf{allowLimit: true, allowCond: true, allowGroupBy: true, allowHaving: true, allowOrderBy: true}
    55  	b.ResetTimer()
    56  	for i := 0; i < b.N; i++ {
    57  		randQuery(MSSQL, &rgc).ToSQL()
    58  	}
    59  }
    60  
    61  func BenchmarkSelect_SelectConditional4MysqlLike(b *testing.B) {
    62  	rgc := randGenConf{allowLimit: true, allowCond: true, allowGroupBy: true, allowHaving: true, allowOrderBy: true}
    63  	b.ResetTimer()
    64  	for i := 0; i < b.N; i++ {
    65  		randQuery(MYSQL, &rgc).ToSQL()
    66  	}
    67  }
    68  
    69  func BenchmarkSelect_SelectConditional4Mixed(b *testing.B) {
    70  	rgc := randGenConf{allowLimit: true, allowCond: true, allowGroupBy: true, allowHaving: true, allowOrderBy: true}
    71  	b.ResetTimer()
    72  	for i := 0; i < b.N; i++ {
    73  		randQuery(randDialect(), &rgc).ToSQL()
    74  	}
    75  }
    76  
    77  func BenchmarkSelect_SelectComplex4Oracle(b *testing.B) {
    78  	rgc := randGenConf{
    79  		allowLimit: true, allowCond: true,
    80  		allowGroupBy: true, allowHaving: true,
    81  		allowOrderBy: true, allowSubQuery: true,
    82  	}
    83  	for i := 0; i < b.N; i++ {
    84  		randQuery(ORACLE, &rgc).ToSQL()
    85  	}
    86  }
    87  
    88  func BenchmarkSelect_SelectComplex4Mssql(b *testing.B) {
    89  	rgc := randGenConf{
    90  		allowLimit: true, allowCond: true,
    91  		allowGroupBy: true, allowHaving: true,
    92  		allowOrderBy: true, allowSubQuery: true,
    93  	}
    94  	b.ResetTimer()
    95  	for i := 0; i < b.N; i++ {
    96  		randQuery(MSSQL, &rgc).ToSQL()
    97  	}
    98  }
    99  
   100  func BenchmarkSelect_SelectComplex4MysqlLike(b *testing.B) {
   101  	rgc := randGenConf{
   102  		allowLimit: true, allowCond: true,
   103  		allowGroupBy: true, allowHaving: true,
   104  		allowOrderBy: true, allowSubQuery: true,
   105  	}
   106  	b.ResetTimer()
   107  	for i := 0; i < b.N; i++ {
   108  		randQuery(MYSQL, &rgc).ToSQL()
   109  	}
   110  }
   111  
   112  func BenchmarkSelect_SelectComplex4MysqlMixed(b *testing.B) {
   113  	rgc := randGenConf{
   114  		allowLimit: true, allowCond: true,
   115  		allowGroupBy: true, allowHaving: true,
   116  		allowOrderBy: true, allowSubQuery: true,
   117  	}
   118  	b.ResetTimer()
   119  	for i := 0; i < b.N; i++ {
   120  		randQuery(randDialect(), &rgc).ToSQL()
   121  	}
   122  }
   123  
   124  func BenchmarkInsert(b *testing.B) {
   125  	rgc := randGenConf{allowCond: true}
   126  	b.ResetTimer()
   127  	for i := 0; i < b.N; i++ {
   128  		randInsertByCondition(&rgc).ToSQL()
   129  	}
   130  }
   131  
   132  func BenchmarkUpdate(b *testing.B) {
   133  	rgc := randGenConf{allowCond: true}
   134  	b.ResetTimer()
   135  	for i := 0; i < b.N; i++ {
   136  		randUpdateByCondition(&rgc).ToSQL()
   137  	}
   138  }
   139  
   140  // randQuery Generate a basic query for benchmark test. But be careful it's not a executable SQL in real db.
   141  func randQuery(dialect string, rgc *randGenConf) *Builder {
   142  	b := randSelectByCondition(dialect, rgc)
   143  	isUnionized := rgc.allowUnion && rand.Intn(1000) >= 500
   144  	if isUnionized {
   145  		r := rand.Intn(3) + 1
   146  		for i := r; i < r; i++ {
   147  			b = b.Union("all", randSelectByCondition(dialect, rgc))
   148  		}
   149  	}
   150  
   151  	if isUnionized && rgc.allowLimit && rand.Intn(1000) >= 500 {
   152  		b = randLimit(Dialect(dialect).Select().From(b, "t"))
   153  	}
   154  
   155  	return b
   156  }
   157  
   158  func randInsertByCondition(rgc *randGenConf) *Builder {
   159  	fields := randSelects()
   160  
   161  	times := rand.Intn(10) + 1
   162  
   163  	eqs := Eq{}
   164  	for i := 0; i < times; i++ {
   165  		eqs[fields[rand.Intn(len(fields))]] = "expected"
   166  	}
   167  
   168  	b := Insert(eqs).From("table1")
   169  
   170  	if rgc.allowCond && rand.Intn(1000) >= 500 {
   171  		b = b.Where(randCond(b.selects, 3))
   172  	}
   173  
   174  	return b
   175  }
   176  
   177  func randUpdateByCondition(rgc *randGenConf) *Builder {
   178  	fields := randSelects()
   179  
   180  	times := rand.Intn(10) + 1
   181  
   182  	eqs := Eq{}
   183  	for i := 0; i < times; i++ {
   184  		eqs[fields[rand.Intn(len(fields))]] = randVal()
   185  	}
   186  
   187  	b := Update(eqs).From("table1")
   188  
   189  	if rgc.allowCond && rand.Intn(1000) >= 500 {
   190  		b.Where(randCond(fields, 3))
   191  	}
   192  
   193  	return b
   194  }
   195  
   196  func randSelectByCondition(dialect string, rgc *randGenConf) *Builder {
   197  	var b *Builder
   198  	if rgc.allowSubQuery {
   199  		cpRgc := *rgc
   200  		cpRgc.allowSubQuery = false
   201  		b = Dialect(dialect).Select(randSelects()...).From(randQuery(dialect, &cpRgc), randTableName(0))
   202  	} else {
   203  		b = Dialect(dialect).Select(randSelects()...).From(randTableName(0))
   204  	}
   205  	if rgc.allowJoin {
   206  		b = randJoin(b, 3)
   207  	}
   208  	if rgc.allowCond && rand.Intn(1000) >= 500 {
   209  		b = b.Where(randCond(b.selects, 3))
   210  	}
   211  	if rgc.allowLimit && rand.Intn(1000) >= 500 {
   212  		b = randLimit(b)
   213  	}
   214  	if rgc.allowOrderBy && rand.Intn(1000) >= 500 {
   215  		b = randOrderBy(b)
   216  	}
   217  	if rgc.allowHaving && rand.Intn(1000) >= 500 {
   218  		b = randHaving(b)
   219  	}
   220  	if rgc.allowGroupBy && rand.Intn(1000) >= 500 {
   221  		b = randGroupBy(b)
   222  	}
   223  
   224  	return b
   225  }
   226  
   227  func randDialect() string {
   228  	dialects := []string{MYSQL, ORACLE, MSSQL, SQLITE, POSTGRES}
   229  
   230  	return dialects[rand.Intn(len(dialects))]
   231  }
   232  
   233  func randSelects() []string {
   234  	if rand.Intn(1000) > 900 {
   235  		return []string{"*"}
   236  	}
   237  
   238  	rdx := rand.Intn(len(queryFields) / 2)
   239  	return queryFields[rdx:]
   240  }
   241  
   242  func randTableName(offset int) string {
   243  	return fmt.Sprintf("table%v", rand.Intn(10)+offset)
   244  }
   245  
   246  func randJoin(b *Builder, lessThan int) *Builder {
   247  	if lessThan <= 0 {
   248  		return b
   249  	}
   250  
   251  	times := rand.Intn(lessThan)
   252  
   253  	for i := 0; i < times; i++ {
   254  		tableName := randTableName(i * 10)
   255  		b = b.Join("", tableName, fmt.Sprintf("%v.id = %v.id", b.TableName(), tableName))
   256  	}
   257  
   258  	return b
   259  }
   260  
   261  func randCond(selects []string, lessThan int) Cond {
   262  	if len(selects) <= 0 {
   263  		return nil
   264  	}
   265  
   266  	cond := NewCond()
   267  
   268  	times := rand.Intn(lessThan)
   269  	for i := 0; i < times; i++ {
   270  		cond = cond.And(Eq{selects[rand.Intn(len(selects))]: randVal()})
   271  	}
   272  
   273  	return cond
   274  }
   275  
   276  func randLimit(b *Builder) *Builder {
   277  	r := rand.Intn(1000) + 1
   278  	if r > 500 {
   279  		return b.Limit(r, 1000)
   280  	}
   281  	return b.Limit(r)
   282  }
   283  
   284  func randOrderBy(b *Builder) *Builder {
   285  	return b.OrderBy(fmt.Sprintf("%v ASC", b.selects[rand.Intn(len(b.selects))]))
   286  }
   287  
   288  func randHaving(b *Builder) *Builder {
   289  	return b.OrderBy(fmt.Sprintf("%v = %v", b.selects[rand.Intn(len(b.selects))], randVal()))
   290  }
   291  
   292  func randGroupBy(b *Builder) *Builder {
   293  	return b.GroupBy(fmt.Sprintf("%v = %v", b.selects[rand.Intn(len(b.selects))], randVal()))
   294  }
   295  
   296  func randVal() interface{} {
   297  	return expectedValues[rand.Intn(len(expectedValues))]
   298  }