github.com/kunlun-qilian/sqlx/v3@v3.0.0/builder/expr_test.go (about)

     1  package builder_test
     2  
     3  import (
     4  	"context"
     5  	"database/sql/driver"
     6  	"fmt"
     7  	"testing"
     8  
     9  	. "github.com/kunlun-qilian/sqlx/v3/builder"
    10  	. "github.com/kunlun-qilian/sqlx/v3/builder/buidertestingutils"
    11  	"github.com/onsi/gomega"
    12  )
    13  
    14  func TestResolveExpr(t *testing.T) {
    15  	t.Run("empty", func(t *testing.T) {
    16  		gomega.NewWithT(t).Expect(ResolveExpr(nil)).To(gomega.BeNil())
    17  	})
    18  }
    19  
    20  type Byte uint8
    21  
    22  func TestEx(t *testing.T) {
    23  	t.Run("empty query", func(t *testing.T) {
    24  		gomega.NewWithT(t).Expect(
    25  			Expr(""),
    26  		).To(BeExpr(""))
    27  	})
    28  
    29  	t.Run("flatten slice", func(t *testing.T) {
    30  		gomega.NewWithT(t).Expect(
    31  			Expr(`#ID IN (?)`, []int{28, 29, 30}),
    32  		).To(BeExpr("#ID IN (?,?,?)", 28, 29, 30))
    33  	})
    34  
    35  	t.Run("flatten slice for slice with named byte", func(t *testing.T) {
    36  		gomega.NewWithT(t).Expect(
    37  			And(
    38  				And(nil, Col("f_id").In([]int{28})),
    39  				Col("f_id").In([]Byte{28}),
    40  			),
    41  		).To(BeExpr("((f_id IN (?))) AND (f_id IN (?))", 28, Byte(28)))
    42  	})
    43  
    44  	t.Run("flatten should skip for bytes", func(t *testing.T) {
    45  		gomega.NewWithT(t).Expect(
    46  			Expr(`#ID = (?)`, []byte("")),
    47  		).To(BeExpr("#ID = (?)", []byte("")))
    48  	})
    49  
    50  	t.Run("flatten with sub expr ", func(t *testing.T) {
    51  		gomega.NewWithT(t).Expect(
    52  			Expr(`#ID = ?`, Expr("#ID + ?", 1)),
    53  		).To(BeExpr("#ID = #ID + ?", 1))
    54  	})
    55  
    56  	t.Run("flatten with ValuerExpr", func(t *testing.T) {
    57  		gomega.NewWithT(t).Expect(
    58  			Expr(`#Point = ?`, Point{1, 1}),
    59  		).To(BeExpr("#Point = ST_GeomFromText(?)", Point{1, 1}))
    60  	})
    61  }
    62  
    63  func BenchmarkEx(b *testing.B) {
    64  	b.Run("empty query", func(b *testing.B) {
    65  		for i := 0; i < b.N; i++ {
    66  			_ = Expr("").Ex(context.Background())
    67  		}
    68  	})
    69  
    70  	b.Run("flatten slice", func(b *testing.B) {
    71  		for i := 0; i < b.N; i++ {
    72  			Expr(`#ID IN (?)`, []int{28, 29, 30}).Ex(context.Background())
    73  		}
    74  	})
    75  
    76  	b.Run("flatten with sub expr", func(b *testing.B) {
    77  		b.Run("raw", func(b *testing.B) {
    78  			eb := Expr("")
    79  			eb.Grow(2)
    80  
    81  			eb.WriteQuery("#ID > ?")
    82  			eb.WriteQuery(" AND ")
    83  			eb.WriteQuery("#ID < ?")
    84  
    85  			eb.AppendArgs(1, 10)
    86  
    87  			rawBuild := func() *Ex {
    88  				return eb.Ex(context.Background())
    89  			}
    90  
    91  			clone := func(ex *Ex) *Ex {
    92  				return Expr(ex.Query(), ex.Args()...).Ex(context.Background())
    93  			}
    94  
    95  			b.Run("clone", func(b *testing.B) {
    96  				ex := rawBuild()
    97  
    98  				for i := 0; i < b.N; i++ {
    99  					_ = clone(ex)
   100  				}
   101  			})
   102  		})
   103  
   104  		b.Run("IsNilExpr", func(b *testing.B) {
   105  			for i := 0; i < b.N; i++ {
   106  				IsNilExpr(Expr(`#ID > ?`, 1))
   107  			}
   108  		})
   109  
   110  		b.Run("by chain", func(b *testing.B) {
   111  			for i := 0; i < b.N; i++ {
   112  				e := AsCond(Expr(`#ID > ?`, 1)).And(AsCond(Expr(`#ID < ?`, 10)))
   113  				e.Ex(context.Background())
   114  			}
   115  		})
   116  
   117  		b.Run("by expr", func(b *testing.B) {
   118  			for i := 0; i < b.N; i++ {
   119  				e := And(
   120  					Col("f_id").Lt(0),
   121  					Col("f_id").In([]int{1, 2, 3}),
   122  				)
   123  				e.Ex(context.Background())
   124  			}
   125  		})
   126  
   127  		b.Run("by expr without re created", func(b *testing.B) {
   128  			left := Col("f_id").Lt(0)
   129  			right := Col("f_id").In([]int{1, 2, 3})
   130  
   131  			b.Run("single", func(b *testing.B) {
   132  				for i := 0; i < b.N; i++ {
   133  					left.Ex(context.Background())
   134  				}
   135  			})
   136  
   137  			b.Run("composed", func(b *testing.B) {
   138  				e := And(left, left, right, right)
   139  
   140  				b.Log(e.Ex(context.Background()).Query())
   141  
   142  				for i := 0; i < b.N; i++ {
   143  					e.Ex(context.Background())
   144  				}
   145  			})
   146  		})
   147  	})
   148  }
   149  
   150  type Point struct {
   151  	X float64
   152  	Y float64
   153  }
   154  
   155  func (Point) DataType(engine string) string {
   156  	return "POINT"
   157  }
   158  
   159  func (Point) ValueEx() string {
   160  	return `ST_GeomFromText(?)`
   161  }
   162  
   163  func (p Point) Value() (driver.Value, error) {
   164  	return fmt.Sprintf("POINT(%v %v)", p.X, p.Y), nil
   165  }