Skip to content

Commit

Permalink
api/v1/atttribute_list_params: move JSONB query builder into its own …
Browse files Browse the repository at this point in the history
…method and add tests
  • Loading branch information
joelrebel committed Aug 14, 2023
1 parent 87a0c2b commit 7f63c49
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 10 deletions.
29 changes: 19 additions & 10 deletions pkg/api/v1/attribute_list_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func parseQueryAttributesListParams(c *gin.Context, key string) []AttributeListP
func (p *AttributeListParams) queryMods(tblName string) qm.QueryMod {
nsMod := qm.Where(fmt.Sprintf("%s.namespace = ?", tblName), p.Namespace)

sqlValues := []interface{}{}
values := []interface{}{}
jsonPath := ""

// If we only have a namespace and no keys we are limiting by namespace only
Expand All @@ -106,23 +106,35 @@ func (p *AttributeListParams) queryMods(tblName string) qm.QueryMod {
// injection since these strings are passed in by the user.
jsonPath += "?"

sqlValues = append(sqlValues, k)
values = append(values, k)
}

where, values := p.setJSONBWhereClause(tblName, jsonPath, values)

queryMods := []qm.QueryMod{nsMod, qm.And(where, values...)}

if p.AttributeOperator == AttributeLogicalOR {
return qm.Or2(qm.Expr(queryMods...))
}

return qm.Expr(queryMods...)
}

func (p *AttributeListParams) setJSONBWhereClause(tblName, jsonPath string, values []interface{}) (string, []interface{}) {
where := ""

switch p.Operator {
case OperatorLessThan:
sqlValues = append(sqlValues, p.Value)
values = append(values, p.Value)
where = fmt.Sprintf("json_extract_path_text(%s.data::JSONB, %s)::int < ?", tblName, jsonPath)
case OperatorGreaterThan:
sqlValues = append(sqlValues, p.Value)
values = append(values, p.Value)
where = fmt.Sprintf("json_extract_path_text(%s.data::JSONB, %s)::int > ?", tblName, jsonPath)
case OperatorLike:
sqlValues = append(sqlValues, p.Value)
values = append(values, p.Value)
where = fmt.Sprintf("json_extract_path_text(%s.data::JSONB, %s) LIKE ?", tblName, jsonPath)
case OperatorEqual:
sqlValues = append(sqlValues, p.Value)
values = append(values, p.Value)
where = fmt.Sprintf("json_extract_path_text(%s.data::JSONB, %s) = ?", tblName, jsonPath)
default:
// we only have keys so we just want to ensure the key is there
Expand All @@ -138,8 +150,5 @@ func (p *AttributeListParams) queryMods(tblName string) qm.QueryMod {
}
}

return qm.Expr(
nsMod,
qm.And(where, sqlValues...),
)
return where, values
}
105 changes: 105 additions & 0 deletions pkg/api/v1/attribute_list_params_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,108 @@ func Test_parseQueryAttributesListParams(t *testing.T) {
})
}
}

func TestSetJSONBWhereClause(t *testing.T) {
tblName := "foo"

testCases := []struct {
jsonPath string
param AttributeListParams
expectedValues []interface{}
expectedWhereStr string
testName string
}{
{
"?",
AttributeListParams{
Namespace: "hollow.versioned",
Keys: []string{
"a",
"b",
},
Operator: "lt",
Value: "5",
},
[]interface{}{"5"},
"json_extract_path_text(foo.data::JSONB, ?)::int < ?",
"where less than",
},
{
"?",
AttributeListParams{
Namespace: "hollow.versioned",
Keys: []string{
"a",
"b",
},
Operator: "gt",
Value: "5",
},
[]interface{}{"5"},
"json_extract_path_text(foo.data::JSONB, ?)::int > ?",
"where greater than",
},
{
"?",
AttributeListParams{
Namespace: "hollow.versioned",
Keys: []string{
"a",
"b",
},
Operator: "like",
Value: "foobar",
},
[]interface{}{"foobar"},
"json_extract_path_text(foo.data::JSONB, ?) LIKE ?",
"like",
},
{
"?",
AttributeListParams{
Namespace: "hollow.versioned",
Keys: []string{
"a",
"b",
},
Operator: "eq",
Value: "10",
},
[]interface{}{"10"},
"json_extract_path_text(foo.data::JSONB, ?) = ?",
"equal",
},
{
"",
AttributeListParams{
Namespace: "hollow.versioned",
Keys: []string{
"a",
"b",
},
},
[]interface{}{},
`foo.data::JSONB -> ? \? ?`,
"default - keys specified with no operator",
},
{
"?",
AttributeListParams{
Namespace: "hollow.versioned",
},
[]interface{}{},
"foo.data::JSONB",
"default - no keys",
},
}

values := []interface{}{}

for _, tc := range testCases {
t.Run(tc.testName, func(t *testing.T) {
gotWhereStr, gotValues := tc.param.setJSONBWhereClause(tblName, tc.jsonPath, values)
assert.Equal(t, tc.expectedValues, gotValues, "values")
assert.Equal(t, tc.expectedWhereStr, gotWhereStr, "where stmt")
})
}
}

0 comments on commit 7f63c49

Please sign in to comment.