19
19
import io .hyperfoil .tools .horreum .bus .AsyncEventChannels ;
20
20
import io .hyperfoil .tools .horreum .entity .alerting .DataPointDAO ;
21
21
import io .hyperfoil .tools .horreum .hibernate .JsonBinaryType ;
22
+ import io .hyperfoil .tools .horreum .hibernate .JsonbSetType ;
22
23
import io .hyperfoil .tools .horreum .mapper .DatasetMapper ;
23
24
import jakarta .annotation .security .PermitAll ;
24
25
import jakarta .annotation .security .RolesAllowed ;
@@ -274,37 +275,27 @@ public Object getData(int id, String token, String schemaUri) {
274
275
//this is nearly identical to TestServiceImpl.labelValues (except the return object)
275
276
//this reads from the dataset table but provides data specific to the run...
276
277
@ Override
277
- public List <ExportedLabelValues > labelValues (int runId , String filter , String sort , String direction , int limit , int page , List <String > include , List <String > exclude ){
278
+ public List <ExportedLabelValues > labelValues (int runId , String filter , String sort , String direction , int limit , int page , List <String > include , List <String > exclude , boolean multiFilter ){
278
279
List <ExportedLabelValues > rtrn = new ArrayList <>();
279
280
Run run = getRun (runId ,null );
280
281
if (run == null ){
281
282
throw ServiceException .serverError ("Cannot find run " +runId );
282
283
}
283
284
Object filterObject = Util .getFilterObject (filter );
284
- String filterSql = "" ;
285
- if (filterObject instanceof JsonNode && ((JsonNode )filterObject ).getNodeType () == JsonNodeType .OBJECT ){
286
- filterSql = "WHERE " +TestServiceImpl .LABEL_VALUES_FILTER_CONTAINS_JSON ;
287
- }else {
288
- Util .CheckResult jsonpathResult = Util .castCheck (filter ,"jsonpath" ,em );
289
- if (jsonpathResult .ok ()) {
290
- filterSql = "WHERE " +TestServiceImpl .LABEL_VALUES_FILTER_MATCHES_NOT_NULL ;
291
- } else {
292
- if (filter !=null && filter .startsWith ("{" ) && filter .endsWith ("}" )) {
293
- Util .CheckResult jsonbResult = Util .castCheck (filter , "jsonb" , em );
294
- if (!jsonbResult .ok ()) {
295
- //we expect this error (because filterObject is not JsonNode
296
- } else {
297
- //this would be a surprise and quite a problem
298
- }
299
- } else {
300
- //how do we report back invalid jsonpath
301
- }
302
- }
285
+
286
+ TestServiceImpl .FilterDef filterDef = TestServiceImpl .getFilterDef (filter ,null ,null ,multiFilter ,(str )->
287
+ labelValues (runId ,str ,sort ,direction ,limit ,page ,include ,exclude ,false ),em );
288
+
289
+ String filterSql = filterDef .sql ();
290
+ if (filterDef .filterObject ()!=null ){
291
+ filterObject = filterDef .filterObject ();
303
292
}
293
+
304
294
if (filterSql .isBlank () && filter != null && !filter .isBlank ()){
305
295
//TODO there was an error with the filter, do we return that info to the user?
306
296
}
307
297
String orderSql = "" ;
298
+
308
299
String orderDirection = direction .equalsIgnoreCase ("ascending" ) ? "ASC" : "DESC" ;
309
300
if (!sort .isBlank ()){
310
301
Util .CheckResult jsonpathResult = Util .castCheck (sort , "jsonpath" , em );
@@ -315,12 +306,13 @@ public List<ExportedLabelValues> labelValues(int runId, String filter, String so
315
306
}
316
307
}
317
308
String includeExcludeSql = "" ;
309
+ List <String > mutableInclude = new ArrayList <>(include );
310
+
318
311
if (include !=null && !include .isEmpty ()) {
319
312
if (exclude != null && !exclude .isEmpty ()) {
320
- include = new ArrayList <>(include );
321
- include .removeAll (exclude );
313
+ mutableInclude .removeAll (exclude );
322
314
}
323
- if (!include .isEmpty ()) {
315
+ if (!mutableInclude .isEmpty ()) {
324
316
includeExcludeSql = " AND label.name in :include" ;
325
317
}
326
318
}
@@ -349,12 +341,21 @@ SELECT DISTINCT COALESCE(jsonb_object_agg(label.name, lv.value) FILTER (WHERE la
349
341
if (!filterSql .isEmpty ()) {
350
342
if (filterSql .contains (TestServiceImpl .LABEL_VALUES_FILTER_CONTAINS_JSON )) {
351
343
query .setParameter ("filter" , filterObject , JsonBinaryType .INSTANCE );
352
- } else {
344
+ } else if ( filterSql . contains ( TestServiceImpl . LABEL_VALUES_FILTER_MATCHES_NOT_NULL )) {
353
345
query .setParameter ("filter" , filter );
354
346
}
355
347
}
348
+ if (!filterDef .multis ().isEmpty () && filterDef .filterObject ()!=null ){
349
+ ObjectNode fullFilterObject = (ObjectNode ) Util .getFilterObject (filter );
350
+ for (int i =0 ; i <filterDef .multis ().size (); i ++){
351
+ String key = filterDef .multis ().get (i );
352
+ ArrayNode value = (ArrayNode ) fullFilterObject .get (key );
353
+ query .setParameter ("key" +i ,"$." +key );
354
+ query .setParameter ("value" +i ,value , JsonbSetType .INSTANCE );
355
+ }
356
+ }
356
357
if (includeExcludeSql .contains (":include" )){
357
- query .setParameter ("include" ,include );
358
+ query .setParameter ("include" ,mutableInclude );
358
359
}else if (includeExcludeSql .contains (":exclude" )){
359
360
query .setParameter ("exclude" ,exclude );
360
361
}
@@ -369,7 +370,6 @@ SELECT DISTINCT COALESCE(jsonb_object_agg(label.name, lv.value) FILTER (WHERE la
369
370
.addScalar ("datasetId" ,Integer .class )
370
371
.addScalar ("start" , StandardBasicTypes .INSTANT )
371
372
.addScalar ("stop" , StandardBasicTypes .INSTANT );
372
-
373
373
//casting because type inference cannot detect there will be two scalars in the result
374
374
//TODO replace this with strictly typed entries
375
375
((List <Object []>) query .getResultList ()).forEach (objects ->{
0 commit comments