@@ -77,9 +77,10 @@ func checkValueCount(operator string, nValues int) bool {
7777}
7878
7979// Convert a single filter to where clauses
80+ // nolint funlen
8081func (t * FilterData ) ToWhere (fieldName string , attributes database.AttrMap ) (string , []any , error ) {
8182 var err error
82- transformedOperator , transformedValues := t .transformParams (fieldName )
83+ transformedOperator , transformedValues , hasNull := t .transformParams (fieldName )
8384 var values = make ([]any , len (transformedValues ))
8485 for i , v := range transformedValues {
8586 fieldInfo , found := attributes [fieldName ]
@@ -115,8 +116,16 @@ func (t *FilterData) ToWhere(fieldName string, attributes database.AttrMap) (str
115116 case OpBetween :
116117 return fmt .Sprintf ("%s BETWEEN ? AND ? " , attributes [fieldName ].DataQuery ), values , nil
117118 case OpIn :
119+ if hasNull {
120+ return fmt .Sprintf ("(%s IN ? OR %s IS NULL) " ,
121+ attributes [fieldName ].DataQuery , attributes [fieldName ].DataQuery ), []any {values }, nil
122+ }
118123 return fmt .Sprintf ("%s IN (?) " , attributes [fieldName ].DataQuery ), []any {values }, nil
119124 case OpNotIn :
125+ if hasNull {
126+ return fmt .Sprintf ("(%s NOT IN ? AND %s IS NOT NULL) " ,
127+ attributes [fieldName ].DataQuery , attributes [fieldName ].DataQuery ), []any {values }, nil
128+ }
120129 return fmt .Sprintf ("%s NOT IN (?) " , attributes [fieldName ].DataQuery ), []any {values }, nil
121130 case OpNull :
122131 return fmt .Sprintf ("%s IS NULL " , attributes [fieldName ].DataQuery ), []any {}, nil
@@ -127,39 +136,65 @@ func (t *FilterData) ToWhere(fieldName string, attributes database.AttrMap) (str
127136 }
128137}
129138
130- func (t * FilterData ) transformParams (fieldName string ) (transformedOperator string , transformedValues []string ) {
131- if len (t .Values ) == 1 && (t .Values [0 ] == "null" || t .Values [0 ] == "notnull" ) {
139+ func (t * FilterData ) transformParams (fieldName string ) (
140+ transformedOperator string , transformedValues []string , hasNull bool ) {
141+ if len (t .Values ) == 1 && (t .Values [0 ] == OpNull || t .Values [0 ] == OpNotNull ) {
132142 // handle special cases filter=null and filter=notnull
133- return t .Values [0 ], []string {"0" }
143+ return t .Values [0 ], []string {"0" }, false
134144 }
135- if fieldName != "advisory_type_name" {
136- // no change
137- return t .Operator , t .Values
145+ // special case, in advisory_type_name filter expand "other" into list of what we mean by other
146+ valuesToProcess := t .Values
147+ operatorToUse := t .Operator
148+ if fieldName == "advisory_type_name" {
149+ transformedValues = make ([]string , 0 , len (t .Values ))
150+ for _ , originalValue := range t .Values {
151+ if originalValue == "other" {
152+ transformedValues = append (transformedValues , database .OtherAdvisoryTypes ... )
153+ } else {
154+ transformedValues = append (transformedValues , originalValue )
155+ }
156+ }
157+ // If "other" was expanded, use the expanded list for further processing
158+ if len (transformedValues ) != len (t .Values ) {
159+ valuesToProcess = transformedValues
160+ // Convert operator if needed
161+ switch t .Operator {
162+ case OpEq :
163+ operatorToUse = OpIn
164+ case OpNeq :
165+ operatorToUse = OpNotIn
166+ default :
167+ operatorToUse = t .Operator
168+ }
169+ }
138170 }
139171
140- // special case, in advisory_type_name filter expand "other" into list of what we mean by other
141- transformedValues = make ([]string , 0 , len (t .Values ))
142- for _ , originalValue := range t .Values {
143- if originalValue == "other" {
144- transformedValues = append (transformedValues , database .OtherAdvisoryTypes ... )
172+ if fieldName == "severity" && (t .Operator == OpIn || t .Operator == OpNotIn ) {
173+ valuesToProcess , hasNull = separateNullFromValues (valuesToProcess )
174+ }
175+ return operatorToUse , valuesToProcess , hasNull
176+ }
177+
178+ func separateNullFromValues (values []string ) (regularValues []string , hasNull bool ) {
179+ hasNullValue := false
180+
181+ for _ , v := range values {
182+ if v == "null" {
183+ hasNullValue = true
145184 } else {
146- transformedValues = append (transformedValues , originalValue )
185+ regularValues = append (regularValues , v )
147186 }
148187 }
149188
150- if len (transformedValues ) == len ( t . Values ) {
151- return t . Operator , t . Values
189+ if hasNullValue && len (regularValues ) == 0 {
190+ return [] string { "0" }, false
152191 }
153192
154- switch t .Operator {
155- case OpEq :
156- transformedOperator = OpIn
157- case OpNeq :
158- transformedOperator = OpNotIn
159- default :
160- transformedOperator = t .Operator
193+ // null mixed with values e.g. in:2,null
194+ if hasNullValue && len (regularValues ) > 0 {
195+ return regularValues , true
161196 }
162- return transformedOperator , transformedValues
197+ return regularValues , false
163198}
164199
165200func (t Filters ) ToQueryParams () string {
0 commit comments