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 3 commits
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ We support and actively test against certain third-party clients to ensure compa
- `FLOOR(number)`: Return the largest integer value that is less than or equal to `number`.
- `ROUND(number, decimals)`: Round the `number` to `decimals` decimal places.
- `CONNECTION_ID()`: Return the current connection ID.
- `SOUNDEX(str)`: Returns the soundex of a string.

## Example

Expand Down
1 change: 1 addition & 0 deletions SUPPORTED.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
- ROUND
- COALESCE
- CONNECTION_ID
- SOUNDEX

## Time functions
- DAY
Expand Down
1 change: 1 addition & 0 deletions sql/expression/function/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,5 @@ var Defaults = sql.Functions{
"coalesce": sql.FunctionN(NewCoalesce),
"json_extract": sql.FunctionN(NewJSONExtract),
"connection_id": sql.Function0(NewConnectionID),
"soundex": sql.Function1(NewSoundex),
}
102 changes: 102 additions & 0 deletions sql/expression/function/soundex.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package function

import (
"fmt"
"strings"
"unicode"

"gopkg.in/src-d/go-mysql-server.v0/sql"
"gopkg.in/src-d/go-mysql-server.v0/sql/expression"
)

// Soundex is a function that returns the soundex of a string. Two strings that
// sound almost the same should have identical soundex strings. A standard
// soundex string is four characters long, but the SOUNDEX() function returns
// an arbitrarily long string.
type Soundex struct {
expression.UnaryExpression
}

// NewSoundex creates a new Soundex expression.
func NewSoundex(e sql.Expression) sql.Expression {
return &Soundex{expression.UnaryExpression{Child: e}}
}

// Eval implements the Expression interface.
func (s *Soundex) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) {
v, err := s.Child.Eval(ctx, row)
if err != nil {
return nil, err
}

if v == nil {
return nil, nil
}

v, err = sql.Text.Convert(v)
if err != nil {
return nil, err
}

var b strings.Builder
var last rune
for _, c := range strings.ToUpper(v.(string)) {
if last == 0 && !unicode.IsLetter(c) {
continue
}
code := s.code(c)
if last == 0 {
b.WriteRune(c)
last = code
continue
}
if code == '0' || code == last {
continue
}
b.WriteRune(code)
last = code
}
if b.Len() == 0 {
return "", nil
}
for i := len([]rune(b.String())); i < 4; i++ {
b.WriteRune('0')
}
return b.String(), nil
}

func (s *Soundex) code(c rune) rune {
switch c {
case 'B', 'F', 'P', 'V':
return '1'
case 'C', 'G', 'J', 'K', 'Q', 'S', 'X', 'Z':
return '2'
case 'D', 'T':
return '3'
case 'L':
return '4'
case 'M', 'N':
return '5'
case 'R':
return '6'
}
return '0'
}

func (s *Soundex) String() string {
return fmt.Sprintf("SOUNDEX(%s)", s.Child)
}

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

// Type implements the Expression interface.
func (s *Soundex) Type() sql.Type {
return s.Child.Type()
}
49 changes: 49 additions & 0 deletions sql/expression/function/soundex_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package function

import (
"testing"

"github.com/stretchr/testify/require"
"gopkg.in/src-d/go-mysql-server.v0/sql"
"gopkg.in/src-d/go-mysql-server.v0/sql/expression"
)

func TestSoundex(t *testing.T) {
testCases := []struct {
name string
rowType sql.Type
row sql.Row
expected interface{}
}{
{"text nil", sql.Text, sql.NewRow(nil), nil},
{"text empty", sql.Text, sql.NewRow(""), ""},
{"text ignored character", sql.Text, sql.NewRow("-"), ""},
{"text runes", sql.Text, sql.NewRow("日本語"), "日000"},
{"text Hello ok", sql.Text, sql.NewRow("Hello"), "H400"},
{"text Quadratically ok", sql.Text, sql.NewRow("Quadratically"), "Q36324"},
{"text Lee ok", sql.Text, sql.NewRow("Lee"), "L000"},
{"text McKnockitter ok", sql.Text, sql.NewRow("McKnockitter"), "M25236"},
{"text Honeyman ok", sql.Text, sql.NewRow("Honeyman"), "H500"},
{"text Munn ok", sql.Text, sql.NewRow("Munn"), "M000"},
{"text Poppett ok", sql.Text, sql.NewRow("Poppett"), "P300"},
{"text Peachman ok", sql.Text, sql.NewRow("Peachman"), "P250"},
{"text Cochrane ok", sql.Text, sql.NewRow("Cochrane"), "C650"},
{"text Chesley ok", sql.Text, sql.NewRow("Chesley"), "C400"},
{"text Tachenion ok", sql.Text, sql.NewRow("Tachenion"), "T250"},
{"text Wilcox ok", sql.Text, sql.NewRow("Wilcox"), "W420"},
{"binary ok", sql.Blob, sql.NewRow([]byte("Harvey")), "H610"},
{"other type", sql.Int32, sql.NewRow(int32(1)), ""},
}

for _, tt := range testCases {
f := NewSoundex(expression.NewGetField(0, tt.rowType, "", true))

t.Run(tt.name, func(t *testing.T) {
require.Equal(t, tt.expected, eval(t, f, tt.row))
})

req := require.New(t)
req.True(f.IsNullable())
req.Equal(tt.rowType, f.Type())
}
}
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