Skip to content

Commit a989023

Browse files
authored
Merge pull request #194 from erizocosmico/feature/udf-get-language
internal/function: implement language function
2 parents 6513ca1 + bf625c4 commit a989023

File tree

113 files changed

+342311
-1
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

113 files changed

+342311
-1
lines changed

Gopkg.lock

Lines changed: 23 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Gopkg.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,7 @@
4141
[[override]]
4242
name = "github.com/satori/go.uuid"
4343
revision = "36e9d2ebbde5e3f13ab2e25625fd453271d6522e"
44+
45+
[[constraint]]
46+
name = "gopkg.in/src-d/enry.v1"
47+
version = "1.6.3"

internal/function/language.go

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
package function
2+
3+
import (
4+
"fmt"
5+
6+
enry "gopkg.in/src-d/enry.v1"
7+
"gopkg.in/src-d/go-mysql-server.v0/sql"
8+
)
9+
10+
// Language gets the language of a file given its path and
11+
// the optional content of the file.
12+
type Language struct {
13+
Left sql.Expression
14+
Right sql.Expression
15+
}
16+
17+
// NewLanguage creates a new Language UDF.
18+
func NewLanguage(args ...sql.Expression) (sql.Expression, error) {
19+
var left, right sql.Expression
20+
switch len(args) {
21+
case 1:
22+
left = args[0]
23+
case 2:
24+
left = args[0]
25+
right = args[1]
26+
default:
27+
return nil, sql.ErrInvalidArgumentNumber.New("1 or 2", len(args))
28+
}
29+
30+
return &Language{left, right}, nil
31+
}
32+
33+
// Resolved implements the Expression interface.
34+
func (f *Language) Resolved() bool {
35+
return f.Left.Resolved() && (f.Right == nil || f.Right.Resolved())
36+
}
37+
38+
func (f *Language) String() string {
39+
if f.Right == nil {
40+
return fmt.Sprintf("language(%s)", f.Left)
41+
}
42+
return fmt.Sprintf("language(%s, %s)", f.Left, f.Right)
43+
}
44+
45+
// IsNullable implements the Expression interface.
46+
func (f *Language) IsNullable() bool {
47+
return f.Left.IsNullable() || (f.Right != nil && f.Right.IsNullable())
48+
}
49+
50+
// Type implements the Expression interface.
51+
func (Language) Type() sql.Type {
52+
return sql.Text
53+
}
54+
55+
// TransformUp implements the Expression interface.
56+
func (f *Language) TransformUp(fn sql.TransformExprFunc) (sql.Expression, error) {
57+
left, err := f.Left.TransformUp(fn)
58+
if err != nil {
59+
return nil, err
60+
}
61+
62+
var right sql.Expression
63+
if f.Right != nil {
64+
right, err = f.Right.TransformUp(fn)
65+
if err != nil {
66+
return nil, err
67+
}
68+
}
69+
70+
return fn(&Language{left, right})
71+
}
72+
73+
// Eval implements the Expression interface.
74+
func (f *Language) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) {
75+
left, err := f.Left.Eval(ctx, row)
76+
if err != nil {
77+
return nil, err
78+
}
79+
80+
if left == nil {
81+
return nil, nil
82+
}
83+
84+
left, err = sql.Text.Convert(left)
85+
if err != nil {
86+
return nil, err
87+
}
88+
89+
path := left.(string)
90+
var blob []byte
91+
92+
if f.Right != nil {
93+
right, err := f.Right.Eval(ctx, row)
94+
if err != nil {
95+
return nil, err
96+
}
97+
98+
if right == nil {
99+
return nil, nil
100+
}
101+
102+
right, err = sql.Blob.Convert(right)
103+
if err != nil {
104+
return nil, err
105+
}
106+
107+
blob = right.([]byte)
108+
}
109+
110+
return enry.GetLanguage(path, blob), nil
111+
}
112+
113+
// Children implements the Expression interface.
114+
func (f *Language) Children() []sql.Expression {
115+
if f.Right == nil {
116+
return []sql.Expression{f.Left}
117+
}
118+
119+
return []sql.Expression{f.Left, f.Right}
120+
}

internal/function/language_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package function
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
errors "gopkg.in/src-d/go-errors.v1"
8+
"gopkg.in/src-d/go-mysql-server.v0/sql"
9+
"gopkg.in/src-d/go-mysql-server.v0/sql/expression"
10+
)
11+
12+
func TestLanguage(t *testing.T) {
13+
testCases := []struct {
14+
name string
15+
row sql.Row
16+
expected interface{}
17+
err *errors.Kind
18+
}{
19+
{"left is null", sql.NewRow(nil), nil, nil},
20+
{"right is null", sql.NewRow("foo", nil), nil, nil},
21+
{"both are null", sql.NewRow(nil, nil), nil, nil},
22+
{"only path is given", sql.NewRow("foo.rb"), "Ruby", nil},
23+
{"too many args given", sql.NewRow("foo.rb", "bar", "baz"), nil, sql.ErrInvalidArgumentNumber},
24+
{"path and blob are given", sql.NewRow("foo", "#!/usr/bin/env python\n\nprint 'foo'"), "Python", nil},
25+
{"invalid blob type given", sql.NewRow("foo", 5), nil, sql.ErrInvalidType},
26+
}
27+
28+
for _, tt := range testCases {
29+
t.Run(tt.name, func(t *testing.T) {
30+
require := require.New(t)
31+
32+
var args = make([]sql.Expression, len(tt.row))
33+
for i := range tt.row {
34+
args[i] = expression.NewGetField(i, sql.Text, "", false)
35+
}
36+
37+
f, err := NewLanguage(args...)
38+
if err == nil {
39+
var val interface{}
40+
val, err = f.Eval(nil, tt.row)
41+
if tt.err == nil {
42+
require.NoError(err)
43+
require.Equal(tt.expected, val)
44+
}
45+
}
46+
47+
if tt.err != nil {
48+
require.Error(err)
49+
require.True(tt.err.Is(err))
50+
}
51+
})
52+
}
53+
}

internal/function/registry.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ var Functions = sql.Functions{
88
"commit_has_blob": sql.Function2(NewCommitHasBlob),
99
"history_idx": sql.Function2(NewHistoryIdx),
1010
"commit_has_tree": sql.Function2(NewCommitHasTree),
11+
"language": sql.FunctionN(NewLanguage),
1112
}

vendor/github.com/toqueteos/trie/LICENSE.txt

Lines changed: 22 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/toqueteos/trie/README.md

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/toqueteos/trie/example_test.go

Lines changed: 66 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)