1+ package org .labkey .test .util .data ;
2+
3+ import org .apache .commons .csv .CSVFormat ;
4+ import org .apache .commons .csv .CSVParser ;
5+ import org .apache .commons .csv .CSVRecord ;
6+ import org .labkey .remoteapi .query .Filter ;
7+
8+ import java .io .IOException ;
9+ import java .io .StringReader ;
10+ import java .util .Comparator ;
11+ import java .util .LinkedHashMap ;
12+ import java .util .List ;
13+ import java .util .Map ;
14+ import java .util .stream .Collectors ;
15+
16+ import static org .labkey .test .util .samplemanagement .SMTestUtils .COL_SAMPLE_ID_NAME ;
17+ import static org .labkey .test .util .samplemanagement .SMTestUtils .COL_SAMPLE_NAME_NAME ;
18+
19+ public class TestArrayDataUtils
20+ {
21+
22+ public static <T > Map <String , T > getMapWithIdAndMultiChoiceField (List <Map <String , T >> data )
23+ {
24+ return data .stream ()
25+ .collect (Collectors .toMap (
26+ row -> String .valueOf (row .get (COL_SAMPLE_NAME_NAME ) != null ? row .get (COL_SAMPLE_NAME_NAME ) : row .get (COL_SAMPLE_ID_NAME )),
27+ row ->
28+ {
29+ String complexKey = row .keySet ().stream ()
30+ .filter (k -> k .contains ("Multi Choice" ))
31+ .findFirst ()
32+ .orElse ("" );
33+ return row .get (complexKey );
34+ }
35+ ));
36+ }
37+
38+ /**
39+ * Filtering Map according to filter and then sorting values in alphabetical order.
40+ *
41+ * @return filtered Map
42+ */
43+ public static <T > Map <String , List <String >> filterMap (Map <String , T > map , List <String > searchValues , Filter .Operator filterType )
44+ {
45+ return map .entrySet ().stream ()
46+ .filter (entry -> entry .getValue () instanceof List )
47+ .map (entry -> Map .entry (entry .getKey (), (List <String >) entry .getValue ()))
48+ .filter (entry -> isMatch (entry .getValue (), searchValues , filterType ))
49+ .collect (Collectors .toMap (
50+ Map .Entry ::getKey ,
51+ e -> e .getValue ().stream ()
52+ // Standard alphabetical sort that accounts for symbols and numbers.
53+ // But uppercase letters are positioned before lowercase letters.
54+ .sorted (Comparator
55+ .comparing ((String s ) -> s .substring (0 , 1 ).toLowerCase ())
56+ .thenComparing (s -> s .substring (0 , 1 ))
57+ .thenComparing (s -> s ))
58+ .collect (Collectors .toList ()),
59+ (e1 , e2 ) -> e1 ,
60+ LinkedHashMap ::new
61+ ));
62+ }
63+
64+ public static Map <String , String > prepareMapForCheck (Map <String , List <String >> map )
65+ {
66+ return map .entrySet ().stream ()
67+ .collect (Collectors .toMap (
68+ Map .Entry ::getKey ,
69+ entry -> String .join (", " , entry .getValue ()),
70+ (e1 , e2 ) -> e1 ,
71+ LinkedHashMap ::new
72+ ));
73+ }
74+
75+ public static <T > Map <String , String > filterAndPrepareMap (Map <String , T > map , List <String > searchValues , Filter .Operator filterType )
76+ {
77+ return prepareMapForCheck (filterMap (map , searchValues , filterType ));
78+ }
79+
80+ public static List <String > parseMultiValueText (String multiValueString ) throws IOException
81+ {
82+ CSVFormat format = CSVFormat .RFC4180 .builder ()
83+ .setIgnoreSurroundingSpaces (true ).setTrim (true ).get ();
84+ try (CSVParser parser = format .parse (new StringReader (multiValueString )))
85+ {
86+ List <CSVRecord > records = parser .getRecords ();
87+ if (records .size () != 1 )
88+ throw new IllegalArgumentException ("Invalid multi-value text string: " + multiValueString );
89+ return records .getFirst ().toList ();
90+ }
91+ }
92+
93+ private static boolean isMatch (List <String > actualValues , List <String > searchValues , Filter .Operator type )
94+ {
95+ return switch (type )
96+ {
97+ case ARRAY_CONTAINS_ALL -> actualValues .containsAll (searchValues );
98+ case ARRAY_CONTAINS_ANY -> searchValues .stream ().anyMatch (actualValues ::contains );
99+ case ARRAY_CONTAINS_EXACT -> actualValues .size () == searchValues .size () && actualValues .containsAll (searchValues );
100+ case ARRAY_CONTAINS_NONE -> searchValues .stream ().noneMatch (actualValues ::contains );
101+ case ARRAY_CONTAINS_NOT_EXACT -> !(actualValues .size () == searchValues .size () && actualValues .containsAll (searchValues ));
102+ case ARRAY_ISEMPTY -> actualValues .isEmpty ();
103+ case ARRAY_ISNOTEMPTY -> !actualValues .isEmpty ();
104+ default -> throw new IllegalArgumentException ("Invalid filter type " + type );
105+ };
106+ }
107+ }
0 commit comments