@@ -4,6 +4,10 @@ import org.genspectrum.lapis.config.SequenceFilterFieldType
4
4
import org.genspectrum.lapis.config.SequenceFilterFields
5
5
import org.genspectrum.lapis.silo.And
6
6
import org.genspectrum.lapis.silo.DateBetween
7
+ import org.genspectrum.lapis.silo.FloatBetween
8
+ import org.genspectrum.lapis.silo.FloatEquals
9
+ import org.genspectrum.lapis.silo.IntBetween
10
+ import org.genspectrum.lapis.silo.IntEquals
7
11
import org.genspectrum.lapis.silo.NucleotideSymbolEquals
8
12
import org.genspectrum.lapis.silo.PangoLineageEquals
9
13
import org.genspectrum.lapis.silo.SiloFilterExpression
@@ -35,14 +39,7 @@ class SiloFilterExpressionMapper(
35
39
}
36
40
.groupBy({ it.first }, { it.second })
37
41
38
- if (allowedSequenceFiltersWithType.keys.any { it.second == Filter .VariantQuery } &&
39
- allowedSequenceFiltersWithType.keys.any { it.second in variantQueryTypes }
40
- ) {
41
- throw IllegalArgumentException (
42
- " variantQuery filter cannot be used with other variant filters such as: " +
43
- " ${variantQueryTypes.joinToString(" , " )} " ,
44
- )
45
- }
42
+ crossValidateFilters(allowedSequenceFiltersWithType)
46
43
47
44
val filterExpressions = allowedSequenceFiltersWithType.map { (key, values) ->
48
45
val (siloColumnName, filter) = key
@@ -52,6 +49,10 @@ class SiloFilterExpressionMapper(
52
49
Filter .DateBetween -> mapToDateBetweenFilter(siloColumnName, values)
53
50
Filter .NucleotideSymbolEquals -> mapToNucleotideFilter(values[0 ].value)
54
51
Filter .VariantQuery -> mapToVariantQueryFilter(values[0 ].value)
52
+ Filter .IntEquals -> mapToIntEqualsFilter(siloColumnName, values)
53
+ Filter .IntBetween -> mapToIntBetweenFilter(siloColumnName, values)
54
+ Filter .FloatEquals -> mapToFloatEqualsFilter(siloColumnName, values)
55
+ Filter .FloatBetween -> mapToFloatBetweenFilter(siloColumnName, values)
55
56
}
56
57
}
57
58
@@ -70,6 +71,12 @@ class SiloFilterExpressionMapper(
70
71
SequenceFilterFieldType .String -> Pair (key, Filter .StringEquals )
71
72
SequenceFilterFieldType .MutationsList -> Pair (key, Filter .NucleotideSymbolEquals )
72
73
SequenceFilterFieldType .VariantQuery -> Pair (key, Filter .VariantQuery )
74
+ SequenceFilterFieldType .Int -> Pair (key, Filter .IntEquals )
75
+ is SequenceFilterFieldType .IntFrom -> Pair (type.associatedField, Filter .IntBetween )
76
+ is SequenceFilterFieldType .IntTo -> Pair (type.associatedField, Filter .IntBetween )
77
+ SequenceFilterFieldType .Float -> Pair (key, Filter .FloatEquals )
78
+ is SequenceFilterFieldType .FloatFrom -> Pair (type.associatedField, Filter .FloatBetween )
79
+ is SequenceFilterFieldType .FloatTo -> Pair (type.associatedField, Filter .FloatBetween )
73
80
74
81
null -> throw IllegalArgumentException (
75
82
" '$key ' is not a valid sequence filter key. Valid keys are: " +
@@ -79,6 +86,47 @@ class SiloFilterExpressionMapper(
79
86
return Pair (filterExpressionId, type)
80
87
}
81
88
89
+ private fun crossValidateFilters (
90
+ allowedSequenceFiltersWithType : Map <Pair <SequenceFilterFieldName , Filter >, List <SequenceFilterValue >>,
91
+ ) {
92
+ if (allowedSequenceFiltersWithType.keys.any { it.second == Filter .VariantQuery } &&
93
+ allowedSequenceFiltersWithType.keys.any { it.second in variantQueryTypes }
94
+ ) {
95
+ throw IllegalArgumentException (
96
+ " variantQuery filter cannot be used with other variant filters such as: " +
97
+ variantQueryTypes.joinToString(" , " ),
98
+ )
99
+ }
100
+
101
+ val intEqualFilters = allowedSequenceFiltersWithType.keys.filter { it.second == Filter .IntEquals }
102
+ for ((intEqualsColumnName, _) in intEqualFilters) {
103
+ val intBetweenFilterForSameColumn = allowedSequenceFiltersWithType[
104
+ Pair (intEqualsColumnName, Filter .IntBetween ),
105
+ ]
106
+
107
+ if (intBetweenFilterForSameColumn != null ) {
108
+ throw IllegalArgumentException (
109
+ " Cannot filter by exact int field '$intEqualsColumnName ' " +
110
+ " and by int range field '${intBetweenFilterForSameColumn[0 ].originalKey} '." ,
111
+ )
112
+ }
113
+ }
114
+
115
+ val floatEqualFilters = allowedSequenceFiltersWithType.keys.filter { it.second == Filter .FloatEquals }
116
+ for ((floatEqualsColumnName, _) in floatEqualFilters) {
117
+ val floatBetweenFilterForSameColumn = allowedSequenceFiltersWithType[
118
+ Pair (floatEqualsColumnName, Filter .FloatBetween ),
119
+ ]
120
+
121
+ if (floatBetweenFilterForSameColumn != null ) {
122
+ throw IllegalArgumentException (
123
+ " Cannot filter by exact float field '$floatEqualsColumnName ' " +
124
+ " and by float range field '${floatBetweenFilterForSameColumn[0 ].originalKey} '." ,
125
+ )
126
+ }
127
+ }
128
+ }
129
+
82
130
private fun mapToVariantQueryFilter (variantQuery : String ): SiloFilterExpression {
83
131
if (variantQuery.isBlank()) {
84
132
throw IllegalArgumentException (
@@ -123,8 +171,8 @@ class SiloFilterExpressionMapper(
123
171
private inline fun <reified T : SequenceFilterFieldType > findDateOfFilterType (
124
172
dateRangeFilters : List <SequenceFilterValue >,
125
173
): LocalDate ? {
126
- val fromFilter = dateRangeFilters.find { (type, _, _) -> type is T }
127
- return getAsDate(fromFilter )
174
+ val filter = dateRangeFilters.find { (type, _, _) -> type is T }
175
+ return getAsDate(filter )
128
176
}
129
177
130
178
private fun getAsDate (sequenceFilterValue : SequenceFilterValue ? ): LocalDate ? {
@@ -162,6 +210,88 @@ class SiloFilterExpressionMapper(
162
210
)
163
211
}
164
212
213
+ private fun mapToIntEqualsFilter (
214
+ siloColumnName : SequenceFilterFieldName ,
215
+ values : List <SequenceFilterValue >,
216
+ ): SiloFilterExpression {
217
+ val value = values[0 ].value
218
+ try {
219
+ return IntEquals (siloColumnName, value.toInt())
220
+ } catch (exception: NumberFormatException ) {
221
+ throw IllegalArgumentException (
222
+ " $siloColumnName '$value ' is not a valid integer: ${exception.message} " ,
223
+ exception,
224
+ )
225
+ }
226
+ }
227
+
228
+ private fun mapToFloatEqualsFilter (
229
+ siloColumnName : SequenceFilterFieldName ,
230
+ values : List <SequenceFilterValue >,
231
+ ): SiloFilterExpression {
232
+ val value = values[0 ].value
233
+ try {
234
+ return FloatEquals (siloColumnName, value.toDouble())
235
+ } catch (exception: NumberFormatException ) {
236
+ throw IllegalArgumentException (
237
+ " $siloColumnName '$value ' is not a valid float: ${exception.message} " ,
238
+ exception,
239
+ )
240
+ }
241
+ }
242
+
243
+ private fun mapToIntBetweenFilter (
244
+ siloColumnName : SequenceFilterFieldName ,
245
+ values : List <SequenceFilterValue >,
246
+ ): SiloFilterExpression {
247
+ return IntBetween (
248
+ siloColumnName,
249
+ from = findIntOfFilterType<SequenceFilterFieldType .IntFrom >(values),
250
+ to = findIntOfFilterType<SequenceFilterFieldType .IntTo >(values),
251
+ )
252
+ }
253
+
254
+ private inline fun <reified T : SequenceFilterFieldType > findIntOfFilterType (
255
+ dateRangeFilters : List <SequenceFilterValue >,
256
+ ): Int? {
257
+ val (_, value, originalKey) = dateRangeFilters.find { (type, _, _) -> type is T } ? : return null
258
+
259
+ try {
260
+ return value.toInt()
261
+ } catch (exception: NumberFormatException ) {
262
+ throw IllegalArgumentException (
263
+ " $originalKey '$value ' is not a valid integer: ${exception.message} " ,
264
+ exception,
265
+ )
266
+ }
267
+ }
268
+
269
+ private fun mapToFloatBetweenFilter (
270
+ siloColumnName : SequenceFilterFieldName ,
271
+ values : List <SequenceFilterValue >,
272
+ ): SiloFilterExpression {
273
+ return FloatBetween (
274
+ siloColumnName,
275
+ from = findFloatOfFilterType<SequenceFilterFieldType .FloatFrom >(values),
276
+ to = findFloatOfFilterType<SequenceFilterFieldType .FloatTo >(values),
277
+ )
278
+ }
279
+
280
+ private inline fun <reified T : SequenceFilterFieldType > findFloatOfFilterType (
281
+ dateRangeFilters : List <SequenceFilterValue >,
282
+ ): Double? {
283
+ val (_, value, originalKey) = dateRangeFilters.find { (type, _, _) -> type is T } ? : return null
284
+
285
+ try {
286
+ return value.toDouble()
287
+ } catch (exception: NumberFormatException ) {
288
+ throw IllegalArgumentException (
289
+ " $originalKey '$value ' is not a valid float: ${exception.message} " ,
290
+ exception,
291
+ )
292
+ }
293
+ }
294
+
165
295
companion object {
166
296
private var NUCLEOTIDE_MUTATION_REGEX : Regex
167
297
@@ -188,6 +318,10 @@ class SiloFilterExpressionMapper(
188
318
DateBetween ,
189
319
NucleotideSymbolEquals ,
190
320
VariantQuery ,
321
+ IntEquals ,
322
+ IntBetween ,
323
+ FloatEquals ,
324
+ FloatBetween ,
191
325
}
192
326
193
327
private val variantQueryTypes = listOf (Filter .PangoLineage , Filter .NucleotideSymbolEquals )
0 commit comments