View Javadoc
1   package de.dlr.shepard.common.search.query;
2   
3   import static org.junit.jupiter.api.Assertions.assertEquals;
4   import static org.junit.jupiter.api.Assertions.assertThrows;
5   
6   import de.dlr.shepard.common.exceptions.ShepardParserException;
7   import de.dlr.shepard.common.neo4j.entities.ContainerType;
8   import de.dlr.shepard.common.search.endpoints.BasicContainerAttributes;
9   import de.dlr.shepard.common.search.io.SearchScope;
10  import de.dlr.shepard.common.util.SortingHelper;
11  import de.dlr.shepard.common.util.TraversalRules;
12  import java.util.stream.Stream;
13  import org.junit.jupiter.api.Test;
14  import org.junit.jupiter.params.ParameterizedTest;
15  import org.junit.jupiter.params.provider.Arguments;
16  import org.junit.jupiter.params.provider.MethodSource;
17  
18  public class Neo4jQueryBuilderTest {
19  
20    private static final String userName = "userName";
21  
22    private static Stream<Arguments> emitCollectionDataObjectReferenceQuerySelectionWithNeo4jIdTest() {
23      var queryEq = Arguments.of(
24        """
25        {
26          "property": "name",
27          "value": "MyName",
28          "operator": "eq"
29        }
30        """,
31        "MATCH (col:Collection)-[:has_dataobject]->(do:DataObject)-[:has_reference]->(br:BasicReference) WHERE (toLower(br.`name`) = \"myname\") AND (id(col) = 1 AND id(do) = 2) AND (br.deleted = FALSE) AND (NOT exists((col)-[:has_permissions]->(:Permissions)) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"userName\" })) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"userName\"})))"
32      );
33      var queryNe = Arguments.of(
34        """
35        {
36          "property": "name",
37          "value": "MyName",
38          "operator": "ne"
39        }
40        """,
41        "MATCH (col:Collection)-[:has_dataobject]->(do:DataObject)-[:has_reference]->(br:BasicReference) WHERE (toLower(br.`name`) <> \"myname\") AND (id(col) = 1 AND id(do) = 2) AND (br.deleted = FALSE) AND (NOT exists((col)-[:has_permissions]->(:Permissions)) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"userName\" })) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"userName\"})))"
42      );
43  
44      return Stream.of(queryEq, queryNe);
45    }
46  
47    @ParameterizedTest
48    @MethodSource
49    public void emitCollectionDataObjectReferenceQuerySelectionWithNeo4jIdTest(String input, String expected) {
50      SearchScope scope = new SearchScope();
51      scope.setCollectionId(1L);
52      scope.setDataObjectId(2L);
53      String neo4jQuery = Neo4jQueryBuilder.collectionDataObjectReferenceSelectionQueryWithNeo4jId(
54        scope,
55        input,
56        userName
57      );
58      assertEquals(expected, neo4jQuery);
59    }
60  
61    private static Stream<Arguments> emitCollectionDataObjectBasicReferenceQuerySelectionWithNeo4jIdTest() {
62      var queryChildren = Arguments.of(
63        """
64        { "property": "name", "value": "MyName", "operator": "eq" }
65        """,
66        TraversalRules.children,
67        "MATCH (col:Collection)-[:has_dataobject]->(d:DataObject)-[:has_child*0..]->(do:DataObject)-[:has_reference]->(br:BasicReference) WHERE (toLower(br.`name`) = \"myname\") AND (id(col) = 1 AND id(d) = 2) AND (br.deleted = FALSE) AND (NOT exists((col)-[:has_permissions]->(:Permissions)) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"userName\" })) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"userName\"})))"
68      );
69      var queryParents = Arguments.of(
70        """
71        { "property": "name", "value": "MyName", "operator": "eq" }
72        """,
73        TraversalRules.parents,
74        "MATCH (col:Collection)-[:has_dataobject]->(d:DataObject)<-[:has_child*0..]-(do:DataObject)-[:has_reference]->(br:BasicReference) WHERE (toLower(br.`name`) = \"myname\") AND (id(col) = 1 AND id(d) = 2) AND (br.deleted = FALSE) AND (NOT exists((col)-[:has_permissions]->(:Permissions)) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"userName\" })) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"userName\"})))"
75      );
76      var querySuccessors = Arguments.of(
77        """
78        { "property": "name", "value": "MyName", "operator": "eq" }
79        """,
80        TraversalRules.successors,
81        "MATCH (col:Collection)-[:has_dataobject]->(d:DataObject)-[:has_successor*0..]->(do:DataObject)-[:has_reference]->(br:BasicReference) WHERE (toLower(br.`name`) = \"myname\") AND (id(col) = 1 AND id(d) = 2) AND (br.deleted = FALSE) AND (NOT exists((col)-[:has_permissions]->(:Permissions)) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"userName\" })) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"userName\"})))"
82      );
83      var queryPredecessors = Arguments.of(
84        """
85        { "property": "name", "value": "MyName", "operator": "eq" }
86        """,
87        TraversalRules.predecessors,
88        "MATCH (col:Collection)-[:has_dataobject]->(d:DataObject)<-[:has_successor*0..]-(do:DataObject)-[:has_reference]->(br:BasicReference) WHERE (toLower(br.`name`) = \"myname\") AND (id(col) = 1 AND id(d) = 2) AND (br.deleted = FALSE) AND (NOT exists((col)-[:has_permissions]->(:Permissions)) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"userName\" })) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"userName\"})))"
89      );
90  
91      return Stream.of(queryChildren, queryParents, querySuccessors, queryPredecessors);
92    }
93  
94    @ParameterizedTest
95    @MethodSource
96    public void emitCollectionDataObjectBasicReferenceQuerySelectionWithNeo4jIdTest(
97      String input,
98      TraversalRules traversalRules,
99      String expected
100   ) {
101     SearchScope scope = new SearchScope();
102     scope.setCollectionId(1L);
103     scope.setDataObjectId(2L);
104     String neo4jQuery = Neo4jQueryBuilder.collectionDataObjectBasicReferenceSelectionQueryWithNeo4jId(
105       scope,
106       traversalRules,
107       input,
108       userName
109     );
110     assertEquals(expected, neo4jQuery);
111   }
112 
113   @Test
114   public void emitCollectionBasicReferenceSelectionQueryWithNeo4jIdTest() {
115     String searchBodyQuery =
116       """
117       { "property": "name", "value": "MyName", "operator": "eq" }""";
118     String neo4jQuery = Neo4jQueryBuilder.collectionBasicReferenceSelectionQueryWithNeo4jId(
119       searchBodyQuery,
120       4L,
121       userName
122     );
123     String expected =
124       "MATCH (col:Collection)-[:has_dataobject]->(do:DataObject)-[:has_reference]->(br:BasicReference) WHERE (toLower(br.`name`) = \"myname\") AND (id(col) = 4) AND (br.deleted = FALSE) AND (NOT exists((col)-[:has_permissions]->(:Permissions)) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"userName\" })) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"userName\"})))";
125     assertEquals(expected, neo4jQuery);
126   }
127 
128   @Test
129   public void emitCollectionBasicReferenceSelectionQueryValueIRIWithNeo4jIdTest() {
130     String searchBodyQuery =
131       """
132       { "property": "valueIRI", "value": "MyName", "operator": "eq" }""";
133     String neo4jQuery = Neo4jQueryBuilder.collectionBasicReferenceSelectionQueryWithNeo4jId(
134       searchBodyQuery,
135       4L,
136       userName
137     );
138     String expected =
139       "MATCH (col:Collection)-[:has_dataobject]->(do:DataObject)-[:has_reference]->(br:BasicReference) WHERE (EXISTS {MATCH (br) - [] -> (sem:SemanticAnnotation) WHERE (sem.valueIRI = \"MyName\")}) AND (id(col) = 4) AND (br.deleted = FALSE) AND (NOT exists((col)-[:has_permissions]->(:Permissions)) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"userName\" })) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"userName\"})))";
140     assertEquals(expected, neo4jQuery);
141   }
142 
143   @Test
144   public void emitCollectionBasicReferenceSelectionQueryPropertyIRIWithNeo4jIdTest() {
145     String searchBodyQuery =
146       """
147       { "property": "propertyIRI", "value": "MyName", "operator": "eq" }""";
148     String neo4jQuery = Neo4jQueryBuilder.collectionBasicReferenceSelectionQueryWithNeo4jId(
149       searchBodyQuery,
150       4L,
151       userName
152     );
153     String expected =
154       "MATCH (col:Collection)-[:has_dataobject]->(do:DataObject)-[:has_reference]->(br:BasicReference) WHERE (EXISTS {MATCH (br) - [] -> (sem:SemanticAnnotation) WHERE (sem.propertyIRI = \"MyName\")}) AND (id(col) = 4) AND (br.deleted = FALSE) AND (NOT exists((col)-[:has_permissions]->(:Permissions)) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"userName\" })) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"userName\"})))";
155     assertEquals(expected, neo4jQuery);
156   }
157 
158   @Test
159   public void emitBasicReferenceSelectionQueryWithNeo4jIdTest() {
160     String searchBodyQuery =
161       """
162       { "property": "name", "value": "MyName", "operator": "eq" }""";
163     String neo4jQuery = Neo4jQueryBuilder.basicReferenceSelectionQueryWithNeo4jId(searchBodyQuery, userName);
164     String expected =
165       "MATCH (col:Collection)-[:has_dataobject]->(do:DataObject)-[:has_reference]->(br:BasicReference) WHERE (toLower(br.`name`) = \"myname\") AND (br.deleted = FALSE) AND (NOT exists((col)-[:has_permissions]->(:Permissions)) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"userName\" })) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"userName\"})))";
166     assertEquals(expected, neo4jQuery);
167   }
168 
169   @Test
170   public void emitDataObjectQueryTest() {
171     String searchBodyQuery =
172       """
173       {
174       "property": "name", "value": "MyName", "operator": "eq" }""";
175     String neo4jQuery = Neo4jQueryBuilder.dataObjectSelectionQueryWithNeo4jId(searchBodyQuery, userName);
176     String expected =
177       "MATCH (col:Collection)-[:has_dataobject]->(do:DataObject) WHERE (toLower(do.`name`) = \"myname\") AND (do.deleted = FALSE) AND (NOT exists((col)-[:has_permissions]->(:Permissions)) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"userName\" })) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"userName\"})))";
178     assertEquals(expected, neo4jQuery);
179   }
180 
181   @Test
182   public void emitCollectionDataObjectDataObjectSelectionQueryWithNeo4jIdTest() {
183     SearchScope scope = new SearchScope();
184     scope.setCollectionId(1L);
185     scope.setDataObjectId(2L);
186     String searchBodyQuery =
187       """
188       { "property": "name", "value": "MyName", "operator": "eq" }""";
189     String neo4jQuery = Neo4jQueryBuilder.collectionDataObjectDataObjectSelectionQueryWithNeo4jId(
190       scope,
191       searchBodyQuery,
192       userName
193     );
194     String expected =
195       "MATCH (col:Collection)-[:has_dataobject]->(do:DataObject) WHERE (toLower(do.`name`) = \"myname\") AND (id(col) = 1 AND id(do) = 2) AND (do.deleted = FALSE) AND (NOT exists((col)-[:has_permissions]->(:Permissions)) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"userName\" })) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"userName\"})))";
196     assertEquals(expected, neo4jQuery);
197   }
198 
199   @Test
200   public void emitCollectionDataObjectDataObjectSelectionQueryChildrenWithNeo4jIdTest() {
201     SearchScope scope = new SearchScope();
202     scope.setCollectionId(1L);
203     scope.setDataObjectId(2L);
204     String searchBodyQuery =
205       """
206       { "property": "name", "value": "MyName", "operator": "eq" }""";
207     String neo4jQuery = Neo4jQueryBuilder.collectionDataObjectDataObjectSelectionQueryWithNeo4jId(
208       scope,
209       TraversalRules.children,
210       searchBodyQuery,
211       userName
212     );
213     String expected =
214       "MATCH (col:Collection)-[:has_dataobject]->(d:DataObject)-[:has_child*0..]->(do:DataObject) WHERE (toLower(do.`name`) = \"myname\") AND (id(col) = 1 AND id(d) = 2) AND (do.deleted = FALSE) AND (NOT exists((col)-[:has_permissions]->(:Permissions)) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"userName\" })) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"userName\"})))";
215     assertEquals(expected, neo4jQuery);
216   }
217 
218   @Test
219   public void emitCollectionDataObjectDataObjectSelectionQueryPredecessorsWithNeo4jTest() {
220     SearchScope scope = new SearchScope();
221     scope.setCollectionId(1L);
222     scope.setDataObjectId(2L);
223     String searchBodyQuery =
224       """
225       { "property": "name", "value": "MyName", "operator": "eq" }""";
226     String neo4jQuery = Neo4jQueryBuilder.collectionDataObjectDataObjectSelectionQueryWithNeo4jId(
227       scope,
228       TraversalRules.predecessors,
229       searchBodyQuery,
230       userName
231     );
232     String expected =
233       "MATCH (col:Collection)-[:has_dataobject]->(d:DataObject)<-[:has_successor*0..]-(do:DataObject) WHERE (toLower(do.`name`) = \"myname\") AND (id(col) = 1 AND id(d) = 2) AND (do.deleted = FALSE) AND (NOT exists((col)-[:has_permissions]->(:Permissions)) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"userName\" })) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"userName\"})))";
234     assertEquals(expected, neo4jQuery);
235   }
236 
237   @Test
238   public void emitCollectionDataObjectQueryWithNeo4jIdTest() {
239     SearchScope scope = new SearchScope();
240     scope.setCollectionId(1L);
241     scope.setDataObjectId(2L);
242     String searchBodyQuery =
243       """
244       { "property": "name", "value": "MyName", "operator": "eq" }""";
245     String neo4jQuery = Neo4jQueryBuilder.collectionDataObjectSelectionQueryWithNeo4jId(
246       scope.getCollectionId(),
247       searchBodyQuery,
248       userName
249     );
250     String expected =
251       "MATCH (col:Collection)-[:has_dataobject]->(do:DataObject) WHERE (toLower(do.`name`) = \"myname\") AND (id(col) = 1) AND (do.deleted = FALSE) AND (NOT exists((col)-[:has_permissions]->(:Permissions)) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"userName\" })) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"userName\"})))";
252     assertEquals(expected, neo4jQuery);
253   }
254 
255   private static Stream<Arguments> emitCollectionQueryWithNeo4jIdTest() {
256     var queryEq = Arguments.of(
257       """
258       {
259          "property":"name",
260          "value":"MyName",
261          "operator":"eq"
262       }""",
263       "MATCH (col:Collection) WHERE (toLower(col.`name`) = \"myname\") AND (col.deleted = FALSE) AND (NOT exists((col)-[:has_permissions]->(:Permissions)) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"userName\" })) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"userName\"})))"
264     );
265     var queryOrGtContains = Arguments.of(
266       """
267       {
268          "OR":[
269             {
270                "property":"createdAt",
271                "value":"2021-05-12",
272                "operator":"gt"
273             },
274             {
275                "property":"attributes||b",
276                "value":"abc",
277                "operator":"contains"
278             }
279          ]
280       }""",
281       "MATCH (col:Collection) WHERE ((col.createdAt > \"2021-05-12\") OR (toLower(col.`attributes||b`) contains \"abc\")) AND (col.deleted = FALSE) AND (NOT exists((col)-[:has_permissions]->(:Permissions)) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"userName\" })) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"userName\"})))"
282     );
283     var queryAndGtContains = Arguments.of(
284       """
285       {
286          "AND":[
287             {
288                "property":"createdAt",
289                "value":"2021-05-12",
290                "operator":"gt"
291             },
292             {
293                "property":"attributes||b",
294                "value":"abc",
295                "operator":"contains"
296             }
297          ]
298       }""",
299       "MATCH (col:Collection) WHERE ((col.createdAt > \"2021-05-12\") AND (toLower(col.`attributes||b`) contains \"abc\")) AND (col.deleted = FALSE) AND (NOT exists((col)-[:has_permissions]->(:Permissions)) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"userName\" })) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"userName\"})))"
300     );
301     var queryNot = Arguments.of(
302       """
303       {
304          "NOT":{
305             "property":"attributes||b",
306             "value":"abc",
307             "operator":"contains"
308          }
309       }""",
310       "MATCH (col:Collection) WHERE (NOT((toLower(col.`attributes||b`) contains \"abc\"))) AND (col.deleted = FALSE) AND (NOT exists((col)-[:has_permissions]->(:Permissions)) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"userName\" })) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"userName\"})))"
311     );
312     var queryAndReferencedCollectionIdReferencedDataObjectId = Arguments.of(
313       """
314       {
315          "AND":[
316             {
317                "property":"referencedCollectionId",
318                "value":"2021-05-12",
319                "operator":"le"
320             },
321             {
322                "property":"referencedDataObjectId",
323                "value":"abc",
324                "operator":"contains"
325             }
326          ]
327       }""",
328       "MATCH (col:Collection) WHERE ((EXISTS {MATCH (col)-[:points_to]->(refCol:Collection) WHERE id(refCol) <= \"2021-05-12\" }) AND (EXISTS {MATCH (col)-[:points_to]->(refDo:DataObject) WHERE id(refDo) contains \"abc\" })) AND (col.deleted = FALSE) AND (NOT exists((col)-[:has_permissions]->(:Permissions)) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"userName\" })) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"userName\"})))"
329     );
330     var queryAndCreatedByGtUpdatedBy = Arguments.of(
331       """
332       {
333          "AND":[
334             {
335                "property":"createdBy",
336                "value":"2021-05-12",
337                "operator":"gt"
338             },
339             {
340                "property":"updatedBy",
341                "value":"abc",
342                "operator":"contains"
343             }
344          ]
345       }""",
346       "MATCH (col:Collection) WHERE ((EXISTS {MATCH (col) - [:created_by] -> (u) WHERE toLower(u.username) > \"2021-05-12\" }) AND (EXISTS {MATCH (col) - [:updated_by] -> (u) WHERE toLower(u.username) contains \"abc\" })) AND (col.deleted = FALSE) AND (NOT exists((col)-[:has_permissions]->(:Permissions)) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"userName\" })) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"userName\"})))"
347     );
348     var queryAndFileContainerIdStructuredDataContainerIdLtGe = Arguments.of(
349       """
350       {
351          "AND":[
352             {
353                "property":"fileContainerId",
354                "value":23,
355                "operator":"lt"
356             },
357             {
358                "property":"structuredDataContainerId",
359                "value":"abc",
360                "operator":"ge"
361             }
362          ]
363       }""",
364       "MATCH (col:Collection) WHERE ((EXISTS {MATCH (col)-[:is_in_container]->(refCon:FileContainer) WHERE id(refCon) < 23 }) AND (EXISTS {MATCH (col)-[:is_in_container]->(refCon:StructuredDataContainer) WHERE id(refCon) >= \"abc\" })) AND (col.deleted = FALSE) AND (NOT exists((col)-[:has_permissions]->(:Permissions)) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"userName\" })) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"userName\"})))"
365     );
366     var querytimeseriesContainerIdId = Arguments.of(
367       """
368       {
369          "AND":[
370             {
371                "property":"timeseriesContainerId",
372                "value":"2021-05-12",
373                "operator":"gt"
374             },
375             {
376                "property":"id",
377                "value":"abc",
378                "operator":"contains"
379             }
380          ]
381       }""",
382       "MATCH (col:Collection) WHERE ((EXISTS {MATCH (col)-[:is_in_container]->(refCon:TimeseriesContainer) WHERE id(refCon) > \"2021-05-12\" }) AND (id(col) contains \"abc\")) AND (col.deleted = FALSE) AND (NOT exists((col)-[:has_permissions]->(:Permissions)) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"userName\" })) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"userName\"})))"
383     );
384     var queryNotIn = Arguments.of(
385       """
386       {
387          "NOT":{
388             "property":"attributes||b",
389             "value":[
390                1,
391                2,
392                "e"
393             ],
394             "operator":"in"
395          }
396       }""",
397       "MATCH (col:Collection) WHERE (NOT((toLower(col.`attributes||b`) IN [1, 2, \"e\"]))) AND (col.deleted = FALSE) AND (NOT exists((col)-[:has_permissions]->(:Permissions)) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"userName\" })) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"userName\"})))"
398     );
399     var queryIn = Arguments.of(
400       """
401       {
402          "property":"attributes||b",
403          "value": [],
404          "operator":"in"
405       }""",
406       "MATCH (col:Collection) WHERE (toLower(col.`attributes||b`) IN []) AND (col.deleted = FALSE) AND (NOT exists((col)-[:has_permissions]->(:Permissions)) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"userName\" })) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"userName\"})))"
407     );
408 
409     return Stream.of(
410       queryEq,
411       queryOrGtContains,
412       queryAndGtContains,
413       queryNot,
414       queryAndReferencedCollectionIdReferencedDataObjectId,
415       queryAndCreatedByGtUpdatedBy,
416       queryAndFileContainerIdStructuredDataContainerIdLtGe,
417       querytimeseriesContainerIdId,
418       queryNotIn,
419       queryIn
420     );
421   }
422 
423   @ParameterizedTest
424   @MethodSource
425   public void emitCollectionQueryWithNeo4jIdTest(String input, String expected) {
426     String neo4jQuery = Neo4jQueryBuilder.collectionSelectionQueryWithNeo4jId(
427       input,
428       userName,
429       new SortingHelper(null, null)
430     );
431     assertEquals(expected, neo4jQuery);
432   }
433 
434   private static Stream<Arguments> emitCollectionDataObjectDataObjectSelectionQueryTraversalWithNeo4jIdTest() {
435     var queryParents = Arguments.of(
436       """
437       { "property": "name", "value": "MyName", "operator": "eq" }
438       """,
439       TraversalRules.parents,
440       "MATCH (col:Collection)-[:has_dataobject]->(d:DataObject)<-[:has_child*0..]-(do:DataObject) WHERE (toLower(do.`name`) = \"myname\") AND (id(col) = 1 AND id(d) = 2) AND (do.deleted = FALSE) AND (NOT exists((col)-[:has_permissions]->(:Permissions)) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"userName\" })) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"userName\"})))"
441     );
442     var queryChildren = Arguments.of(
443       """
444       { "property": "name", "value": "MyName", "operator": "eq" }
445       """,
446       TraversalRules.children,
447       "MATCH (col:Collection)-[:has_dataobject]->(d:DataObject)-[:has_child*0..]->(do:DataObject) WHERE (toLower(do.`name`) = \"myname\") AND (id(col) = 1 AND id(d) = 2) AND (do.deleted = FALSE) AND (NOT exists((col)-[:has_permissions]->(:Permissions)) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"userName\" })) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"userName\"})))"
448     );
449     var queryPredecessors = Arguments.of(
450       """
451       { "property": "name", "value": "MyName", "operator": "eq"}
452       """,
453       TraversalRules.predecessors,
454       "MATCH (col:Collection)-[:has_dataobject]->(d:DataObject)<-[:has_successor*0..]-(do:DataObject) WHERE (toLower(do.`name`) = \"myname\") AND (id(col) = 1 AND id(d) = 2) AND (do.deleted = FALSE) AND (NOT exists((col)-[:has_permissions]->(:Permissions)) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"userName\" })) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"userName\"})))"
455     );
456     var querySuccessors = Arguments.of(
457       """
458       { "property": "name", "value": "MyName", "operator": "eq" }
459       """,
460       TraversalRules.successors,
461       "MATCH (col:Collection)-[:has_dataobject]->(d:DataObject)-[:has_successor*0..]->(do:DataObject) WHERE (toLower(do.`name`) = \"myname\") AND (id(col) = 1 AND id(d) = 2) AND (do.deleted = FALSE) AND (NOT exists((col)-[:has_permissions]->(:Permissions)) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"userName\" })) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((col)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((col)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"userName\"})))"
462     );
463     return Stream.of(queryParents, queryChildren, queryPredecessors, querySuccessors);
464   }
465 
466   @ParameterizedTest
467   @MethodSource
468   public void emitCollectionDataObjectDataObjectSelectionQueryTraversalWithNeo4jIdTest(
469     String input,
470     TraversalRules traversalRules,
471     String expected
472   ) {
473     SearchScope scope = new SearchScope();
474     scope.setCollectionId(1L);
475     scope.setDataObjectId(2L);
476     String neo4jQuery = Neo4jQueryBuilder.collectionDataObjectDataObjectSelectionQueryWithNeo4jId(
477       scope,
478       traversalRules,
479       input,
480       userName
481     );
482     assertEquals(expected, neo4jQuery);
483   }
484 
485   @Test
486   public void emitStructuredDataContainerSelectionQueryWithNeo4jIdTest() {
487     String JSONQuery = "{\"property\": \"name\", \"value\": \"MyName\", \"operator\": \"eq\"}";
488     String userName = "MarxKarl";
489     String neo4jQuery = Neo4jQueryBuilder.containerSelectionQueryWithNeo4jId(
490       JSONQuery,
491       ContainerType.STRUCTUREDDATA,
492       new SortingHelper(null, null),
493       userName
494     );
495     String expected =
496       "MATCH (sdc:StructuredDataContainer) WHERE (toLower(sdc.`name`) = \"myname\") AND (sdc.deleted = FALSE) AND (NOT exists((sdc)-[:has_permissions]->(:Permissions)) OR exists((sdc)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"MarxKarl\" })) OR exists((sdc)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((sdc)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((sdc)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"MarxKarl\"})))";
497     assertEquals(expected, neo4jQuery);
498   }
499 
500   @Test
501   public void emitTimeseriesContainerSelectionQueryWithNeo4jIdTest() {
502     String JSONQuery = "{\"property\": \"name\", \"value\": \"MyName\", \"operator\": \"eq\"}";
503     String userName = "MarxKarl";
504     String neo4jQuery = Neo4jQueryBuilder.containerSelectionQueryWithNeo4jId(
505       JSONQuery,
506       ContainerType.TIMESERIES,
507       new SortingHelper(null, null),
508       userName
509     );
510     String expected =
511       "MATCH (tsc:TimeseriesContainer) WHERE (toLower(tsc.`name`) = \"myname\") AND (tsc.deleted = FALSE) AND (NOT exists((tsc)-[:has_permissions]->(:Permissions)) OR exists((tsc)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"MarxKarl\" })) OR exists((tsc)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((tsc)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((tsc)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"MarxKarl\"})))";
512     assertEquals(expected, neo4jQuery);
513   }
514 
515   @Test
516   public void emitFileContainerSelectionQueryWithNeo4jIdTest() {
517     String JSONQuery = "{\"property\": \"name\", \"value\": \"MyName\", \"operator\": \"eq\"}";
518     String userName = "GatesWilliam";
519     String neo4jQuery = Neo4jQueryBuilder.containerSelectionQueryWithNeo4jId(
520       JSONQuery,
521       ContainerType.FILE,
522       new SortingHelper(null, null),
523       userName
524     );
525     String expected =
526       "MATCH (fc:FileContainer) WHERE (toLower(fc.`name`) = \"myname\") AND (fc.deleted = FALSE) AND (NOT exists((fc)-[:has_permissions]->(:Permissions)) OR exists((fc)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"GatesWilliam\" })) OR exists((fc)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((fc)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((fc)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"GatesWilliam\"})))";
527     assertEquals(expected, neo4jQuery);
528   }
529 
530   @Test
531   public void emitFileContainerSelectionQueryWithNeo4jIdIdTest() {
532     String JSONQuery = "{\"property\": \"id\", \"value\": \"MyName\", \"operator\": \"eq\"}";
533     String userName = "GatesWilliam";
534     String neo4jQuery = Neo4jQueryBuilder.containerSelectionQueryWithNeo4jId(
535       JSONQuery,
536       ContainerType.FILE,
537       new SortingHelper(null, null),
538       userName
539     );
540     String expected =
541       "MATCH (fc:FileContainer) WHERE (id(fc) = \"MyName\") AND (fc.deleted = FALSE) AND (NOT exists((fc)-[:has_permissions]->(:Permissions)) OR exists((fc)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"GatesWilliam\" })) OR exists((fc)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((fc)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((fc)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"GatesWilliam\"})))";
542     assertEquals(expected, neo4jQuery);
543   }
544 
545   @Test
546   public void emitFileContainerSelectionQueryInWithNeo4jIdTest() {
547     String JSONQuery = "{\"property\": \"id\", \"value\": [1,2], \"operator\": \"in\"}";
548     String userName = "GatesWilliam";
549     String neo4jQuery = Neo4jQueryBuilder.containerSelectionQueryWithNeo4jId(
550       JSONQuery,
551       ContainerType.FILE,
552       new SortingHelper(null, null),
553       userName
554     );
555     String expected =
556       "MATCH (fc:FileContainer) WHERE (id(fc) IN [1, 2]) AND (fc.deleted = FALSE) AND (NOT exists((fc)-[:has_permissions]->(:Permissions)) OR exists((fc)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"GatesWilliam\" })) OR exists((fc)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((fc)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((fc)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"GatesWilliam\"})))";
557     assertEquals(expected, neo4jQuery);
558   }
559 
560   @Test
561   public void emitFileContainerSelectionQueryInEmptyWithNeo4jIdTest() {
562     String JSONQuery = "{\"property\": \"id\", \"value\": [], \"operator\": \"in\"}";
563     String userName = "GatesWilliam";
564     String neo4jQuery = Neo4jQueryBuilder.containerSelectionQueryWithNeo4jId(
565       JSONQuery,
566       ContainerType.FILE,
567       new SortingHelper(null, null),
568       userName
569     );
570     String expected =
571       "MATCH (fc:FileContainer) WHERE (id(fc) IN []) AND (fc.deleted = FALSE) AND (NOT exists((fc)-[:has_permissions]->(:Permissions)) OR exists((fc)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"GatesWilliam\" })) OR exists((fc)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((fc)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((fc)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"GatesWilliam\"})))";
572     assertEquals(expected, neo4jQuery);
573   }
574 
575   @Test
576   public void emitFileContainerSelectionQueryNotWithNeo4jIdTest() {
577     String JSONQuery = "{\"NOT\":{\"property\": \"name\", \"value\": \"MyName\", \"operator\": \"eq\"}}";
578     String userName = "GatesWilliam";
579     String neo4jQuery = Neo4jQueryBuilder.containerSelectionQueryWithNeo4jId(
580       JSONQuery,
581       ContainerType.FILE,
582       new SortingHelper(null, null),
583       userName
584     );
585     String expected =
586       "MATCH (fc:FileContainer) WHERE (NOT((toLower(fc.`name`) = \"myname\"))) AND (fc.deleted = FALSE) AND (NOT exists((fc)-[:has_permissions]->(:Permissions)) OR exists((fc)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"GatesWilliam\" })) OR exists((fc)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((fc)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((fc)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"GatesWilliam\"})))";
587     assertEquals(expected, neo4jQuery);
588   }
589 
590   @Test
591   public void emitFileContainerSelectionQueryAndWithNeo4jIdTest() {
592     String JSONQuery =
593       "{\"AND\":[{\"property\": \"createdBy\", \"value\": \"MyName\", \"operator\": \"eq\"}," +
594       "{\"property\": \"updatedBy\", \"value\": \"MyName\", \"operator\": \"eq\"}]}";
595     String userName = "GatesWilliam";
596     String neo4jQuery = Neo4jQueryBuilder.containerSelectionQueryWithNeo4jId(
597       JSONQuery,
598       ContainerType.FILE,
599       new SortingHelper(null, null),
600       userName
601     );
602     String expected =
603       "MATCH (fc:FileContainer) WHERE ((EXISTS {MATCH (fc) - [:created_by] -> (u) WHERE toLower(u.username) = \"myname\" }) AND (EXISTS {MATCH (fc) - [:updated_by] -> (u) WHERE toLower(u.username) = \"myname\" })) AND (fc.deleted = FALSE) AND (NOT exists((fc)-[:has_permissions]->(:Permissions)) OR exists((fc)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"GatesWilliam\" })) OR exists((fc)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((fc)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((fc)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"GatesWilliam\"})))";
604     assertEquals(expected, neo4jQuery);
605   }
606 
607   @Test
608   public void emitFileContainerSelectionQueryOrWithNeo4jIdTest() {
609     String JSONQuery =
610       "{\"OR\":[{\"property\": \"valueIRI\", \"value\": \"MyName\", \"operator\": \"eq\"}," +
611       "{\"property\": \"propertyIRI\", \"value\": \"MyName\", \"operator\": \"eq\"}]}";
612     String userName = "GatesWilliam";
613     String neo4jQuery = Neo4jQueryBuilder.containerSelectionQueryWithNeo4jId(
614       JSONQuery,
615       ContainerType.FILE,
616       new SortingHelper(null, null),
617       userName
618     );
619     String expected =
620       "MATCH (fc:FileContainer) WHERE ((EXISTS {MATCH (fc) - [] -> (sem:SemanticAnnotation) WHERE (sem.valueIRI = \"MyName\")}) OR (EXISTS {MATCH (fc) - [] -> (sem:SemanticAnnotation) WHERE (sem.propertyIRI = \"MyName\")})) AND (fc.deleted = FALSE) AND (NOT exists((fc)-[:has_permissions]->(:Permissions)) OR exists((fc)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"GatesWilliam\" })) OR exists((fc)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((fc)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((fc)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"GatesWilliam\"})))";
621     assertEquals(expected, neo4jQuery);
622   }
623 
624   @Test
625   public void emitFileContainerSelectionQueryCollectionDataObjectWithNeo4jIdTest() {
626     String JSONQuery =
627       "{\"OR\":[{\"property\": \"referencedCollectionId\", \"value\": \"5\", \"operator\": \"eq\"}," +
628       "{\"property\": \"referencedDataObjectId\", \"value\": \"6\", \"operator\": \"eq\"}]}";
629     String userName = "GatesWilliam";
630     String neo4jQuery = Neo4jQueryBuilder.containerSelectionQueryWithNeo4jId(
631       JSONQuery,
632       ContainerType.FILE,
633       new SortingHelper(null, null),
634       userName
635     );
636     String expected =
637       "MATCH (fc:FileContainer) WHERE ((EXISTS {MATCH (fc)-[:points_to]->(refCol:Collection) WHERE id(refCol) = \"5\" }) OR (EXISTS {MATCH (fc)-[:points_to]->(refDo:DataObject) WHERE id(refDo) = \"6\" })) AND (fc.deleted = FALSE) AND (NOT exists((fc)-[:has_permissions]->(:Permissions)) OR exists((fc)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"GatesWilliam\" })) OR exists((fc)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((fc)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((fc)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"GatesWilliam\"})))";
638     assertEquals(expected, neo4jQuery);
639   }
640 
641   @Test
642   public void emitFileContainerSelectionContainerTest() {
643     String JSONQuery =
644       "{\"OR\":[{\"property\": \"fileContainerId\", \"value\": \"5\", \"operator\": \"eq\"}," +
645       "{\"property\": \"structuredDataContainerId\", \"value\": \"6\", \"operator\": \"eq\"}," +
646       "{\"property\": \"timeseriesContainerId\", \"value\": \"7\", \"operator\": \"eq\"}]}";
647     String userName = "GatesWilliam";
648     String neo4jQuery = Neo4jQueryBuilder.containerSelectionQueryWithNeo4jId(
649       JSONQuery,
650       ContainerType.FILE,
651       new SortingHelper(null, null),
652       userName
653     );
654     String expected =
655       "MATCH (fc:FileContainer) WHERE ((EXISTS {MATCH (fc)-[:is_in_container]->(refCon:FileContainer) WHERE id(refCon) = \"5\" }) OR (EXISTS {MATCH (fc)-[:is_in_container]->(refCon:StructuredDataContainer) WHERE id(refCon) = \"6\" }) OR (EXISTS {MATCH (fc)-[:is_in_container]->(refCon:TimeseriesContainer) WHERE id(refCon) = \"7\" })) AND (fc.deleted = FALSE) AND (NOT exists((fc)-[:has_permissions]->(:Permissions)) OR exists((fc)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"GatesWilliam\" })) OR exists((fc)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((fc)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((fc)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"GatesWilliam\"})))";
656     assertEquals(expected, neo4jQuery);
657   }
658 
659   @Test
660   public void emitBasicContainerSortedSelectionContainerTest() {
661     String JSONQuery =
662       "{\"OR\":[{\"property\": \"fileContainerId\", \"value\": \"5\", \"operator\": \"eq\"}," +
663       "{\"property\": \"structuredDataContainerId\", \"value\": \"6\", \"operator\": \"eq\"}," +
664       "{\"property\": \"timeseriesContainerId\", \"value\": \"7\", \"operator\": \"eq\"}]}";
665     String userName = "GatesWilliam";
666     String neo4jQuery = Neo4jQueryBuilder.containerSelectionQueryWithNeo4jId(
667       JSONQuery,
668       ContainerType.BASIC,
669       new SortingHelper(BasicContainerAttributes.name, null),
670       userName
671     );
672     String expected =
673       "MATCH (bc:BasicContainer) WHERE ((EXISTS {MATCH (bc)-[:is_in_container]->(refCon:FileContainer) WHERE id(refCon) = \"5\" }) OR (EXISTS {MATCH (bc)-[:is_in_container]->(refCon:StructuredDataContainer) WHERE id(refCon) = \"6\" }) OR (EXISTS {MATCH (bc)-[:is_in_container]->(refCon:TimeseriesContainer) WHERE id(refCon) = \"7\" })) AND (bc.deleted = FALSE) AND (NOT exists((bc)-[:has_permissions]->(:Permissions)) OR exists((bc)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"GatesWilliam\" })) OR exists((bc)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) OR exists((bc)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) OR exists((bc)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"GatesWilliam\"}))) ORDER BY toLower(bc.name)";
674     assertEquals(expected, neo4jQuery);
675   }
676 
677   @Test
678   public void emitUserSelectionQueryTest() {
679     String JSONQuery = "{\"property\": \"username\", \"value\": \"user\", \"operator\": \"eq\"}";
680     String neo4jQuery = Neo4jQueryBuilder.userSelectionQuery(JSONQuery);
681     String expected = "MATCH (user:User) WHERE (toLower(user.`username`) = \"user\")";
682     assertEquals(expected, neo4jQuery);
683   }
684 
685   @Test
686   public void emitUserGroupSelectionQueryTest() {
687     String JSONQuery = "{\"property\": \"name\", \"value\": \"group\", \"operator\": \"contains\"}";
688     String neo4jQuery = Neo4jQueryBuilder.userGroupSelectionQuery(JSONQuery);
689     String expected = "MATCH (userGroup:UserGroup) WHERE (toLower(userGroup.`name`) contains \"group\")";
690     assertEquals(expected, neo4jQuery);
691   }
692 
693   @Test
694   public void invalidJsonTest() {
695     String JSONQuery = "}";
696     assertThrows(ShepardParserException.class, () ->
697       Neo4jQueryBuilder.collectionSelectionQueryWithNeo4jId(JSONQuery, userName, new SortingHelper(null, null))
698     );
699   }
700 
701   @Test
702   public void emptyJsonTest() {
703     String JSONQuery = "{}";
704     assertThrows(ShepardParserException.class, () ->
705       Neo4jQueryBuilder.collectionSelectionQueryWithNeo4jId(JSONQuery, userName, new SortingHelper(null, null))
706     );
707   }
708 
709   @Test
710   public void invalidOperatorTest() {
711     String searchBodyQuery =
712       """
713       { "property": "name", "value": "MyName", "operator": "bla" }""";
714     assertThrows(ShepardParserException.class, () ->
715       Neo4jQueryBuilder.collectionSelectionQueryWithNeo4jId(searchBodyQuery, userName, new SortingHelper(null, null))
716     );
717   }
718 
719   @Test
720   public void invalidBooleanOperatorTest() {
721     String JSONQuery =
722       """
723       { "invalid": { "property": "name", "value": "MyName", "operator": "eq" } }""";
724     assertThrows(ShepardParserException.class, () ->
725       Neo4jQueryBuilder.collectionSelectionQueryWithNeo4jId(JSONQuery, userName, new SortingHelper(null, null))
726     );
727   }
728 }