From 0a3e488af948cbd22aa11f53f79a18befdd46b00 Mon Sep 17 00:00:00 2001 From: SumLare Date: Sun, 7 Oct 2018 15:22:04 +0300 Subject: [PATCH 1/2] Add like function implementation --- pkg/stdlib/strings/like.go | 47 +++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/pkg/stdlib/strings/like.go b/pkg/stdlib/strings/like.go index c463967f..b0463196 100644 --- a/pkg/stdlib/strings/like.go +++ b/pkg/stdlib/strings/like.go @@ -2,12 +2,18 @@ package strings import ( "context" + "unicode" + "github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/runtime/values" ) /* * Checks whether the pattern search is contained in the string text, using wildcard matching. + * @param text (String) - The string to search in. + * @param search (String) - A search pattern that can contain the wildcard characters. + * @param caseInsensitive (Boolean) - If set to true, the matching will be case-insensitive. The default is false. + * @return (Boolean) - Returns true if the pattern is contained in text, and false otherwise. */ func Like(_ context.Context, args ...core.Value) (core.Value, error) { err := core.ValidateArgs(args, 2, 3) @@ -16,5 +22,44 @@ func Like(_ context.Context, args ...core.Value) (core.Value, error) { return values.False, err } - return values.None, core.Error(core.ErrNotImplemented, "LIKE") + str := []rune(args[0].String()) + pattern := []rune(args[1].String()) + + if len(pattern) == 0 { + return values.NewBoolean(len(str) == 0), nil + } + + lookup := make([][]bool, len(str)+1) + + for i := range lookup { + lookup[i] = make([]bool, len(pattern)+1) + } + + lookup[0][0] = true + + for j := 1; j < len(pattern)+1; j++ { + if pattern[j-1] == '%' { + lookup[0][j] = lookup[0][j-1] + } + } + + for i := 1; i < len(str)+1; i++ { + for j := 1; j < len(pattern)+1; j++ { + if pattern[j-1] == '%' { + lookup[i][j] = lookup[i][j-1] || lookup[i-1][j] + } else if pattern[j-1] == '_' || str[i-1] == pattern[j-1] { + lookup[i][j] = lookup[i-1][j-1] + } else if len(args) > 2 { + if args[2] == values.True && unicode.ToLower(str[i-1]) == unicode.ToLower(pattern[j-1]) { + lookup[i][j] = lookup[i-1][j-1] + } + } else { + lookup[i][j] = false + } + } + } + + matched := lookup[len(str)][len(pattern)] + + return values.NewBoolean(matched), nil } From c97e12d90f7d728b9dc3fdee680bac04aecc0f98 Mon Sep 17 00:00:00 2001 From: SumLare Date: Sun, 7 Oct 2018 15:29:09 +0300 Subject: [PATCH 2/2] Add like function test --- pkg/stdlib/strings/like_test.go | 65 +++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/pkg/stdlib/strings/like_test.go b/pkg/stdlib/strings/like_test.go index 9c53d25e..99ea900b 100644 --- a/pkg/stdlib/strings/like_test.go +++ b/pkg/stdlib/strings/like_test.go @@ -1 +1,66 @@ package strings_test + +import ( + "context" + "testing" + + "github.com/MontFerret/ferret/pkg/runtime/values" + "github.com/MontFerret/ferret/pkg/stdlib/strings" + . "github.com/smartystreets/goconvey/convey" +) + +func TestLike(t *testing.T) { + Convey("When args are not passed", t, func() { + Convey("It should return an error", func() { + var err error + _, err = strings.Like(context.Background()) + + So(err, ShouldBeError) + + _, err = strings.Like(context.Background(), values.NewString("")) + + So(err, ShouldBeError) + }) + }) + + Convey("Should return true when matches with _ pattern", t, func() { + out, _ := strings.Like( + context.Background(), + values.NewString("cart"), + values.NewString("ca_t"), + ) + + So(out, ShouldEqual, true) + }) + + Convey("Should return true when matches with % pattern", t, func() { + out, _ := strings.Like( + context.Background(), + values.NewString("foo bar baz"), + values.NewString("%bar%"), + ) + + So(out, ShouldEqual, true) + }) + + Convey("Should return false when matches with no caseInsensitive parameter", t, func() { + out, _ := strings.Like( + context.Background(), + values.NewString("FoO bAr BaZ"), + values.NewString("fOo%bAz"), + ) + + So(out, ShouldEqual, false) + }) + + Convey("Should return true when matches with caseInsensitive parameter", t, func() { + out, _ := strings.Like( + context.Background(), + values.NewString("FoO bAr BaZ"), + values.NewString("fOo%bAz"), + values.True, + ) + + So(out, ShouldEqual, true) + }) +}