View Javadoc
1   package de.dlr.shepard.context.collection.daos;
2   
3   import static org.junit.jupiter.api.Assertions.assertEquals;
4   import static org.junit.jupiter.api.Assertions.assertTrue;
5   import static org.mockito.Mockito.doReturn;
6   import static org.mockito.Mockito.spy;
7   import static org.mockito.Mockito.verify;
8   import static org.mockito.Mockito.when;
9   
10  import de.dlr.shepard.BaseTestCase;
11  import de.dlr.shepard.auth.users.entities.User;
12  import de.dlr.shepard.common.neo4j.daos.GenericDAO;
13  import de.dlr.shepard.common.util.CypherQueryHelper;
14  import de.dlr.shepard.common.util.QueryParamHelper;
15  import de.dlr.shepard.context.collection.endpoints.DataObjectAttributes;
16  import de.dlr.shepard.context.collection.entities.Collection;
17  import java.util.Collections;
18  import java.util.Date;
19  import java.util.HashMap;
20  import java.util.List;
21  import java.util.Map;
22  import org.junit.jupiter.api.Test;
23  import org.mockito.InjectMocks;
24  import org.mockito.Mock;
25  import org.neo4j.ogm.session.Session;
26  
27  public class CollectionDAOTest extends BaseTestCase {
28  
29    @Mock
30    private Session session;
31  
32    @Mock
33    private GenericDAO<?> genericDao;
34  
35    @InjectMocks
36    private CollectionDAO dao;
37  
38    @Test
39    public void getEntityTypeTest() {
40      var type = dao.getEntityType();
41      assertEquals(Collection.class, type);
42    }
43  
44    @Test
45    public void findAll_WithoutName() {
46      var col1 = new Collection(1L);
47      col1.setName("Yes");
48      Map<String, Object> paramsMap = new HashMap<>();
49      paramsMap.put("name", null);
50  
51      var query =
52        """
53        MATCH (c:Collection { deleted: FALSE }) WHERE (NOT exists((c)-[:has_permissions]->(:Permissions)) \
54        OR exists((c)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: "bob" })) \
55        OR exists((c)-[:has_permissions]->(:Permissions {permissionType: "Public"})) \
56        OR exists((c)-[:has_permissions]->(:Permissions {permissionType: "PublicReadable"})) \
57        OR exists((c)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: "bob"}))) \
58        WITH c MATCH path=(c)-[*0..1]-(n) WHERE n.deleted = FALSE OR n.deleted IS NULL RETURN c, nodes(path), relationships(path)""";
59      when(session.query(Collection.class, query, paramsMap)).thenReturn(List.of(col1));
60  
61      var params = new QueryParamHelper();
62      var actual = dao.findAllCollectionsByNeo4jId(params, "bob");
63      verify(session).query(Collection.class, query, paramsMap);
64      assertEquals(List.of(col1), actual);
65    }
66  
67    @Test
68    public void findAllByShepardQueryParams_WithoutName() {
69      var col1 = new Collection(1L);
70      col1.setShepardId(11L);
71      col1.setName("Yes");
72      Map<String, Object> paramsMap = new HashMap<>();
73      paramsMap.put("name", null);
74  
75      var query =
76        """
77        MATCH (c:Collection { deleted: FALSE })-[:has_version]->(v:Version) WHERE (NOT exists((c)-[:has_permissions]->(:Permissions)) \
78        OR exists((c)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"bob\" })) \
79        OR exists((c)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) \
80        OR exists((c)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) \
81        OR exists((c)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"bob\"}))) \
82        AND""" +
83        " " +
84        CypherQueryHelper.getVersionHeadPart("v") +
85        " " +
86        """
87        WITH c MATCH path=(c)-[*0..1]-(n) WHERE n.deleted = FALSE OR n.deleted IS NULL RETURN c, nodes(path), relationships(path)""";
88      when(session.query(Collection.class, query, paramsMap)).thenReturn(List.of(col1));
89  
90      var params = new QueryParamHelper();
91      var actual = dao.findAllCollectionsByShepardId(params, "bob");
92      verify(session).query(Collection.class, query, paramsMap);
93      assertEquals(List.of(col1), actual);
94    }
95  
96    @Test
97    public void findAll_WithoutNameOrderByNameDesc() {
98      var col1 = new Collection(1L);
99      col1.setName("Yes");
100     Map<String, Object> paramsMap = new HashMap<>();
101     paramsMap.put("name", null);
102 
103     var query =
104       """
105       MATCH (c:Collection { deleted: FALSE }) WHERE (NOT exists((c)-[:has_permissions]->(:Permissions)) \
106       OR exists((c)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: "bob" })) \
107       OR exists((c)-[:has_permissions]->(:Permissions {permissionType: "Public"})) \
108       OR exists((c)-[:has_permissions]->(:Permissions {permissionType: "PublicReadable"})) \
109       OR exists((c)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: "bob"}))) \
110       WITH c ORDER BY toLower(c.name) DESC \
111       MATCH path=(c)-[*0..1]-(n) WHERE n.deleted = FALSE OR n.deleted IS NULL RETURN c, nodes(path), relationships(path)""";
112     when(session.query(Collection.class, query, paramsMap)).thenReturn(List.of(col1));
113 
114     var params = new QueryParamHelper();
115     var collectionAttribute = DataObjectAttributes.name;
116     params = params.withOrderByAttribute(collectionAttribute, true);
117     var actual = dao.findAllCollectionsByNeo4jId(params, "bob");
118     verify(session).query(Collection.class, query, paramsMap);
119     assertEquals(List.of(col1), actual);
120   }
121 
122   @Test
123   public void findAllByShepardQueryParams_WithoutNameOrderByNameDesc() {
124     var col1 = new Collection(1L);
125     col1.setShepardId(11L);
126     col1.setName("Yes");
127     Map<String, Object> paramsMap = new HashMap<>();
128     paramsMap.put("name", null);
129 
130     var query =
131       """
132       MATCH (c:Collection { deleted: FALSE })-[:has_version]->(v:Version) \
133       WHERE (NOT exists((c)-[:has_permissions]->(:Permissions)) \
134       OR exists((c)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"bob\" })) \
135       OR exists((c)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) \
136       OR exists((c)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) \
137       OR exists((c)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"bob\"}))) \
138       AND""" +
139       " " +
140       CypherQueryHelper.getVersionHeadPart("v") +
141       " " +
142       """
143       WITH c ORDER BY toLower(c.name) DESC MATCH path=(c)-[*0..1]-(n) WHERE n.deleted = FALSE OR n.deleted IS NULL \
144       RETURN c, nodes(path), relationships(path)""";
145     when(session.query(Collection.class, query, paramsMap)).thenReturn(List.of(col1));
146 
147     var params = new QueryParamHelper();
148     var collectionAttribute = DataObjectAttributes.name;
149     params = params.withOrderByAttribute(collectionAttribute, true);
150     var actual = dao.findAllCollectionsByShepardId(params, "bob");
151     verify(session).query(Collection.class, query, paramsMap);
152     assertEquals(List.of(col1), actual);
153   }
154 
155   @Test
156   public void findAll_WithName() {
157     var col1 = new Collection(1L);
158     col1.setName("Yes");
159     var col2 = new Collection(2L);
160     col2.setName("No");
161     Map<String, Object> paramsMap = new HashMap<>();
162     paramsMap.put("name", "Yes");
163 
164     var query =
165       """
166       MATCH (c:Collection { name : $name, deleted: FALSE }) WHERE (NOT exists((c)-[:has_permissions]->(:Permissions)) \
167       OR exists((c)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"bob\" })) \
168       OR exists((c)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) \
169       OR exists((c)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) \
170       OR exists((c)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"bob\"}))) \
171       WITH c MATCH path=(c)-[*0..1]-(n) WHERE n.deleted = FALSE OR n.deleted IS NULL RETURN c, nodes(path), relationships(path)""";
172     when(session.query(Collection.class, query, paramsMap)).thenReturn(List.of(col1, col2));
173 
174     var params = new QueryParamHelper().withName("Yes");
175     var actual = dao.findAllCollectionsByNeo4jId(params, "bob");
176     verify(session).query(Collection.class, query, paramsMap);
177     assertEquals(List.of(col1), actual);
178   }
179 
180   @Test
181   public void findAllWithShepardQueryParams_WithName() {
182     var col1 = new Collection(1L);
183     col1.setShepardId(11L);
184     col1.setName("Yes");
185     var col2 = new Collection(2L);
186     col2.setShepardId(21L);
187     col2.setName("No");
188     Map<String, Object> paramsMap = new HashMap<>();
189     paramsMap.put("name", "Yes");
190 
191     var query =
192       """
193       MATCH (c:Collection { name : $name, deleted: FALSE })-[:has_version]->(v:Version) \
194       WHERE (NOT exists((c)-[:has_permissions]->(:Permissions)) \
195       OR exists((c)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"bob\" })) \
196       OR exists((c)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) \
197       OR exists((c)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) \
198       OR exists((c)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"bob\"}))) \
199       AND""" +
200       " " +
201       CypherQueryHelper.getVersionHeadPart("v") +
202       " " +
203       """
204       WITH c MATCH path=(c)-[*0..1]-(n) WHERE n.deleted = FALSE OR n.deleted IS NULL RETURN c, nodes(path), relationships(path)""";
205     when(session.query(Collection.class, query, paramsMap)).thenReturn(List.of(col1, col2));
206 
207     var params = new QueryParamHelper().withName("Yes");
208     var actual = dao.findAllCollectionsByShepardId(params, "bob");
209     verify(session).query(Collection.class, query, paramsMap);
210     assertEquals(List.of(col1), actual);
211   }
212 
213   @Test
214   public void findAll_WithNameOrderByNameDesc() {
215     var col1 = new Collection(1L);
216     col1.setName("Yes");
217     var col2 = new Collection(2L);
218     col2.setName("No");
219     Map<String, Object> paramsMap = new HashMap<>();
220     paramsMap.put("name", "Yes");
221 
222     var query =
223       """
224       MATCH (c:Collection { name : $name, deleted: FALSE }) WHERE (NOT exists((c)-[:has_permissions]->(:Permissions)) \
225       OR exists((c)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: "bob" })) \
226       OR exists((c)-[:has_permissions]->(:Permissions {permissionType: "Public"})) \
227       OR exists((c)-[:has_permissions]->(:Permissions {permissionType: "PublicReadable"})) \
228       OR exists((c)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: "bob"}))) \
229       WITH c ORDER BY toLower(c.name) DESC \
230       MATCH path=(c)-[*0..1]-(n) WHERE n.deleted = FALSE OR n.deleted IS NULL RETURN c, nodes(path), relationships(path)""";
231     when(session.query(Collection.class, query, paramsMap)).thenReturn(List.of(col1, col2));
232 
233     var params = new QueryParamHelper().withName("Yes");
234     var collectionAttribute = DataObjectAttributes.name;
235     params = params.withOrderByAttribute(collectionAttribute, true);
236     var actual = dao.findAllCollectionsByNeo4jId(params, "bob");
237     verify(session).query(Collection.class, query, paramsMap);
238     assertEquals(List.of(col1), actual);
239   }
240 
241   @Test
242   public void findAllByShepardQueryParams_WithNameOrderByNameDesc() {
243     var col1 = new Collection(1L);
244     col1.setName("Yes");
245     var col2 = new Collection(2L);
246     col2.setName("No");
247     Map<String, Object> paramsMap = new HashMap<>();
248     paramsMap.put("name", "Yes");
249 
250     var query =
251       """
252       MATCH (c:Collection { name : $name, deleted: FALSE })-[:has_version]->(v:Version) \
253       WHERE (NOT exists((c)-[:has_permissions]->(:Permissions)) \
254       OR exists((c)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"bob\" })) \
255       OR exists((c)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) \
256       OR exists((c)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) \
257       OR exists((c)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"bob\"}))) \
258       AND""" +
259       " " +
260       CypherQueryHelper.getVersionHeadPart("v") +
261       " " +
262       """
263       WITH c ORDER BY toLower(c.name) DESC MATCH path=(c)-[*0..1]-(n) WHERE n.deleted = FALSE OR n.deleted IS NULL \
264       RETURN c, nodes(path), relationships(path)""";
265     when(session.query(Collection.class, query, paramsMap)).thenReturn(List.of(col1, col2));
266 
267     var params = new QueryParamHelper().withName("Yes");
268     var collectionAttribute = DataObjectAttributes.name;
269     params = params.withOrderByAttribute(collectionAttribute, true);
270     var actual = dao.findAllCollectionsByShepardId(params, "bob");
271     verify(session).query(Collection.class, query, paramsMap);
272     assertEquals(List.of(col1), actual);
273   }
274 
275   @Test
276   public void findAll_WithPage() {
277     var col1 = new Collection(1L);
278     col1.setName("Yes");
279     Map<String, Object> paramsMap = new HashMap<>();
280     paramsMap.put("name", null);
281     paramsMap.put("offset", 300);
282     paramsMap.put("size", 100);
283 
284     var query =
285       """
286       MATCH (c:Collection { deleted: FALSE }) WHERE (NOT exists((c)-[:has_permissions]->(:Permissions)) \
287       OR exists((c)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: "bob" })) \
288       OR exists((c)-[:has_permissions]->(:Permissions {permissionType: "Public"})) \
289       OR exists((c)-[:has_permissions]->(:Permissions {permissionType: "PublicReadable"})) \
290       OR exists((c)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: "bob"}))) \
291       WITH c SKIP $offset LIMIT $size \
292       MATCH path=(c)-[*0..1]-(n) WHERE n.deleted = FALSE OR n.deleted IS NULL RETURN c, nodes(path), relationships(path)""";
293     when(session.query(Collection.class, query, paramsMap)).thenReturn(List.of(col1));
294 
295     var params = new QueryParamHelper().withPageAndSize(3, 100);
296     var actual = dao.findAllCollectionsByNeo4jId(params, "bob");
297     verify(session).query(Collection.class, query, paramsMap);
298     assertEquals(List.of(col1), actual);
299   }
300 
301   @Test
302   public void findAllByShepardQueryParams_WithPage() {
303     var col1 = new Collection(1L);
304     col1.setName("Yes");
305     Map<String, Object> paramsMap = new HashMap<>();
306     paramsMap.put("name", null);
307     paramsMap.put("offset", 300);
308     paramsMap.put("size", 100);
309 
310     var query =
311       """
312       MATCH (c:Collection { deleted: FALSE })-[:has_version]->(v:Version) \
313       WHERE (NOT exists((c)-[:has_permissions]->(:Permissions)) \
314       OR exists((c)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"bob\" })) \
315       OR exists((c)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) \
316       OR exists((c)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) \
317       OR exists((c)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"bob\"}))) \
318       AND""" +
319       " " +
320       CypherQueryHelper.getVersionHeadPart("v") +
321       " " +
322       """
323       WITH c SKIP $offset LIMIT $size MATCH path=(c)-[*0..1]-(n) WHERE n.deleted = FALSE OR n.deleted IS NULL \
324       RETURN c, nodes(path), relationships(path)""";
325     when(session.query(Collection.class, query, paramsMap)).thenReturn(List.of(col1));
326 
327     var params = new QueryParamHelper().withPageAndSize(3, 100);
328     var actual = dao.findAllCollectionsByShepardId(params, "bob");
329     verify(session).query(Collection.class, query, paramsMap);
330     assertEquals(List.of(col1), actual);
331   }
332 
333   @Test
334   public void findAll_WithPageOrderByNameDesc() {
335     var col1 = new Collection(1L);
336     col1.setName("Yes");
337     Map<String, Object> paramsMap = new HashMap<>();
338     paramsMap.put("name", null);
339     paramsMap.put("offset", 300);
340     paramsMap.put("size", 100);
341 
342     var query =
343       """
344       MATCH (c:Collection { deleted: FALSE }) WHERE (NOT exists((c)-[:has_permissions]->(:Permissions)) \
345       OR exists((c)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: "bob" })) \
346       OR exists((c)-[:has_permissions]->(:Permissions {permissionType: "Public"})) \
347       OR exists((c)-[:has_permissions]->(:Permissions {permissionType: "PublicReadable"})) \
348       OR exists((c)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: "bob"}))) \
349       WITH c ORDER BY toLower(c.name) DESC SKIP $offset LIMIT $size \
350       MATCH path=(c)-[*0..1]-(n) WHERE n.deleted = FALSE OR n.deleted IS NULL RETURN c, nodes(path), relationships(path)""";
351     when(session.query(Collection.class, query, paramsMap)).thenReturn(List.of(col1));
352 
353     var params = new QueryParamHelper().withPageAndSize(3, 100);
354     var collectionAttribute = DataObjectAttributes.name;
355     params = params.withOrderByAttribute(collectionAttribute, true);
356     var actual = dao.findAllCollectionsByNeo4jId(params, "bob");
357     verify(session).query(Collection.class, query, paramsMap);
358     assertEquals(List.of(col1), actual);
359   }
360 
361   @Test
362   public void findAllByShepardQueryParams_WithPageOrderByNameDesc() {
363     var col1 = new Collection(1L);
364     col1.setShepardId(11L);
365     col1.setName("Yes");
366     Map<String, Object> paramsMap = new HashMap<>();
367     paramsMap.put("name", null);
368     paramsMap.put("offset", 300);
369     paramsMap.put("size", 100);
370 
371     var query =
372       """
373       MATCH (c:Collection { deleted: FALSE })-[:has_version]->(v:Version) \
374       WHERE (NOT exists((c)-[:has_permissions]->(:Permissions)) \
375       OR exists((c)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"bob\" })) \
376       OR exists((c)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) \
377       OR exists((c)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) \
378       OR exists((c)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"bob\"}))) \
379       AND""" +
380       " " +
381       CypherQueryHelper.getVersionHeadPart("v") +
382       " " +
383       """
384       WITH c ORDER BY toLower(c.name) DESC SKIP $offset LIMIT $size MATCH path=(c)-[*0..1]-(n) \
385       WHERE n.deleted = FALSE OR n.deleted IS NULL RETURN c, nodes(path), relationships(path)""";
386     when(session.query(Collection.class, query, paramsMap)).thenReturn(List.of(col1));
387 
388     var params = new QueryParamHelper().withPageAndSize(3, 100);
389     var collectionAttribute = DataObjectAttributes.name;
390     params = params.withOrderByAttribute(collectionAttribute, true);
391     var actual = dao.findAllCollectionsByShepardId(params, "bob");
392     verify(session).query(Collection.class, query, paramsMap);
393     assertEquals(List.of(col1), actual);
394   }
395 
396   @Test
397   public void findAll_WithNameAndPage() {
398     var col1 = new Collection(1L);
399     col1.setName("Yes");
400     var col2 = new Collection(2L);
401     col2.setName("No");
402     Map<String, Object> paramsMap = new HashMap<>();
403     paramsMap.put("name", "Yes");
404     paramsMap.put("offset", 300);
405     paramsMap.put("size", 100);
406 
407     var query =
408       """
409       MATCH (c:Collection { name : $name, deleted: FALSE }) WHERE (NOT exists((c)-[:has_permissions]->(:Permissions)) \
410       OR exists((c)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: "bob" })) \
411       OR exists((c)-[:has_permissions]->(:Permissions {permissionType: "Public"})) \
412       OR exists((c)-[:has_permissions]->(:Permissions {permissionType: "PublicReadable"})) \
413       OR exists((c)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: "bob"}))) \
414       WITH c SKIP $offset LIMIT $size \
415       MATCH path=(c)-[*0..1]-(n) WHERE n.deleted = FALSE OR n.deleted IS NULL RETURN c, nodes(path), relationships(path)""";
416     when(session.query(Collection.class, query, paramsMap)).thenReturn(List.of(col1, col2));
417 
418     var params = new QueryParamHelper().withPageAndSize(3, 100).withName("Yes");
419     var actual = dao.findAllCollectionsByNeo4jId(params, "bob");
420     verify(session).query(Collection.class, query, paramsMap);
421     assertEquals(List.of(col1), actual);
422   }
423 
424   @Test
425   public void findAllByShepardQueryParams_WithNameAndPage() {
426     var col1 = new Collection(1L);
427     col1.setShepardId(11L);
428     col1.setName("Yes");
429     var col2 = new Collection(2L);
430     col2.setShepardId(21L);
431     col2.setName("No");
432     Map<String, Object> paramsMap = new HashMap<>();
433     paramsMap.put("name", "Yes");
434     paramsMap.put("offset", 300);
435     paramsMap.put("size", 100);
436 
437     var query =
438       """
439       MATCH (c:Collection { name : $name, deleted: FALSE })-[:has_version]->(v:Version) \
440       WHERE (NOT exists((c)-[:has_permissions]->(:Permissions)) \
441       OR exists((c)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"bob\" })) \
442       OR exists((c)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) \
443       OR exists((c)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) \
444       OR exists((c)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"bob\"}))) \
445       AND""" +
446       " " +
447       CypherQueryHelper.getVersionHeadPart("v") +
448       " " +
449       """
450       WITH c SKIP $offset LIMIT $size MATCH path=(c)-[*0..1]-(n) WHERE n.deleted = FALSE OR n.deleted IS NULL \
451       RETURN c, nodes(path), relationships(path)""";
452     when(session.query(Collection.class, query, paramsMap)).thenReturn(List.of(col1, col2));
453 
454     var params = new QueryParamHelper().withPageAndSize(3, 100).withName("Yes");
455     var actual = dao.findAllCollectionsByShepardId(params, "bob");
456     verify(session).query(Collection.class, query, paramsMap);
457     assertEquals(List.of(col1), actual);
458   }
459 
460   @Test
461   public void findAll_WithNameAndPageOrderByNameDesc() {
462     var col1 = new Collection(1L);
463     col1.setName("Yes");
464     var col2 = new Collection(2L);
465     col2.setName("No");
466     Map<String, Object> paramsMap = new HashMap<>();
467     paramsMap.put("name", "Yes");
468     paramsMap.put("offset", 300);
469     paramsMap.put("size", 100);
470 
471     var query =
472       """
473       MATCH (c:Collection { name : $name, deleted: FALSE }) WHERE (NOT exists((c)-[:has_permissions]->(:Permissions)) \
474       OR exists((c)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: "bob" })) \
475       OR exists((c)-[:has_permissions]->(:Permissions {permissionType: "Public"})) \
476       OR exists((c)-[:has_permissions]->(:Permissions {permissionType: "PublicReadable"})) \
477       OR exists((c)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: "bob"}))) \
478       WITH c ORDER BY toLower(c.name) DESC SKIP $offset LIMIT $size \
479       MATCH path=(c)-[*0..1]-(n) WHERE n.deleted = FALSE OR n.deleted IS NULL RETURN c, nodes(path), relationships(path)""";
480     when(session.query(Collection.class, query, paramsMap)).thenReturn(List.of(col1, col2));
481 
482     var params = new QueryParamHelper().withPageAndSize(3, 100).withName("Yes");
483     var collectionAttribute = DataObjectAttributes.name;
484     params = params.withOrderByAttribute(collectionAttribute, true);
485     var actual = dao.findAllCollectionsByNeo4jId(params, "bob");
486     verify(session).query(Collection.class, query, paramsMap);
487     assertEquals(List.of(col1), actual);
488   }
489 
490   @Test
491   public void findAllByShepardQueryParams_WithNameAndPageOrderByNameDesc() {
492     var col1 = new Collection(1L);
493     col1.setShepardId(11L);
494     col1.setName("Yes");
495     var col2 = new Collection(2L);
496     col2.setShepardId(21L);
497     col2.setName("No");
498     Map<String, Object> paramsMap = new HashMap<>();
499     paramsMap.put("name", "Yes");
500     paramsMap.put("offset", 300);
501     paramsMap.put("size", 100);
502 
503     var query =
504       """
505       MATCH (c:Collection { name : $name, deleted: FALSE })-[:has_version]->(v:Version) \
506       WHERE (NOT exists((c)-[:has_permissions]->(:Permissions)) \
507       OR exists((c)-[:has_permissions]->(:Permissions)-[:readable_by|owned_by]->(:User { username: \"bob\" })) \
508       OR exists((c)-[:has_permissions]->(:Permissions {permissionType: \"Public\"})) \
509       OR exists((c)-[:has_permissions]->(:Permissions {permissionType: \"PublicReadable\"})) \
510       OR exists((c)-[:has_permissions]->(:Permissions)-[:readable_by_group]->(:UserGroup)<-[:is_in_group]-(:User { username: \"bob\"}))) \
511       AND""" +
512       " " +
513       CypherQueryHelper.getVersionHeadPart("v") +
514       " " +
515       """
516       WITH c ORDER BY toLower(c.name) DESC SKIP $offset LIMIT $size MATCH path=(c)-[*0..1]-(n) \
517       WHERE n.deleted = FALSE OR n.deleted IS NULL \
518       RETURN c, nodes(path), relationships(path)""";
519     when(session.query(Collection.class, query, paramsMap)).thenReturn(List.of(col1, col2));
520 
521     var params = new QueryParamHelper().withPageAndSize(3, 100).withName("Yes");
522     var collectionAttribute = DataObjectAttributes.name;
523     params = params.withOrderByAttribute(collectionAttribute, true);
524     var actual = dao.findAllCollectionsByShepardId(params, "bob");
525     verify(session).query(Collection.class, query, paramsMap);
526     assertEquals(List.of(col1), actual);
527   }
528 
529   @Test
530   public void deleteCollectionByShepardIdTest() {
531     CollectionDAO spy = spy(CollectionDAO.class);
532     var collection = new Collection(1L);
533     collection.setShepardId(11L);
534     var user = new User("bob");
535     var date = new Date();
536 
537     var updated = new Collection(1L);
538     updated.setShepardId(11L);
539     updated.setUpdatedBy(user);
540     updated.setUpdatedAt(date);
541     updated.setDeleted(true);
542 
543     doReturn(collection).when(spy).findByShepardId(11L);
544     doReturn(updated).when(spy).createOrUpdate(updated);
545     doReturn(true)
546       .when(spy)
547       .runQuery(
548         """
549         MATCH (c:Collection {shepardId:11}) OPTIONAL MATCH (c)-[:has_dataobject]->(d:DataObject) \
550         OPTIONAL MATCH (d)-[:has_reference]->(r:BasicReference) \
551         FOREACH (n in [c,d,r] | SET n.deleted = true)""",
552         Collections.emptyMap()
553       );
554 
555     var result = spy.deleteCollectionByShepardId(11L, user, date);
556     verify(spy).createOrUpdate(updated);
557     assertTrue(result);
558   }
559 }