Add support for INTERVAL operator.

This commit is contained in:
zer0sub 2019-05-06 14:01:50 +02:00
parent 4f9323ddca
commit dd9b815dbb
4 changed files with 57 additions and 27 deletions

View file

@ -10,20 +10,25 @@ import (
type intervalExpression struct { type intervalExpression struct {
expressionInterfaceImpl expressionInterfaceImpl
duration time.Duration duration time.Duration
negative bool
} }
var intervalSep = ":" const intervalSep = ":"
func (c *intervalExpression) Serialize(out *queryData, options ...serializeOption) error { func (c *intervalExpression) Serialize(out *queryData, options ...serializeOption) error {
hours := c.duration / time.Hour
minutes := (c.duration % time.Hour) / time.Minute
sec := (c.duration % time.Minute) / time.Second
msec := (c.duration % time.Second) / time.Microsecond
out.WriteString("INTERVAL '") out.WriteString("INTERVAL '")
if c.negative {
duration := c.duration
if duration < 0 {
duration = -duration
out.WriteString("-") out.WriteString("-")
} }
hours := duration / time.Hour
minutes := (duration % time.Hour) / time.Minute
sec := (duration % time.Minute) / time.Second
msec := (duration % time.Second) / time.Microsecond
out.WriteString(strconv.FormatInt(int64(hours), 10)) out.WriteString(strconv.FormatInt(int64(hours), 10))
out.WriteString(intervalSep) out.WriteString(intervalSep)
out.WriteString(strconv.FormatInt(int64(minutes), 10)) out.WriteString(strconv.FormatInt(int64(minutes), 10))
@ -36,19 +41,16 @@ func (c *intervalExpression) Serialize(out *queryData, options ...serializeOptio
return nil return nil
} }
// Interval returns a representation of duration //// Interval returns a representation of duration
// in a form "INTERVAL `hour:min:sec:microsec` HOUR_MICROSECOND" //func Interval(duration time.Duration) Expression {
func Interval(duration time.Duration) Expression { // intervalExp := &intervalExpression{
negative := false // duration: duration,
if duration < 0 { // }
negative = true //
duration = -duration // intervalExp.expressionInterfaceImpl.parent = intervalExp
} //
return &intervalExpression{ // return intervalExp
duration: duration, //}
negative: negative,
}
}
var likeEscaper = strings.NewReplacer("_", "\\_", "%", "\\%") var likeEscaper = strings.NewReplacer("_", "\\_", "%", "\\%")

View file

@ -31,3 +31,14 @@ func TestCase2(t *testing.T) {
assert.NilError(t, err) assert.NilError(t, err)
assert.Equal(t, queryData.buff.String(), `(CASE table3.col1 WHEN $1 THEN table3.col1 + $2 WHEN $3 THEN table3.col1 + $4 ELSE $5 END)`) assert.Equal(t, queryData.buff.String(), `(CASE table3.col1 WHEN $1 THEN table3.col1 + $2 WHEN $3 THEN table3.col1 + $4 ELSE $5 END)`)
} }
func TestInterval(t *testing.T) {
query := INTERVAL(`6 years 5 months 4 days 3 hours 2 minutes 1 second`)
queryData := &queryData{}
err := query.Serialize(queryData)
assert.NilError(t, err)
assert.Equal(t, queryData.buff.String(), `INTERVAL $1`)
}

View file

@ -48,3 +48,25 @@ func (t *timeInterfaceImpl) LtEq(expression TimeExpression) BoolExpression {
func (t *timeInterfaceImpl) LtEqL(literal string) BoolExpression { func (t *timeInterfaceImpl) LtEqL(literal string) BoolExpression {
return LtEq(t.parent, Literal(literal)) return LtEq(t.parent, Literal(literal))
} }
//---------------------------------------------------//
type prefixTimeExpression struct {
expressionInterfaceImpl
timeInterfaceImpl
prefixExpression
}
func newPrefixTimeExpression(expression Expression, operator string) TimeExpression {
timeExpr := prefixTimeExpression{}
timeExpr.prefixExpression = newPrefixExpression(expression, operator)
timeExpr.expressionInterfaceImpl.parent = &timeExpr
timeExpr.timeInterfaceImpl.parent = &timeExpr
return &timeExpr
}
func INTERVAL(interval string) Expression {
return newPrefixTimeExpression(Literal(interval), "INTERVAL")
}

View file

@ -2,7 +2,6 @@ package tests
import ( import (
"fmt" "fmt"
"github.com/davecgh/go-spew/spew"
"github.com/sub0zero/go-sqlbuilder/sqlbuilder" "github.com/sub0zero/go-sqlbuilder/sqlbuilder"
"github.com/sub0zero/go-sqlbuilder/tests/.test_files/dvd_rental/dvds/model" "github.com/sub0zero/go-sqlbuilder/tests/.test_files/dvd_rental/dvds/model"
. "github.com/sub0zero/go-sqlbuilder/tests/.test_files/dvd_rental/dvds/table" . "github.com/sub0zero/go-sqlbuilder/tests/.test_files/dvd_rental/dvds/table"
@ -678,11 +677,10 @@ func TestSelectWithCase(t *testing.T) {
ORDER_BY(Payment.PaymentID.ASC()). ORDER_BY(Payment.PaymentID.ASC()).
LIMIT(20) LIMIT(20)
queryStr, args, err := query.Sql() queryStr, _, err := query.Sql()
assert.NilError(t, err) assert.NilError(t, err)
fmt.Println(queryStr) assert.Equal(t, queryStr, `SELECT (CASE payment.staff_id WHEN $1 THEN $2 WHEN $3 THEN $4 WHEN $5 THEN $6 ELSE $7 END) AS "staff_id_num" FROM dvds.payment ORDER BY payment.payment_id ASC LIMIT $8`)
fmt.Println(args)
dest := []struct { dest := []struct {
StaffIdNum string StaffIdNum string
@ -694,9 +692,6 @@ func TestSelectWithCase(t *testing.T) {
assert.Equal(t, len(dest), 20) assert.Equal(t, len(dest), 20)
assert.Equal(t, dest[0].StaffIdNum, "TWO") assert.Equal(t, dest[0].StaffIdNum, "TWO")
assert.Equal(t, dest[1].StaffIdNum, "ONE") assert.Equal(t, dest[1].StaffIdNum, "ONE")
spew.Dump(dest)
} }
func int16Ptr(i int16) *int16 { func int16Ptr(i int16) *int16 {