Skip to content

Commit 06070c6

Browse files
committed
generate FALSE if values is empty in IN/ALL/SOME/ANY
1 parent fc56bc8 commit 06070c6

File tree

2 files changed

+149
-125
lines changed

2 files changed

+149
-125
lines changed

cond.go

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,10 +186,15 @@ func (c *Cond) LTE(field string, value interface{}) string {
186186

187187
// In is used to construct the expression "field IN (value...)".
188188
func (c *Cond) In(field string, values ...interface{}) string {
189-
if len(field) == 0 || len(values) == 0 {
189+
if len(field) == 0 {
190190
return ""
191191
}
192192

193+
// Empty values means "false".
194+
if len(values) == 0 {
195+
return "0 = 1"
196+
}
197+
193198
return c.Var(condBuilder{
194199
Builder: func(ctx *argsCompileContext) {
195200
ctx.WriteString(field)
@@ -457,10 +462,15 @@ func (c *Cond) NotExists(subquery interface{}) string {
457462

458463
// Any is used to construct the expression "field op ANY (value...)".
459464
func (c *Cond) Any(field, op string, values ...interface{}) string {
460-
if len(field) == 0 || len(op) == 0 || len(values) == 0 {
465+
if len(field) == 0 || len(op) == 0 {
461466
return ""
462467
}
463468

469+
// Empty values means "false".
470+
if len(values) == 0 {
471+
return "0 = 1"
472+
}
473+
464474
return c.Var(condBuilder{
465475
Builder: func(ctx *argsCompileContext) {
466476
ctx.WriteString(field)
@@ -475,10 +485,15 @@ func (c *Cond) Any(field, op string, values ...interface{}) string {
475485

476486
// All is used to construct the expression "field op ALL (value...)".
477487
func (c *Cond) All(field, op string, values ...interface{}) string {
478-
if len(field) == 0 || len(op) == 0 || len(values) == 0 {
488+
if len(field) == 0 || len(op) == 0 {
479489
return ""
480490
}
481491

492+
// Empty values means "false".
493+
if len(values) == 0 {
494+
return "0 = 1"
495+
}
496+
482497
return c.Var(condBuilder{
483498
Builder: func(ctx *argsCompileContext) {
484499
ctx.WriteString(field)
@@ -493,10 +508,15 @@ func (c *Cond) All(field, op string, values ...interface{}) string {
493508

494509
// Some is used to construct the expression "field op SOME (value...)".
495510
func (c *Cond) Some(field, op string, values ...interface{}) string {
496-
if len(field) == 0 || len(op) == 0 || len(values) == 0 {
511+
if len(field) == 0 || len(op) == 0 {
497512
return ""
498513
}
499514

515+
// Empty values means "false".
516+
if len(values) == 0 {
517+
return "0 = 1"
518+
}
519+
500520
return c.Var(condBuilder{
501521
Builder: func(ctx *argsCompileContext) {
502522
ctx.WriteString(field)

cond_test.go

Lines changed: 125 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -12,165 +12,162 @@ import (
1212

1313
type TestPair struct {
1414
Expected string
15-
Actual func(cond *Cond) string
15+
Actual string
16+
}
17+
18+
func newTestPair(expected string, fn func(c *Cond) string) *TestPair {
19+
cond := newCond()
20+
format := fn(cond)
21+
sql, _ := cond.Args.CompileWithFlavor(format, PostgreSQL)
22+
return &TestPair{
23+
Expected: expected,
24+
Actual: sql,
25+
}
1626
}
1727

1828
func TestCond(t *testing.T) {
1929
a := assert.New(t)
20-
cases := map[string]func(cond *Cond) string{
21-
"$a = $1": func(cond *Cond) string { return cond.Equal("$a", 123) },
22-
"$b = $1": func(cond *Cond) string { return cond.E("$b", 123) },
23-
"$c = $1": func(cond *Cond) string { return cond.EQ("$c", 123) },
24-
"$a <> $1": func(cond *Cond) string { return cond.NotEqual("$a", 123) },
25-
"$b <> $1": func(cond *Cond) string { return cond.NE("$b", 123) },
26-
"$c <> $1": func(cond *Cond) string { return cond.NEQ("$c", 123) },
27-
"$a > $1": func(cond *Cond) string { return cond.GreaterThan("$a", 123) },
28-
"$b > $1": func(cond *Cond) string { return cond.G("$b", 123) },
29-
"$c > $1": func(cond *Cond) string { return cond.GT("$c", 123) },
30-
"$a >= $1": func(cond *Cond) string { return cond.GreaterEqualThan("$a", 123) },
31-
"$b >= $1": func(cond *Cond) string { return cond.GE("$b", 123) },
32-
"$c >= $1": func(cond *Cond) string { return cond.GTE("$c", 123) },
33-
"$a < $1": func(cond *Cond) string { return cond.LessThan("$a", 123) },
34-
"$b < $1": func(cond *Cond) string { return cond.L("$b", 123) },
35-
"$c < $1": func(cond *Cond) string { return cond.LT("$c", 123) },
36-
"$a <= $1": func(cond *Cond) string { return cond.LessEqualThan("$a", 123) },
37-
"$b <= $1": func(cond *Cond) string { return cond.LE("$b", 123) },
38-
"$c <= $1": func(cond *Cond) string { return cond.LTE("$c", 123) },
39-
"$a IN ($1, $2, $3)": func(cond *Cond) string { return cond.In("$a", 1, 2, 3) },
40-
"$a NOT IN ($1, $2, $3)": func(cond *Cond) string { return cond.NotIn("$a", 1, 2, 3) },
41-
"$a LIKE $1": func(cond *Cond) string { return cond.Like("$a", "%Huan%") },
42-
"$a ILIKE $1": func(cond *Cond) string { return cond.ILike("$a", "%Huan%") },
43-
"$a NOT LIKE $1": func(cond *Cond) string { return cond.NotLike("$a", "%Huan%") },
44-
"$a NOT ILIKE $1": func(cond *Cond) string { return cond.NotILike("$a", "%Huan%") },
45-
"$a IS NULL": func(cond *Cond) string { return cond.IsNull("$a") },
46-
"$a IS NOT NULL": func(cond *Cond) string { return cond.IsNotNull("$a") },
47-
"$a BETWEEN $1 AND $2": func(cond *Cond) string { return cond.Between("$a", 123, 456) },
48-
"$a NOT BETWEEN $1 AND $2": func(cond *Cond) string { return cond.NotBetween("$a", 123, 456) },
49-
"NOT 1 = 1": func(cond *Cond) string { return cond.Not("1 = 1") },
50-
"EXISTS ($1)": func(cond *Cond) string { return cond.Exists(1) },
51-
"NOT EXISTS ($1)": func(cond *Cond) string { return cond.NotExists(1) },
52-
"$a > ANY ($1, $2)": func(cond *Cond) string { return cond.Any("$a", ">", 1, 2) },
53-
"$a < ALL ($1)": func(cond *Cond) string { return cond.All("$a", "<", 1) },
54-
"$a > SOME ($1, $2, $3)": func(cond *Cond) string { return cond.Some("$a", ">", 1, 2, 3) },
55-
"$a IS DISTINCT FROM $1": func(cond *Cond) string { return cond.IsDistinctFrom("$a", 1) },
56-
"$a IS NOT DISTINCT FROM $1": func(cond *Cond) string { return cond.IsNotDistinctFrom("$a", 1) },
57-
"$1": func(cond *Cond) string { return cond.Var(123) },
58-
}
59-
60-
for expected, f := range cases {
61-
actual := callCond(f)
62-
a.Equal(actual, expected)
30+
cases := []*TestPair{
31+
newTestPair("$a = $1", func(c *Cond) string { return c.Equal("$a", 123) }),
32+
newTestPair("$b = $1", func(c *Cond) string { return c.E("$b", 123) }),
33+
newTestPair("$c = $1", func(c *Cond) string { return c.EQ("$c", 123) }),
34+
newTestPair("$a <> $1", func(c *Cond) string { return c.NotEqual("$a", 123) }),
35+
newTestPair("$b <> $1", func(c *Cond) string { return c.NE("$b", 123) }),
36+
newTestPair("$c <> $1", func(c *Cond) string { return c.NEQ("$c", 123) }),
37+
newTestPair("$a > $1", func(c *Cond) string { return c.GreaterThan("$a", 123) }),
38+
newTestPair("$b > $1", func(c *Cond) string { return c.G("$b", 123) }),
39+
newTestPair("$c > $1", func(c *Cond) string { return c.GT("$c", 123) }),
40+
newTestPair("$a >= $1", func(c *Cond) string { return c.GreaterEqualThan("$a", 123) }),
41+
newTestPair("$b >= $1", func(c *Cond) string { return c.GE("$b", 123) }),
42+
newTestPair("$c >= $1", func(c *Cond) string { return c.GTE("$c", 123) }),
43+
newTestPair("$a < $1", func(c *Cond) string { return c.LessThan("$a", 123) }),
44+
newTestPair("$b < $1", func(c *Cond) string { return c.L("$b", 123) }),
45+
newTestPair("$c < $1", func(c *Cond) string { return c.LT("$c", 123) }),
46+
newTestPair("$a <= $1", func(c *Cond) string { return c.LessEqualThan("$a", 123) }),
47+
newTestPair("$b <= $1", func(c *Cond) string { return c.LE("$b", 123) }),
48+
newTestPair("$c <= $1", func(c *Cond) string { return c.LTE("$c", 123) }),
49+
newTestPair("$a IN ($1, $2, $3)", func(c *Cond) string { return c.In("$a", 1, 2, 3) }),
50+
newTestPair("0 = 1", func(c *Cond) string { return c.In("$a") }),
51+
newTestPair("$a NOT IN ($1, $2, $3)", func(c *Cond) string { return c.NotIn("$a", 1, 2, 3) }),
52+
newTestPair("$a LIKE $1", func(c *Cond) string { return c.Like("$a", "%Huan%") }),
53+
newTestPair("$a ILIKE $1", func(c *Cond) string { return c.ILike("$a", "%Huan%") }),
54+
newTestPair("$a NOT LIKE $1", func(c *Cond) string { return c.NotLike("$a", "%Huan%") }),
55+
newTestPair("$a NOT ILIKE $1", func(c *Cond) string { return c.NotILike("$a", "%Huan%") }),
56+
newTestPair("$a IS NULL", func(c *Cond) string { return c.IsNull("$a") }),
57+
newTestPair("$a IS NOT NULL", func(c *Cond) string { return c.IsNotNull("$a") }),
58+
newTestPair("$a BETWEEN $1 AND $2", func(c *Cond) string { return c.Between("$a", 123, 456) }),
59+
newTestPair("$a NOT BETWEEN $1 AND $2", func(c *Cond) string { return c.NotBetween("$a", 123, 456) }),
60+
newTestPair("NOT 1 = 1", func(c *Cond) string { return c.Not("1 = 1") }),
61+
newTestPair("EXISTS ($1)", func(c *Cond) string { return c.Exists(1) }),
62+
newTestPair("NOT EXISTS ($1)", func(c *Cond) string { return c.NotExists(1) }),
63+
newTestPair("$a > ANY ($1, $2)", func(c *Cond) string { return c.Any("$a", ">", 1, 2) }),
64+
newTestPair("0 = 1", func(c *Cond) string { return c.Any("$a", ">") }),
65+
newTestPair("$a < ALL ($1)", func(c *Cond) string { return c.All("$a", "<", 1) }),
66+
newTestPair("0 = 1", func(c *Cond) string { return c.All("$a", "<") }),
67+
newTestPair("$a > SOME ($1, $2, $3)", func(c *Cond) string { return c.Some("$a", ">", 1, 2, 3) }),
68+
newTestPair("0 = 1", func(c *Cond) string { return c.Some("$a", ">") }),
69+
newTestPair("$a IS DISTINCT FROM $1", func(c *Cond) string { return c.IsDistinctFrom("$a", 1) }),
70+
newTestPair("$a IS NOT DISTINCT FROM $1", func(c *Cond) string { return c.IsNotDistinctFrom("$a", 1) }),
71+
newTestPair("$1", func(c *Cond) string { return c.Var(123) }),
72+
}
73+
74+
for _, f := range cases {
75+
a.Equal(f.Actual, f.Expected)
6376
}
6477
}
6578

6679
func TestOrCond(t *testing.T) {
6780
a := assert.New(t)
68-
cases := []TestPair{
69-
{Expected: "(1 = 1 OR 2 = 2 OR 3 = 3)", Actual: func(cond *Cond) string { return cond.Or("1 = 1", "2 = 2", "3 = 3") }},
81+
cases := []*TestPair{
82+
newTestPair("(1 = 1 OR 2 = 2 OR 3 = 3)", func(c *Cond) string { return c.Or("1 = 1", "2 = 2", "3 = 3") }),
7083

71-
{Expected: "(1 = 1 OR 2 = 2)", Actual: func(cond *Cond) string { return cond.Or("", "1 = 1", "2 = 2") }},
72-
{Expected: "(1 = 1 OR 2 = 2)", Actual: func(cond *Cond) string { return cond.Or("1 = 1", "2 = 2", "") }},
73-
{Expected: "(1 = 1 OR 2 = 2)", Actual: func(cond *Cond) string { return cond.Or("1 = 1", "", "2 = 2") }},
84+
newTestPair("(1 = 1 OR 2 = 2)", func(c *Cond) string { return c.Or("", "1 = 1", "2 = 2") }),
85+
newTestPair("(1 = 1 OR 2 = 2)", func(c *Cond) string { return c.Or("1 = 1", "2 = 2", "") }),
86+
newTestPair("(1 = 1 OR 2 = 2)", func(c *Cond) string { return c.Or("1 = 1", "", "2 = 2") }),
7487

75-
{Expected: "(1 = 1)", Actual: func(cond *Cond) string { return cond.Or("1 = 1", "", "") }},
76-
{Expected: "(1 = 1)", Actual: func(cond *Cond) string { return cond.Or("", "1 = 1", "") }},
77-
{Expected: "(1 = 1)", Actual: func(cond *Cond) string { return cond.Or("", "", "1 = 1") }},
78-
{Expected: "(1 = 1)", Actual: func(cond *Cond) string { return cond.Or("1 = 1") }},
88+
newTestPair("(1 = 1)", func(c *Cond) string { return c.Or("1 = 1", "", "") }),
89+
newTestPair("(1 = 1)", func(c *Cond) string { return c.Or("", "1 = 1", "") }),
90+
newTestPair("(1 = 1)", func(c *Cond) string { return c.Or("", "", "1 = 1") }),
91+
newTestPair("(1 = 1)", func(c *Cond) string { return c.Or("1 = 1") }),
7992

80-
{Expected: "", Actual: func(cond *Cond) string { return cond.Or("") }},
81-
{Expected: "", Actual: func(cond *Cond) string { return cond.Or() }},
82-
{Expected: "", Actual: func(cond *Cond) string { return cond.Or("", "", "") }},
93+
{Expected: "", Actual: newCond().Or("")},
94+
{Expected: "", Actual: newCond().Or()},
95+
{Expected: "", Actual: newCond().Or("", "", "")},
8396
}
8497

8598
for _, f := range cases {
86-
actual := callCond(f.Actual)
87-
a.Equal(actual, f.Expected)
99+
a.Equal(f.Actual, f.Expected)
88100
}
89101
}
90102

91103
func TestAndCond(t *testing.T) {
92104
a := assert.New(t)
93-
cases := []TestPair{
94-
{Expected: "(1 = 1 AND 2 = 2 AND 3 = 3)", Actual: func(cond *Cond) string { return cond.And("1 = 1", "2 = 2", "3 = 3") }},
105+
cases := []*TestPair{
106+
newTestPair("(1 = 1 AND 2 = 2 AND 3 = 3)", func(c *Cond) string { return c.And("1 = 1", "2 = 2", "3 = 3") }),
95107

96-
{Expected: "(1 = 1 AND 2 = 2)", Actual: func(cond *Cond) string { return cond.And("", "1 = 1", "2 = 2") }},
97-
{Expected: "(1 = 1 AND 2 = 2)", Actual: func(cond *Cond) string { return cond.And("1 = 1", "2 = 2", "") }},
98-
{Expected: "(1 = 1 AND 2 = 2)", Actual: func(cond *Cond) string { return cond.And("1 = 1", "", "2 = 2") }},
108+
newTestPair("(1 = 1 AND 2 = 2)", func(c *Cond) string { return c.And("", "1 = 1", "2 = 2") }),
109+
newTestPair("(1 = 1 AND 2 = 2)", func(c *Cond) string { return c.And("1 = 1", "2 = 2", "") }),
110+
newTestPair("(1 = 1 AND 2 = 2)", func(c *Cond) string { return c.And("1 = 1", "", "2 = 2") }),
99111

100-
{Expected: "(1 = 1)", Actual: func(cond *Cond) string { return cond.And("1 = 1", "", "") }},
101-
{Expected: "(1 = 1)", Actual: func(cond *Cond) string { return cond.And("", "1 = 1", "") }},
102-
{Expected: "(1 = 1)", Actual: func(cond *Cond) string { return cond.And("", "", "1 = 1") }},
103-
{Expected: "(1 = 1)", Actual: func(cond *Cond) string { return cond.And("1 = 1") }},
112+
newTestPair("(1 = 1)", func(c *Cond) string { return c.And("1 = 1", "", "") }),
113+
newTestPair("(1 = 1)", func(c *Cond) string { return c.And("", "1 = 1", "") }),
114+
newTestPair("(1 = 1)", func(c *Cond) string { return c.And("", "", "1 = 1") }),
115+
newTestPair("(1 = 1)", func(c *Cond) string { return c.And("1 = 1") }),
104116

105-
{Expected: "", Actual: func(cond *Cond) string { return cond.And("") }},
106-
{Expected: "", Actual: func(cond *Cond) string { return cond.And() }},
107-
{Expected: "", Actual: func(cond *Cond) string { return cond.And("", "", "") }},
117+
{Expected: "", Actual: newCond().And("")},
118+
{Expected: "", Actual: newCond().And()},
119+
{Expected: "", Actual: newCond().And("", "", "")},
108120
}
109121

110122
for _, f := range cases {
111-
actual := callCond(f.Actual)
112-
a.Equal(actual, f.Expected)
123+
a.Equal(f.Actual, f.Expected)
113124
}
114125
}
115126

116127
func TestEmptyCond(t *testing.T) {
117128
a := assert.New(t)
118-
cases := []func(cond *Cond) string{
119-
func(cond *Cond) string { return cond.Equal("", 123) },
120-
func(cond *Cond) string { return cond.NotEqual("", 123) },
121-
func(cond *Cond) string { return cond.GreaterThan("", 123) },
122-
func(cond *Cond) string { return cond.GreaterEqualThan("", 123) },
123-
func(cond *Cond) string { return cond.LessThan("", 123) },
124-
func(cond *Cond) string { return cond.LessEqualThan("", 123) },
125-
func(cond *Cond) string { return cond.In("", 1, 2, 3) },
126-
func(cond *Cond) string { return cond.In("a") },
127-
func(cond *Cond) string { return cond.NotIn("", 1, 2, 3) },
128-
func(cond *Cond) string { return cond.NotIn("a") },
129-
func(cond *Cond) string { return cond.Like("", "%Huan%") },
130-
func(cond *Cond) string { return cond.ILike("", "%Huan%") },
131-
func(cond *Cond) string { return cond.NotLike("", "%Huan%") },
132-
func(cond *Cond) string { return cond.NotILike("", "%Huan%") },
133-
func(cond *Cond) string { return cond.IsNull("") },
134-
func(cond *Cond) string { return cond.IsNotNull("") },
135-
func(cond *Cond) string { return cond.Between("", 123, 456) },
136-
func(cond *Cond) string { return cond.NotBetween("", 123, 456) },
137-
func(cond *Cond) string { return cond.Not("") },
138-
139-
func(cond *Cond) string { return cond.Any("", "", 1, 2) },
140-
func(cond *Cond) string { return cond.Any("", ">", 1, 2) },
141-
func(cond *Cond) string { return cond.Any("$a", "", 1, 2) },
142-
func(cond *Cond) string { return cond.Any("$a", ">") },
143-
144-
func(cond *Cond) string { return cond.All("", "", 1) },
145-
func(cond *Cond) string { return cond.All("", ">", 1) },
146-
func(cond *Cond) string { return cond.All("$a", "", 1) },
147-
func(cond *Cond) string { return cond.All("$a", ">") },
148-
149-
func(cond *Cond) string { return cond.Some("", "", 1, 2, 3) },
150-
func(cond *Cond) string { return cond.Some("", ">", 1, 2, 3) },
151-
func(cond *Cond) string { return cond.Some("$a", "", 1, 2, 3) },
152-
func(cond *Cond) string { return cond.Some("$a", ">") },
153-
154-
func(cond *Cond) string { return cond.IsDistinctFrom("", 1) },
155-
func(cond *Cond) string { return cond.IsNotDistinctFrom("", 1) },
129+
cases := []string{
130+
newCond().Equal("", 123),
131+
newCond().NotEqual("", 123),
132+
newCond().GreaterThan("", 123),
133+
newCond().GreaterEqualThan("", 123),
134+
newCond().LessThan("", 123),
135+
newCond().LessEqualThan("", 123),
136+
newCond().In("", 1, 2, 3),
137+
newCond().NotIn("", 1, 2, 3),
138+
newCond().NotIn("a"),
139+
newCond().Like("", "%Huan%"),
140+
newCond().ILike("", "%Huan%"),
141+
newCond().NotLike("", "%Huan%"),
142+
newCond().NotILike("", "%Huan%"),
143+
newCond().IsNull(""),
144+
newCond().IsNotNull(""),
145+
newCond().Between("", 123, 456),
146+
newCond().NotBetween("", 123, 456),
147+
newCond().Not(""),
148+
149+
newCond().Any("", "", 1, 2),
150+
newCond().Any("", ">", 1, 2),
151+
newCond().Any("$a", "", 1, 2),
152+
153+
newCond().All("", "", 1),
154+
newCond().All("", ">", 1),
155+
newCond().All("$a", "", 1),
156+
157+
newCond().Some("", "", 1, 2, 3),
158+
newCond().Some("", ">", 1, 2, 3),
159+
newCond().Some("$a", "", 1, 2, 3),
160+
161+
newCond().IsDistinctFrom("", 1),
162+
newCond().IsNotDistinctFrom("", 1),
156163
}
157164

158165
expected := ""
159-
for _, f := range cases {
160-
actual := callCond(f)
166+
for _, actual := range cases {
161167
a.Equal(actual, expected)
162168
}
163169
}
164170

165-
func callCond(fn func(cond *Cond) string) (actual string) {
166-
cond := &Cond{
167-
Args: &Args{},
168-
}
169-
format := fn(cond)
170-
actual, _ = cond.Args.CompileWithFlavor(format, PostgreSQL)
171-
return
172-
}
173-
174171
func TestCondWithFlavor(t *testing.T) {
175172
a := assert.New(t)
176173
cond := &Cond{
@@ -248,3 +245,10 @@ func TestCondMisuse(t *testing.T) {
248245
a.Equal(sql, "SELECT * FROM t1 WHERE /* INVALID ARG $256 */")
249246
a.Equal(args, nil)
250247
}
248+
249+
func newCond() *Cond {
250+
args := &Args{}
251+
return &Cond{
252+
Args: args,
253+
}
254+
}

0 commit comments

Comments
 (0)