Skip to content

Commit 646ce24

Browse files
Add attribute value range checker helper function (#1004)
1 parent 933fb08 commit 646ce24

File tree

3 files changed

+157
-2
lines changed

3 files changed

+157
-2
lines changed
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// Copyright 2019 The SQLFlow Authors. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
package attribute
15+
16+
import (
17+
"fmt"
18+
)
19+
20+
func newFloat32(f float32) *float32 {
21+
return &f
22+
}
23+
24+
// Float32RangeChecker is a helper function to generate range checkers on attribute.
25+
// lower/upper indicates the lower bound and upper bound of the attribute value.
26+
// If lower/upper is nil, it means no boundary.
27+
// includeLower/includeUpper indicates the inclusion of the bound.
28+
func Float32RangeChecker(lower, upper *float32, includeLower, includeUpper bool) func(interface{}) error {
29+
30+
checker := func(e interface{}) error {
31+
f, ok := e.(float32)
32+
if !ok {
33+
return fmt.Errorf("expected type float32, received %T", e)
34+
}
35+
36+
// NOTE(tony): nil means no boundary
37+
if lower != nil {
38+
if includeLower && !(*lower <= f) {
39+
return fmt.Errorf("range check %v <= %v failed", *lower, f)
40+
}
41+
if !includeLower && !(*lower < f) {
42+
return fmt.Errorf("range check %v < %v failed", *lower, f)
43+
}
44+
}
45+
46+
// NOTE(tony): nil means no boundary
47+
if upper != nil {
48+
if includeUpper && !(f <= *upper) {
49+
return fmt.Errorf("range check %v <= %v failed", f, *upper)
50+
}
51+
if !includeUpper && !(f < *upper) {
52+
return fmt.Errorf("range check %v < %v failed", f, *upper)
53+
}
54+
}
55+
56+
return nil
57+
}
58+
59+
return checker
60+
}
61+
62+
func newInt(i int) *int {
63+
return &i
64+
}
65+
66+
// IntRangeChecker is a helper function to generate range checkers on attribute.
67+
// lower/upper indicates the lower bound and upper bound of the attribute value.
68+
// If lower/upper is nil, it means no boundary.
69+
// includeLower/includeUpper indicates the inclusion of the bound.
70+
func IntRangeChecker(lower, upper *int, includeLower, includeUpper bool) func(interface{}) error {
71+
checker := func(e interface{}) error {
72+
i, ok := e.(int)
73+
if !ok {
74+
return fmt.Errorf("expected type float32, received %T", e)
75+
}
76+
77+
// NOTE(tony): nil means no boundary
78+
if lower != nil {
79+
if includeLower && !(*lower <= i) {
80+
return fmt.Errorf("range check %v <= %v failed", *lower, i)
81+
}
82+
if !includeLower && !(*lower < i) {
83+
return fmt.Errorf("range check %v < %v failed", *lower, i)
84+
}
85+
}
86+
87+
// NOTE(tony): nil means no boundary
88+
if upper != nil {
89+
if includeUpper && !(i <= *upper) {
90+
return fmt.Errorf("range check %v <= %v failed", i, *upper)
91+
}
92+
if !includeUpper && !(i < *upper) {
93+
return fmt.Errorf("range check %v < %v failed", i, *upper)
94+
}
95+
}
96+
97+
return nil
98+
}
99+
100+
return checker
101+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Copyright 2019 The SQLFlow Authors. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
package attribute
15+
16+
import (
17+
"github.com/stretchr/testify/assert"
18+
"testing"
19+
)
20+
21+
func TestFloat32RangeChecker(t *testing.T) {
22+
a := assert.New(t)
23+
24+
checker := Float32RangeChecker(newFloat32(0.0), newFloat32(1.0), true, true)
25+
a.Error(checker(float32(-1)))
26+
a.NoError(checker(float32(0)))
27+
a.NoError(checker(float32(0.5)))
28+
a.NoError(checker(float32(1)))
29+
a.Error(checker(float32(2)))
30+
31+
checker2 := Float32RangeChecker(newFloat32(0.0), newFloat32(1.0), false, false)
32+
a.Error(checker2(float32(-1)))
33+
a.Error(checker2(float32(0)))
34+
a.NoError(checker2(float32(0.5)))
35+
a.Error(checker2(float32(1)))
36+
a.Error(checker2(float32(2)))
37+
}
38+
39+
func TestIntRangeChecker(t *testing.T) {
40+
a := assert.New(t)
41+
42+
checker := IntRangeChecker(newInt(0), newInt(2), true, true)
43+
a.Error(checker(int(-1)))
44+
a.NoError(checker(int(0)))
45+
a.NoError(checker(int(1)))
46+
a.NoError(checker(int(2)))
47+
a.Error(checker(int(3)))
48+
49+
checker2 := IntRangeChecker(newInt(0), newInt(2), false, false)
50+
a.Error(checker2(int(-1)))
51+
a.Error(checker2(int(0)))
52+
a.NoError(checker2(int(1)))
53+
a.Error(checker2(int(2)))
54+
a.Error(checker2(int(3)))
55+
}

pkg/sql/ir_generator.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,7 @@ func inferStringValue(expr string) interface{} {
146146
return ret
147147
}
148148
if retFloat, err := strconv.ParseFloat(expr, 32); err == nil {
149-
// always use float32 for attributes, we may never use a float64
150-
// value as some attribute.
149+
// Note(typhoonzero): always use float32 for attributes, we may never use a float64.
151150
return float32(retFloat)
152151
}
153152
retString := strings.Trim(expr, "\"")

0 commit comments

Comments
 (0)