Skip to content
This repository was archived by the owner on Jan 28, 2021. It is now read-only.

sql, function: add weekday and dayofweek #507

Merged
merged 11 commits into from
Oct 31, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
sql, function: add weekday and dayofweek
Signed-off-by: bake <bake@192k.pw>
  • Loading branch information
bake committed Oct 26, 2018
commit 9c054d21ceb448ddf9116537864a2dfb895cf4dc
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ We support and actively test against certain third-party clients to ensure compa

- `IS_BINARY(blob)`: Returns whether a BLOB is a binary file or not.
- `SUBSTRING(str,pos)`, `SUBSTRING(str,pos,len)`: Return a substring from the provided string.
- Date and Timestamp functions: `YEAR(date)`, `MONTH(date)`, `DAY(date)`, `HOUR(date)`, `MINUTE(date)`, `SECOND(date)`, `DAYOFYEAR(date)`.
- Date and Timestamp functions: `YEAR(date)`, `MONTH(date)`, `DAY(date)`, `WEEKDAY(date)`, `HOUR(date)`, `MINUTE(date)`, `SECOND(date)`, `DAYOFWEEK(date)`, `DAYOFYEAR(date)`.
- `ARRAY_LENGTH(json)`: If the json representation is an array, this function returns its size.
- `SPLIT(str,sep)`: Receives a string and a separator and returns the parts of the string split by the separator as a JSON array of strings.
- `CONCAT(...)`: Concatenate any group of fields into a single string.
Expand Down
2 changes: 2 additions & 0 deletions SUPPORTED.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@

## Time functions
- DAY
- WEEKDAY
- DAYOFWEEK
- DAYOFYEAR
- HOUR
- MINUTE
Expand Down
2 changes: 2 additions & 0 deletions sql/expression/function/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@ var Defaults = sql.Functions{
"year": sql.Function1(NewYear),
"month": sql.Function1(NewMonth),
"day": sql.Function1(NewDay),
"weekday": sql.Function1(NewWeekday),
"hour": sql.Function1(NewHour),
"minute": sql.Function1(NewMinute),
"second": sql.Function1(NewSecond),
"dayofweek": sql.Function1(NewDayOfWeek),
"dayofyear": sql.Function1(NewDayOfYear),
"array_length": sql.Function1(NewArrayLength),
"split": sql.Function2(NewSplit),
Expand Down
64 changes: 64 additions & 0 deletions sql/expression/function/time.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,37 @@ func (d *Day) TransformUp(f sql.TransformExprFunc) (sql.Expression, error) {
return f(NewDay(child))
}

// Weekday is a function that returns the weekday of a date where 0 = Monday,
// ..., 6 = Sunday.
type Weekday struct {
expression.UnaryExpression
}

// NewWeekday creates a new Weekday UDF.
func NewWeekday(date sql.Expression) sql.Expression {
return &Weekday{expression.UnaryExpression{Child: date}}
}

func (d *Weekday) String() string { return fmt.Sprintf("WEEKDAY(%s)", d.Child) }

// Type implements the Expression interface.
func (d *Weekday) Type() sql.Type { return sql.Int32 }

// Eval implements the Expression interface.
func (d *Weekday) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) {
return getDatePart(ctx, d.UnaryExpression, row, weekday)
}

// TransformUp implements the Expression interface.
func (d *Weekday) TransformUp(f sql.TransformExprFunc) (sql.Expression, error) {
child, err := d.Child.TransformUp(f)
if err != nil {
return nil, err
}

return f(NewWeekday(child))
}

// Hour is a function that returns the hour of a date.
type Hour struct {
expression.UnaryExpression
Expand Down Expand Up @@ -214,6 +245,37 @@ func (s *Second) TransformUp(f sql.TransformExprFunc) (sql.Expression, error) {
return f(NewSecond(child))
}

// DayOfWeek is a function that returns the day of the week from a date where
// 1 = Sunday, ..., 7 = Saturday.
type DayOfWeek struct {
expression.UnaryExpression
}

// NewDayOfWeek creates a new DayOfWeek UDF.
func NewDayOfWeek(date sql.Expression) sql.Expression {
return &DayOfWeek{expression.UnaryExpression{Child: date}}
}

func (d *DayOfWeek) String() string { return fmt.Sprintf("DAYOFWEEK(%s)", d.Child) }

// Type implements the Expression interface.
func (d *DayOfWeek) Type() sql.Type { return sql.Int32 }

// Eval implements the Expression interface.
func (d *DayOfWeek) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) {
return getDatePart(ctx, d.UnaryExpression, row, dayOfWeek)
}

// TransformUp implements the Expression interface.
func (d *DayOfWeek) TransformUp(f sql.TransformExprFunc) (sql.Expression, error) {
child, err := d.Child.TransformUp(f)
if err != nil {
return nil, err
}

return f(NewDayOfWeek(child))
}

// DayOfYear is a function that returns the day of the year from a date.
type DayOfYear struct {
expression.UnaryExpression
Expand Down Expand Up @@ -258,8 +320,10 @@ var (
year = datePartFunc((time.Time).Year)
month = datePartFunc(func(t time.Time) int { return int(t.Month()) })
day = datePartFunc((time.Time).Day)
weekday = datePartFunc(func(t time.Time) int { return (int(t.Weekday()) + 6) % 7 })
hour = datePartFunc((time.Time).Hour)
minute = datePartFunc((time.Time).Minute)
second = datePartFunc((time.Time).Second)
dayOfWeek = datePartFunc(func(t time.Time) int { return int(t.Weekday()) + 1%7 })
dayOfYear = datePartFunc((time.Time).YearDay)
)
62 changes: 62 additions & 0 deletions sql/expression/function/time_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,37 @@ func TestTime_Day(t *testing.T) {
}
}

func TestTime_Weekday(t *testing.T) {
f := NewWeekday(expression.NewGetField(0, sql.Text, "foo", false))
ctx := sql.NewEmptyContext()

testCases := []struct {
name string
row sql.Row
expected interface{}
err bool
}{
{"null date", sql.NewRow(nil), nil, false},
{"invalid type", sql.NewRow([]byte{0, 1, 2}), nil, false},
{"date as string", sql.NewRow(stringDate), int32(1), false},
{"date as time", sql.NewRow(time.Now()), int32(time.Now().UTC().Weekday()+6) % 7, false},
{"date as unix timestamp", sql.NewRow(int64(tsDate)), int32(6), false},
}

for _, tt := range testCases {
t.Run(tt.name, func(t *testing.T) {
require := require.New(t)
val, err := f.Eval(ctx, tt.row)
if tt.err {
require.Error(err)
} else {
require.NoError(err)
require.Equal(tt.expected, val)
}
})
}
}

func TestTime_Hour(t *testing.T) {
f := NewHour(expression.NewGetField(0, sql.Text, "foo", false))
ctx := sql.NewEmptyContext()
Expand Down Expand Up @@ -199,6 +230,37 @@ func TestTime_Second(t *testing.T) {
}
}

func TestTime_DayOfWeek(t *testing.T) {
f := NewDayOfWeek(expression.NewGetField(0, sql.Text, "foo", false))
ctx := sql.NewEmptyContext()

testCases := []struct {
name string
row sql.Row
expected interface{}
err bool
}{
{"null date", sql.NewRow(nil), nil, false},
{"invalid type", sql.NewRow([]byte{0, 1, 2}), nil, false},
{"date as string", sql.NewRow(stringDate), int32(3), false},
{"date as time", sql.NewRow(time.Now()), int32(time.Now().UTC().Weekday()+1) % 7, false},
{"date as unix timestamp", sql.NewRow(int64(tsDate)), int32(1), false},
}

for _, tt := range testCases {
t.Run(tt.name, func(t *testing.T) {
require := require.New(t)
val, err := f.Eval(ctx, tt.row)
if tt.err {
require.Error(err)
} else {
require.NoError(err)
require.Equal(tt.expected, val)
}
})
}
}

func TestTime_DayOfYear(t *testing.T) {
f := NewDayOfYear(expression.NewGetField(0, sql.Text, "foo", false))
ctx := sql.NewEmptyContext()
Expand Down
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy