Skip to content

Commit

Permalink
Extend contains (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
deankarn committed Jul 29, 2022
1 parent 9b323a9 commit 0d3169d
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 33 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.4.0] - 2022-07-29
### Added
- The ability for CONTAINS_ANY and CONTAINS_ALL to check if a String contains any|all of the values
within an Array. Any non-string data types return a false.

## [0.3.2] - 2022-07-29
### Fixed
- && and || expression chaining.
Expand Down Expand Up @@ -39,7 +44,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Initial conversion from https://github.com/rust-playground/ksql.

[Unreleased]: https://github.com/go-playground/ksql/compare/v0.3.2...HEAD
[Unreleased]: https://github.com/go-playground/ksql/compare/v0.4.0...HEAD
[0.4.0]: https://github.com/go-playground/ksql/compare/v0.3.2...v0.4.0
[0.3.2]: https://github.com/go-playground/ksql/compare/v0.3.1...v0.3.2
[0.3.1]: https://github.com/go-playground/ksql/compare/v0.3.0...v0.3.1
[0.3.0]: https://github.com/go-playground/ksql/compare/v0.2.0...v0.3.0
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
ksql
=====
![Project status](https://img.shields.io/badge/version-0.3.2-green.svg)
![Project status](https://img.shields.io/badge/version-0.4.0-green.svg)
[![GoDoc](https://godoc.org/github.com/go-playground/ksql?status.svg)](https://pkg.go.dev/github.com/go-playground/ksql)
![License](https://img.shields.io/dub/l/vibe-d.svg)

Expand Down
87 changes: 56 additions & 31 deletions parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -1058,23 +1058,35 @@ func (c containsAny) Calculate(src []byte) (any, error) {
return nil, err
}

leftTypeOf := reflect.TypeOf(left)
typesEqual := leftTypeOf == reflect.TypeOf(right)

if !typesEqual && leftTypeOf.Kind() != reflect.Slice {
return nil, ErrUnsupportedTypeComparison{s: fmt.Sprintf("%s CONTAINS %s", left, right)}
}

switch l := left.(type) {
case string:

// betting that lists are short and so less expensive than iterating one to create a hash set
for _, c := range right.(string) {
for _, c2 := range l {
if c == c2 {
switch r := right.(type) {
case string:

// betting that lists are short and so less expensive than iterating one to create a hash set
for _, c := range r {
for _, c2 := range l {
if c == c2 {
return true, nil
}
}
}

case []any:
for _, v := range r {
s, ok := v.(string)
if !ok {
continue
}
if l == s {
return true, nil
}
}
return false, nil

default:
return nil, ErrUnsupportedTypeComparison{s: fmt.Sprintf("%s CONTAINS_ANY %s", left, right)}
}

case []any:
Expand All @@ -1098,10 +1110,13 @@ func (c containsAny) Calculate(src []byte) (any, error) {
}
}
}

default:
return nil, ErrUnsupportedTypeComparison{s: fmt.Sprintf("%s CONTAINS_ANY %s", left, right)}
}

default:
return nil, ErrUnsupportedTypeComparison{s: fmt.Sprintf("%s CONTAINS %s !", left, right)}
return nil, ErrUnsupportedTypeComparison{s: fmt.Sprintf("%s CONTAINS_ANY %s !", left, right)}
}
return false, nil
}
Expand All @@ -1123,55 +1138,65 @@ func (c containsAll) Calculate(src []byte) (any, error) {
return nil, err
}

leftTypeOf := reflect.TypeOf(left)
typesEqual := leftTypeOf == reflect.TypeOf(right)

if !typesEqual && leftTypeOf.Kind() != reflect.Slice {
return nil, ErrUnsupportedTypeComparison{s: fmt.Sprintf("%s CONTAINS %s", left, right)}
}

switch l := left.(type) {
case string:
// betting that lists are short and so less expensive than iterating one to create a hash set
OUTER1:
for _, c := range right.(string) {
for _, c2 := range l {
if c == c2 {
continue OUTER1
switch r := right.(type) {
case string:
// betting that lists are short and so less expensive than iterating one to create a hash set
OUTER1:
for _, c := range r {
for _, c2 := range l {
if c == c2 {
continue OUTER1
}
}
return false, nil
}
return false, nil

case []any:
for _, v := range r {
s, ok := v.(string)
if !ok || !strings.Contains(l, s) {
return false, nil
}
}
return true, nil

default:
return nil, ErrUnsupportedTypeComparison{s: fmt.Sprintf("%s CONTAINS_ALL %s", left, right)}
}

case []any:
switch r := right.(type) {
case []any:
// betting that lists are short and so less expensive than iterating one to create a hash set
OUTER2:
OUTER3:
for _, rv := range r {
for _, lv := range l {
if reflect.DeepEqual(rv, lv) {
continue OUTER2
continue OUTER3
}
}
return false, nil
}

case string:
// betting that lists are short and so less expensive than iterating one to create a hash set
OUTER3:
OUTER4:
for _, c := range r {
for _, v := range l {
if reflect.DeepEqual(string(c), v) {
continue OUTER3
continue OUTER4
}
}
return false, nil
}
default:
return nil, ErrUnsupportedTypeComparison{s: fmt.Sprintf("%s CONTAINS_ALL %s", left, right)}
}

default:
return nil, ErrUnsupportedTypeComparison{s: fmt.Sprintf("%s CONTAINS %s !", left, right)}
return nil, ErrUnsupportedTypeComparison{s: fmt.Sprintf("%s CONTAINS_ALL %s !", left, right)}
}
return true, nil
}
Expand Down
24 changes: 24 additions & 0 deletions parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,30 @@ func TestParser(t *testing.T) {
src: `{"AnnualRevenue":"2000000","NumberOfEmployees":"201","FirstName":"scott"}`,
expected: true,
},
{
name: "CONTAINS_ANY string + array 1",
exp: `.FirstName CONTAINS_ANY ["noah", "emily", "alexandra","scott"]`,
src: `{"AnnualRevenue":"2000000","NumberOfEmployees":"201","FirstName":"scott"}`,
expected: true,
},
{
name: "CONTAINS_ANY string + array 2",
exp: `.FirstName CONTAINS_ANY ["noah", "emily", "alexandra"]`,
src: `{"AnnualRevenue":"2000000","NumberOfEmployees":"201","FirstName":"scott"}`,
expected: false,
},
{
name: "CONTAINS_ALL string + array 1",
exp: `.FirstName CONTAINS_ALL ["sc", "ot", "ott","cot"]`,
src: `{"AnnualRevenue":"2000000","NumberOfEmployees":"201","FirstName":"scott"}`,
expected: true,
},
{
name: "CONTAINS_ALL string + array 2",
exp: `.FirstName CONTAINS_ALL ["sc", "ot", "ott","b"]`,
src: `{"AnnualRevenue":"2000000","NumberOfEmployees":"201","FirstName":"scott"}`,
expected: false,
},
}

for _, tc := range tests {
Expand Down

0 comments on commit 0d3169d

Please sign in to comment.