Skip to content

Commit 8f24fbf

Browse files
Add option for explicit nested AND sub-queries
Signed-off-by: Peter Broadhurst <[email protected]>
1 parent deff72a commit 8f24fbf

File tree

3 files changed

+81
-1
lines changed

3 files changed

+81
-1
lines changed

pkg/ffapi/restfilter_json.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ type FilterJSONKeyValues struct {
6767
}
6868

6969
type FilterJSON struct {
70-
Or []*FilterJSON `ffstruct:"FilterJSON" json:"or,omitempty"`
70+
Or []*FilterJSON `ffstruct:"FilterJSON" json:"or,omitempty"`
71+
And []*FilterJSON `ffstruct:"FilterJSON" json:"and,omitempty"`
7172
FilterJSONOps
7273
}
7374

@@ -435,6 +436,13 @@ func (jf *FilterJSON) BuildAndFilter(ctx context.Context, fb FilterBuilder, opti
435436
andFilter = andFilter.Condition(fb.In(field, rv.resolveMany(field, e.Values)))
436437
}
437438
}
439+
for _, child := range jf.And {
440+
subFilter, err := child.BuildSubFilter(ctx, fb, options...)
441+
if err != nil {
442+
return nil, err
443+
}
444+
andFilter.Condition(subFilter)
445+
}
438446
if len(jf.Or) > 0 {
439447
childFilter := fb.Or()
440448
for _, child := range jf.Or {

pkg/ffapi/restfilter_json_test.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,52 @@ func TestBuildQuerySingleNestedOr(t *testing.T) {
139139
assert.Equal(t, "tag == 'a'", fi.String())
140140
}
141141

142+
func TestBuildQueryAndWithNestedOr(t *testing.T) {
143+
144+
var qf QueryJSON
145+
err := json.Unmarshal([]byte(`{
146+
"and": [
147+
{
148+
"or": [
149+
{
150+
"equal": [
151+
{
152+
"field": "tag",
153+
"value": "a"
154+
}
155+
]
156+
},
157+
{
158+
"equal": [
159+
{
160+
"field": "tag",
161+
"value": "b"
162+
}
163+
]
164+
}
165+
]
166+
},
167+
{
168+
"equal": [
169+
{
170+
"field": "cid",
171+
"value": "12345"
172+
}
173+
]
174+
}
175+
]
176+
}`), &qf)
177+
assert.NoError(t, err)
178+
179+
filter, err := qf.BuildFilter(context.Background(), TestQueryFactory)
180+
assert.NoError(t, err)
181+
182+
fi, err := filter.Finalize()
183+
assert.NoError(t, err)
184+
185+
assert.Equal(t, "( ( tag == 'a' ) || ( tag == 'b' ) ) && ( cid == '12345' )", fi.String())
186+
}
187+
142188
func TestBuildQuerySkipFieldValidation(t *testing.T) {
143189

144190
var jf *FilterJSON
@@ -706,3 +752,28 @@ func TestBuildQueryJSONContainsShortNames(t *testing.T) {
706752

707753
assert.Equal(t, "( sequence <= 12345 ) && ( sequence >> 12345 )", fi.String())
708754
}
755+
756+
func TestBuildQueryAndFail(t *testing.T) {
757+
758+
var qf QueryJSON
759+
err := json.Unmarshal([]byte(`{
760+
"and": [
761+
{
762+
"or": [
763+
{
764+
"equal": [
765+
{
766+
"field": "color",
767+
"value": "b"
768+
}
769+
]
770+
}
771+
]
772+
}
773+
]
774+
}`), &qf)
775+
assert.NoError(t, err)
776+
777+
_, err = qf.BuildFilter(context.Background(), TestQueryFactory)
778+
assert.Regexp(t, "FF00142.*color", err)
779+
}

pkg/i18n/en_base_field_descriptions.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ var (
4444
FilterJSONSort = ffm("FilterJSON.sort", "Array of fields to sort by. A '-' prefix on a field requests that field is sorted in descending order")
4545
FilterJSONCount = ffm("FilterJSON.count", "If true, the total number of entries that could be returned from the database will be calculated and returned as a 'total' (has a performance cost)")
4646
FilterJSONOr = ffm("FilterJSON.or", "Array of sub-queries where any sub-query can match to return results (OR combined). Note that within each sub-query all filters must match (AND combined)")
47+
FilterJSONAnd = ffm("FilterJSON.and", "Array of sub-queries where any sub-query can match to return results (AND combined). Allows complex construction, such as an AND of two nested OR sub-queries.")
4748
FilterJSONFields = ffm("FilterJSON.fields", "Fields to return in the response")
4849

4950
EventStreamBatchSize = ffm("eventstream.batchSize", "Maximum number of events to deliver in each batch")

0 commit comments

Comments
 (0)