Skip to content

Commit edd09e6

Browse files
committed
fix: Incorrect native type casting for boolean and null values when filtering JSONB via -> operator
1 parent 7ba387f commit edd09e6

4 files changed

Lines changed: 94 additions & 11 deletions

File tree

database/querybuilder.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -564,11 +564,11 @@ func validateRelatedOrder(table, schema string, o OrderField, selectFields []Sel
564564
return "", &BuildError{"'" + o.relation + "' is not an embedded resource in this request"}
565565
}
566566

567-
func appendValue(where, value string, valueList []any, nmarker int) (string, []any, int) {
568-
if value == "null" ||
567+
func appendValue(where, value string, valueList []any, nmarker int, forceParam bool) (string, []any, int) {
568+
if !forceParam && (value == "null" ||
569569
value == "true" ||
570570
value == "false" ||
571-
value == "unknown" {
571+
value == "unknown") {
572572
where += value
573573
} else if nmarker >= 0 {
574574
nmarker++
@@ -665,7 +665,7 @@ func whereClause(table, schema, label string, node *WhereConditionNode, nmarker
665665
if i != 0 {
666666
where += ", "
667667
}
668-
where, valueList, nmarker = appendValue(where, value, valueList, nmarker)
668+
where, valueList, nmarker = appendValue(where, value, valueList, nmarker, node.field.jsonPath != "")
669669
}
670670
where += ")"
671671
} else if node.operator == "@@" {
@@ -683,11 +683,11 @@ func whereClause(table, schema, label string, node *WhereConditionNode, nmarker
683683
where += "'" + arg + "'"
684684
where += ", "
685685
}
686-
where, valueList, _ = appendValue(where, node.values[0], valueList, nmarker)
686+
where, valueList, _ = appendValue(where, node.values[0], valueList, nmarker, false)
687687
where += ")"
688688

689689
} else {
690-
where, valueList, _ = appendValue(where, node.values[0], valueList, nmarker)
690+
where, valueList, _ = appendValue(where, node.values[0], valueList, nmarker, node.field.jsonPath != "")
691691
}
692692
}
693693
return where, valueList

go.mod

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ require (
77
github.com/jackc/pgx/v5 v5.8.0
88
github.com/rs/cors v1.11.1
99
github.com/rs/zerolog v1.34.0
10-
github.com/samber/lo v1.52.0
10+
github.com/samber/lo v1.53.0
1111
github.com/sted/heligo v0.3.0
12-
github.com/tailscale/hujson v0.0.0-20250605163823-992244df8c5a
12+
github.com/tailscale/hujson v0.0.0-20260302212456-ecc657c15afd
1313
gopkg.in/natefinch/lumberjack.v2 v2.2.1
1414
)
1515

@@ -20,7 +20,7 @@ require (
2020
github.com/jackc/puddle/v2 v2.2.2 // indirect
2121
github.com/mattn/go-colorable v0.1.14 // indirect
2222
github.com/mattn/go-isatty v0.0.20 // indirect
23-
golang.org/x/sync v0.19.0 // indirect
24-
golang.org/x/sys v0.41.0 // indirect
25-
golang.org/x/text v0.34.0 // indirect
23+
golang.org/x/sync v0.20.0 // indirect
24+
golang.org/x/sys v0.42.0 // indirect
25+
golang.org/x/text v0.35.0 // indirect
2626
)

go.sum

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
3232
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
3333
github.com/samber/lo v1.52.0 h1:Rvi+3BFHES3A8meP33VPAxiBZX/Aws5RxrschYGjomw=
3434
github.com/samber/lo v1.52.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0=
35+
github.com/samber/lo v1.53.0 h1:t975lj2py4kJPQ6haz1QMgtId2gtmfktACxIXArw3HM=
36+
github.com/samber/lo v1.53.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0=
3537
github.com/sted/heligo v0.3.0 h1:D5DpF+kZJdfpKpLNfwMlrr4kGksSTdVNXpJFWkajyMs=
3638
github.com/sted/heligo v0.3.0/go.mod h1:ABeimWAZrNRmHngSfQhEF96yrVeceW2JVS2J2GwbtSo=
3739
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -41,15 +43,23 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu
4143
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
4244
github.com/tailscale/hujson v0.0.0-20250605163823-992244df8c5a h1:a6TNDN9CgG+cYjaeN8l2mc4kSz2iMiCDQxPEyltUV/I=
4345
github.com/tailscale/hujson v0.0.0-20250605163823-992244df8c5a/go.mod h1:EbW0wDK/qEUYI0A5bqq0C2kF8JTQwWONmGDBbzsxxHo=
46+
github.com/tailscale/hujson v0.0.0-20260302212456-ecc657c15afd h1:Rf9uhF1+VJ7ZHqxrG8pJ6YacmHvVCmByDmGbAWCc/gA=
47+
github.com/tailscale/hujson v0.0.0-20260302212456-ecc657c15afd/go.mod h1:EbW0wDK/qEUYI0A5bqq0C2kF8JTQwWONmGDBbzsxxHo=
4448
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
4549
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
50+
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
51+
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
4652
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
4753
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
4854
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
4955
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
5056
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
57+
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
58+
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
5159
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
5260
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
61+
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
62+
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
5363
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
5464
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
5565
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=

test/api/jsonb_bool_null_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package test_api
2+
3+
import (
4+
"testing"
5+
6+
"github.com/sted/smoothdb/test"
7+
)
8+
9+
// Tests for issue #15: Incorrect native type casting for boolean and null values
10+
// when filtering JSONB via `->` operator.
11+
12+
func TestJSONBBoolNull(t *testing.T) {
13+
14+
cmdConfig := test.Config{
15+
BaseUrl: "http://localhost:8082/admin/databases",
16+
CommonHeaders: test.Headers{"Authorization": {adminToken}},
17+
}
18+
19+
commands := []test.Command{
20+
{
21+
Method: "POST",
22+
Query: "/dbtest/tables",
23+
Body: `{
24+
"name": "jsonb_bool_null",
25+
"columns": [
26+
{"name": "id", "type": "int4", "notnull": true},
27+
{"name": "data", "type": "jsonb"}
28+
],
29+
"ifnotexists": true
30+
}`,
31+
},
32+
}
33+
test.Prepare(cmdConfig, commands)
34+
35+
testConfig := test.Config{
36+
BaseUrl: "http://localhost:8082/api/dbtest",
37+
CommonHeaders: test.Headers{"Authorization": {adminToken}},
38+
}
39+
40+
tests := []test.Test{
41+
{
42+
Description: "insert jsonb records with boolean and null values",
43+
Method: "POST",
44+
Query: "/jsonb_bool_null",
45+
Body: `[
46+
{"id": 1, "data": {"f": true}},
47+
{"id": 2, "data": {"f": false}},
48+
{"id": 3, "data": {"g": null}}
49+
]`,
50+
Status: 201,
51+
},
52+
{
53+
Description: "can filter jsonb boolean true via arrow operator",
54+
Query: "/jsonb_bool_null?data->f=eq.true",
55+
Expected: `[{"id":1,"data":{"f": true}}]`,
56+
Status: 200,
57+
},
58+
{
59+
Description: "can filter jsonb boolean false via arrow operator",
60+
Query: "/jsonb_bool_null?data->f=eq.false",
61+
Expected: `[{"id":2,"data":{"f": false}}]`,
62+
Status: 200,
63+
},
64+
{
65+
Description: "can filter jsonb null via arrow operator",
66+
Query: "/jsonb_bool_null?data->g=eq.null",
67+
Expected: `[{"id":3,"data":{"g": null}}]`,
68+
Status: 200,
69+
},
70+
}
71+
72+
test.Execute(t, testConfig, tests)
73+
}

0 commit comments

Comments
 (0)