1 package de.dlr.shepard.common.search.query;
2
3 import com.fasterxml.jackson.core.JsonProcessingException;
4 import com.fasterxml.jackson.databind.JsonNode;
5 import com.fasterxml.jackson.databind.ObjectMapper;
6 import de.dlr.shepard.common.exceptions.ShepardParserException;
7 import de.dlr.shepard.common.neo4j.entities.ContainerType;
8 import de.dlr.shepard.common.search.io.SearchScope;
9 import de.dlr.shepard.common.util.Constants;
10 import de.dlr.shepard.common.util.CypherQueryHelper;
11 import de.dlr.shepard.common.util.Neo4jLabels;
12 import de.dlr.shepard.common.util.SortingHelper;
13 import de.dlr.shepard.common.util.TraversalRules;
14 import java.util.ArrayList;
15 import java.util.Iterator;
16 import java.util.List;
17 import java.util.NoSuchElementException;
18
19 public class Neo4jQueryBuilder {
20
21 private static final List<String> booleanOperators = List.of(
22 Constants.JSON_AND,
23 Constants.JSON_OR,
24 Constants.JSON_NOT,
25 Constants.JSON_XOR
26 );
27 private static final List<String> opAttributes = List.of(
28 Constants.OP_PROPERTY,
29 Constants.OP_VALUE,
30 Constants.OP_OPERATOR
31 );
32 private static final List<String> notIdProperties = List.of(
33 "createdBy",
34 "updatedBy",
35 "valueIRI",
36 "propertyIRI",
37 "createdAt",
38 "updatedAt",
39 "hasAnnotation",
40 "hasAnnotationIRI"
41 );
42
43 private static final List<String> IdProperties = List.of(
44 "id",
45 "referencedCollectionId",
46 "referencedDataObjectId",
47 "fileContainerId",
48 "structuredDataContainerId",
49 "timeseriesContainerId",
50 "successorIds",
51 "predecessorIds",
52 "childrenIds",
53 "parentIds"
54 );
55
56 private static final String INCORRECT_COLON_EXCEPTION_MESSAGE =
57 "the annotation must contain exactly one occurrence of :: to divide the property and the name " +
58 "but the given value is ";
59
60 private static final String colonMatcher = "[^:]*(:[^:]+)*::([^:]+:)*[^:]*";
61
62 private static String getNeo4jWithNeo4jIdString(String jsonquery, String variable) {
63 ObjectMapper objectMapper = new ObjectMapper();
64 JsonNode jsonNode = null;
65 try {
66 jsonNode = objectMapper.readValue(jsonquery, JsonNode.class);
67 } catch (JsonProcessingException e) {
68 throw new ShepardParserException("could not parse JSON " + e.getMessage());
69 }
70 return getNeo4jStringWithNeo4jId(jsonNode, variable);
71 }
72
73 private static String getNeo4jStringWithNeo4jId(JsonNode rootNode, String variable) {
74 String op = "";
75 try {
76 op = rootNode.fieldNames().next();
77 } catch (NoSuchElementException e) {
78 throw new ShepardParserException("error in parsing" + e.getMessage());
79 }
80 if (opAttributes.contains(op)) {
81 return primitiveClauseWithNeo4jId(rootNode, variable);
82 }
83 return complexClauseWithNeo4jId(rootNode, op, variable);
84 }
85
86 private static String complexClauseWithNeo4jId(JsonNode node, String operator, String variable) {
87 if (!booleanOperators.contains(operator)) throw new ShepardParserException("unknown boolean operator: " + operator);
88 if (operator.equals(Constants.JSON_NOT)) return notClauseWithNeo4jId(node, variable);
89 else return multaryClauseWithNeo4jId(node, operator, variable);
90 }
91
92 private static String multaryClauseWithNeo4jId(JsonNode node, String operator, String variable) {
93 Iterator<JsonNode> argumentsArray = node.get(operator).elements();
94 String firstArgument = getNeo4jStringWithNeo4jId(argumentsArray.next(), variable);
95 String ret = "(" + firstArgument;
96 while (argumentsArray.hasNext()) {
97 ret = ret + " " + operator + " " + getNeo4jStringWithNeo4jId(argumentsArray.next(), variable);
98 }
99 ret = ret + ")";
100 return ret;
101 }
102
103 private static String notClauseWithNeo4jId(JsonNode node, String variable) {
104 JsonNode body = node.get(Constants.JSON_NOT);
105 return "(NOT(" + getNeo4jStringWithNeo4jId(body, variable) + "))";
106 }
107
108 private static String primitiveClauseWithNeo4jId(JsonNode node, String variable) {
109 String property = node.get(Constants.OP_PROPERTY).textValue();
110 property = changeAttributesDelimiter(property);
111 if (notIdProperties.contains(property)) return simpleNotIdPropertyPart(node, variable);
112 if (IdProperties.contains(property)) return simpleIdPropertyPart(node, variable);
113 String ret = "(";
114 ret = ret + "toLower(" + variable + ".`" + property + "`) ";
115 ret = ret + operatorString(node.get(Constants.OP_OPERATOR)) + " ";
116 ret = ret + valuePart(node).toLowerCase();
117 ret = ret + ")";
118 return ret;
119 }
120
121
122
123
124
125
126
127
128
129
130
131 private static String changeAttributesDelimiter(String property) {
132 if (property.startsWith("attributes.")) {
133 return property.replaceFirst("attributes.", "attributes||");
134 }
135 return property;
136 }
137
138 private static String valuePart(JsonNode node) {
139 String ret = "";
140 if (node.get(Constants.OP_OPERATOR).textValue().equals(Constants.JSON_IN)) {
141 ret = ret + "[";
142 Iterator<JsonNode> setArray = node.get(Constants.OP_VALUE).elements();
143 if (setArray.hasNext()) {
144 ret = ret + setArray.next();
145 while (setArray.hasNext()) ret = ret + ", " + setArray.next();
146 ret = ret + "]";
147 } else {
148 ret = ret + "]";
149 }
150 } else ret = ret + node.get(Constants.OP_VALUE);
151 return ret;
152 }
153
154 private static String simpleNotIdPropertyPart(JsonNode node, String variable) {
155 String property = node.get(Constants.OP_PROPERTY).textValue();
156
157 if (property.equals("createdBy") || property.equals("updatedBy")) return byPart(node, variable);
158
159 if (property.equals("createdAt") || property.equals("updatedAt")) return atPart(node, variable);
160
161 if (property.equals("valueIRI") || property.equals("propertyIRI")) return iRIPart(node, variable);
162
163 if (property.equals("hasAnnotation")) return hasAnnotationPart(node, variable);
164
165 if (property.equals("hasAnnotationIRI")) return hasAnnotationIRIPart(node, variable);
166 return null;
167 }
168
169 private static String hasAnnotationIRIPart(JsonNode node, String variable) {
170
171
172
173
174
175
176
177 String annotation = node.get(Constants.OP_VALUE).textValue();
178 if (!annotation.matches(colonMatcher)) throw new ShepardParserException(
179 INCORRECT_COLON_EXCEPTION_MESSAGE + annotation
180 );
181 String[] propertyValuePair = annotation.split("::");
182 String propertyIRI = null;
183 String valueIRI = null;
184
185 if (propertyValuePair.length == 0) {
186 propertyIRI = "";
187 valueIRI = "";
188 }
189
190 if (propertyValuePair.length == 1) {
191 propertyIRI = propertyValuePair[0];
192 valueIRI = "";
193 }
194
195 if (propertyValuePair.length == 2) {
196 propertyIRI = propertyValuePair[0];
197 valueIRI = propertyValuePair[1];
198 }
199 String ret = "(";
200 ret =
201 ret + "EXISTS {MATCH (" + variable + ") - [:has_annotation] -> (sem:SemanticAnnotation) WHERE (sem.propertyIRI ";
202 ret = ret + operatorString(node.get(Constants.OP_OPERATOR)) + " \"" + propertyIRI + "\" AND ";
203 ret = ret + " sem.valueIRI " + operatorString(node.get(Constants.OP_OPERATOR)) + " \"" + valueIRI;
204 ret = ret + "\")})";
205 return ret;
206 }
207
208 private static String hasAnnotationPart(JsonNode node, String variable) {
209
210
211
212
213
214
215
216 String annotation = node.get(Constants.OP_VALUE).textValue();
217 if (!annotation.matches(colonMatcher)) throw new ShepardParserException(
218 INCORRECT_COLON_EXCEPTION_MESSAGE + annotation
219 );
220 String[] propertyValuePair = annotation.split("::");
221 String propertyName = null;
222 String valueName = null;
223
224 if (propertyValuePair.length == 0) {
225 propertyName = "";
226 valueName = "";
227 }
228
229 if (propertyValuePair.length == 1) {
230 propertyName = propertyValuePair[0];
231 valueName = "";
232 }
233
234 if (propertyValuePair.length == 2) {
235 propertyName = propertyValuePair[0];
236 valueName = propertyValuePair[1];
237 }
238 String ret = "(";
239 ret =
240 ret + "EXISTS {MATCH (" + variable + ") - [:has_annotation] -> (sem:SemanticAnnotation) WHERE (sem.propertyName ";
241 ret = ret + operatorString(node.get(Constants.OP_OPERATOR)) + " \"" + propertyName + "\" AND ";
242 ret = ret + " sem.valueName " + operatorString(node.get(Constants.OP_OPERATOR)) + " \"" + valueName;
243 ret = ret + "\")})";
244 return ret;
245 }
246
247 private static String simpleIdPropertyPart(JsonNode node, String variable) {
248 String property = node.get(Constants.OP_PROPERTY).textValue();
249
250 if (property.equals("id")) return neo4jIdPart(node, variable);
251
252 if (property.equals("referencedCollectionId")) return referencedCollectionNeo4jIdPart(node, variable);
253
254 if (property.equals("referencedDataObjectId")) return referencedDataObjectNeo4jIdPart(node, variable);
255
256 if (property.equals("fileContainerId")) return fileContainerIdPart(node, variable);
257
258 if (property.equals("structuredDataContainerId")) return structuredDataContainerIdPart(node, variable);
259
260 if (property.equals("timeseriesContainerId")) return timeseriesContainerIdPart(node, variable);
261
262 if (
263 property.equals("successorIds") ||
264 property.equals("predecessorIds") ||
265 property.equals("childrenIds") ||
266 property.equals("parentIds")
267 ) return neighborhoodIdsPart(node, variable);
268 return null;
269 }
270
271 private static String byPart(JsonNode node, String variable) {
272 String ret = "(";
273 String by =
274 switch (node.get(Constants.OP_PROPERTY).textValue()) {
275 case "createdBy" -> "created_by";
276 case "updatedBy" -> "updated_by";
277 default -> "";
278 };
279 ret = ret + "EXISTS {MATCH (" + variable + ") - [:" + by + "] -> (u) WHERE toLower(u.username) ";
280 ret = ret + operatorString(node.get(Constants.OP_OPERATOR)) + " ";
281 ret = ret + node.get(Constants.OP_VALUE).toString().toLowerCase() + " ";
282 ret = ret + "})";
283 return ret;
284 }
285
286 private static String neighborhoodIdsPart(JsonNode node, String variable) {
287 String operatorString = node.get(Constants.OP_OPERATOR).textValue();
288 String neighborhoodProperty = node.get(Constants.OP_PROPERTY).textValue();
289 String neighborhoodNeo4j =
290 switch (neighborhoodProperty) {
291 case "successorIds" -> "-[:has_successor]->";
292 case "predecessorIds" -> "<-[:has_successor]-";
293 case "childrenIds" -> "-[:has_child]->";
294 case "parentIds" -> "<-[:has_child]-";
295 default -> "";
296 };
297 if (operatorString.equals(Constants.JSON_CONTAINS)) return neighborhoodIdsContainsPart(
298 node,
299 variable,
300 neighborhoodNeo4j
301 );
302 if (operatorString.equals(Constants.JSON_IS_CONTAINED_IN)) return neighborhoodIdsIsContainedInPart(
303 node,
304 variable,
305 neighborhoodNeo4j
306 );
307 if (operatorString.equals(Constants.JSON_EQ)) return neighborhoodIdsEqualsPart(node, variable, neighborhoodNeo4j);
308 throw new ShepardParserException("illegal comparison operator " + operatorString);
309 }
310
311 private static String neighborhoodIdsEqualsPart(JsonNode node, String variable, String neighborhoodNeo4j) {
312 return (
313 "((" +
314 neighborhoodIdsIsContainedInPart(node, variable, neighborhoodNeo4j) +
315 ") AND (" +
316 neighborhoodIdsContainsPart(node, variable, neighborhoodNeo4j) +
317 "))"
318 );
319 }
320
321 private static String neighborhoodIdsIsContainedInPart(JsonNode node, String variable, String neighborhoodNeo4j) {
322 String ret = "(";
323 ArrayList<Long> successorIds = new ArrayList<Long>();
324 for (JsonNode longNode : node.get(Constants.OP_VALUE)) {
325 successorIds.add(longNode.longValue());
326 }
327 if (successorIds.size() == 0) return "(NOT EXISTS{MATCH (" + variable + ")" + neighborhoodNeo4j + "(neighborObj)})";
328 String arrayString = "[";
329 for (int i = 0; i < successorIds.size() - 1; i++) arrayString = arrayString + successorIds.get(i) + ",";
330 arrayString = arrayString + successorIds.getLast() + "]";
331 ret =
332 ret +
333 "NOT EXISTS{MATCH (" +
334 variable +
335 ")" +
336 neighborhoodNeo4j +
337 "(neighborObj) WHERE (NOT id(neighborObj) IN " +
338 arrayString +
339 ")})";
340 return ret;
341 }
342
343 private static String neighborhoodIdsContainsPart(JsonNode node, String variable, String neighborhoodNeo4j) {
344 String ret = "(";
345 ArrayList<Long> successorIds = new ArrayList<Long>();
346 for (JsonNode longNode : node.get(Constants.OP_VALUE)) {
347 successorIds.add(longNode.longValue());
348 }
349 if (successorIds.size() == 0) return "(1=1)";
350 for (int i = 0; i < successorIds.size() - 1; i++) {
351 ret =
352 ret +
353 "(EXISTS {MATCH (" +
354 variable +
355 ")" +
356 neighborhoodNeo4j +
357 "(neighborObj) WHERE id(neighborObj)=" +
358 successorIds.get(i) +
359 "}) AND ";
360 }
361 ret =
362 ret +
363 "(EXISTS {MATCH (" +
364 variable +
365 ")" +
366 neighborhoodNeo4j +
367 "(neighborObj) WHERE id(neighborObj)=" +
368 successorIds.getLast() +
369 "}))";
370 return ret;
371 }
372
373 private static String atPart(JsonNode node, String variable) {
374 String ret = "(";
375 String property = node.get(Constants.OP_PROPERTY).textValue();
376 if (property.equals("id")) ret = ret + "id(" + variable + ") ";
377 else ret = ret + variable + "." + property + " ";
378 ret = ret + operatorString(node.get(Constants.OP_OPERATOR)) + " ";
379 ret = ret + valuePart(node).toLowerCase();
380 ret = ret + ")";
381 return ret;
382 }
383
384 private static String iRIPart(JsonNode node, String variable) {
385 String ret = "(";
386 String iriType = node.get(Constants.OP_PROPERTY).textValue();
387 ret = ret + "EXISTS {MATCH (" + variable + ") - [] -> (sem:SemanticAnnotation) WHERE (sem." + iriType + " ";
388 ret = ret + operatorString(node.get(Constants.OP_OPERATOR)) + " ";
389 ret = ret + node.get(Constants.OP_VALUE);
390 ret = ret + ")})";
391 return ret;
392 }
393
394 private static String timeseriesContainerIdPart(JsonNode node, String variable) {
395 return containerIdPart(node, variable, "TimeseriesContainer");
396 }
397
398 private static String structuredDataContainerIdPart(JsonNode node, String variable) {
399 return containerIdPart(node, variable, "StructuredDataContainer");
400 }
401
402 private static String fileContainerIdPart(JsonNode node, String variable) {
403 return containerIdPart(node, variable, "FileContainer");
404 }
405
406 private static String containerIdPart(JsonNode node, String variable, String containerType) {
407 String ret = "(";
408 ret =
409 ret +
410 "EXISTS {MATCH (" +
411 variable +
412 ")-[:" +
413 Neo4jLabels.IS_IN_CONTAINER +
414 "]->(refCon:" +
415 containerType +
416 ") WHERE id(refCon) ";
417 ret = ret + operatorString(node.get(Constants.OP_OPERATOR)) + " ";
418 ret = ret + node.get(Constants.OP_VALUE) + " ";
419 ret = ret + "})";
420 return ret;
421 }
422
423 private static String referencedDataObjectNeo4jIdPart(JsonNode node, String variable) {
424 String ret = "(";
425 ret =
426 ret + "EXISTS {MATCH (" + variable + ")-[:" + Neo4jLabels.POINTS_TO + "]->(refDo:DataObject) WHERE id(refDo) ";
427 ret = ret + operatorString(node.get(Constants.OP_OPERATOR)) + " ";
428 ret = ret + node.get(Constants.OP_VALUE) + " ";
429 ret = ret + "})";
430 return ret;
431 }
432
433 private static String referencedCollectionNeo4jIdPart(JsonNode node, String variable) {
434 String ret = "(";
435 ret =
436 ret + "EXISTS {MATCH (" + variable + ")-[:" + Neo4jLabels.POINTS_TO + "]->(refCol:Collection) WHERE id(refCol) ";
437 ret = ret + operatorString(node.get(Constants.OP_OPERATOR)) + " ";
438 ret = ret + node.get(Constants.OP_VALUE) + " ";
439 ret = ret + "})";
440 return ret;
441 }
442
443 private static String neo4jIdPart(JsonNode node, String variable) {
444 String ret = "(";
445 ret = ret + "id(" + variable + ") ";
446 ret = ret + operatorString(node.get(Constants.OP_OPERATOR)) + " ";
447 ret = ret + valuePart(node);
448 ret = ret + ")";
449 return ret;
450 }
451
452 private static String operatorString(JsonNode node) {
453 String operator = node.textValue();
454 return switch (operator) {
455 case Constants.JSON_EQ -> "=";
456 case Constants.JSON_CONTAINS -> "contains";
457 case Constants.JSON_GT -> ">";
458 case Constants.JSON_LT -> "<";
459 case Constants.JSON_GE -> ">=";
460 case Constants.JSON_LE -> "<=";
461 case Constants.JSON_IN -> "IN";
462 case Constants.JSON_NE -> "<>";
463 case Constants.JSON_REGMATCH -> "=~";
464 default -> throw new ShepardParserException("unknown comparison operator " + operator);
465 };
466 }
467
468 private static String collectionDataObjectMatchPartWithoutVersion() {
469 String ret =
470 "MATCH (" +
471 Constants.COLLECTION_IN_QUERY +
472 ":Collection)-[:has_dataobject]->(" +
473 Constants.DATAOBJECT_IN_QUERY +
474 ":DataObject)";
475 return ret;
476 }
477
478 private static String collectionNeo4jIdWherePart(Long collectionId) {
479 String ret = "(id(" + Constants.COLLECTION_IN_QUERY + ") = " + collectionId + ")";
480 return ret;
481 }
482
483 private static String notDeletedPart(String variable) {
484 String ret = "(" + variable + ".deleted = FALSE)";
485 return ret;
486 }
487
488 private static String collectionDataObjectNeo4jIdWherePart(Long collectionId, Long dataObjectId) {
489 String ret =
490 "(id(" +
491 Constants.COLLECTION_IN_QUERY +
492 ") = " +
493 collectionId +
494 " AND id(" +
495 Constants.DATAOBJECT_IN_QUERY +
496 ") = " +
497 dataObjectId +
498 ")";
499 return ret;
500 }
501
502 private static String collectionDataObjectTraversalNeo4jIdWherePart(Long collectionId, Long dataObjectId) {
503 String ret = "(id(" + Constants.COLLECTION_IN_QUERY + ") = " + collectionId + " AND id(d) = " + dataObjectId + ")";
504 return ret;
505 }
506
507 private static String basicReferenceMatchPartWithoutVersion() {
508 String ret =
509 "MATCH (" +
510 Constants.COLLECTION_IN_QUERY +
511 ":Collection)-[:has_dataobject]->(" +
512 Constants.DATAOBJECT_IN_QUERY +
513 ":DataObject)-[:has_reference]->(" +
514 Constants.REFERENCE_IN_QUERY +
515 ":BasicReference)";
516 return ret;
517 }
518
519 public static String collectionSelectionQueryWithNeo4jId(
520 String searchBodyQuery,
521 String userName,
522 SortingHelper sortOrder
523 ) {
524 String ret = "MATCH (" + Constants.COLLECTION_IN_QUERY + ":Collection)";
525 ret = ret + " WHERE ";
526 ret = ret + getNeo4jWithNeo4jIdString(searchBodyQuery, Constants.COLLECTION_IN_QUERY);
527 ret = ret + " AND ";
528 ret = ret + notDeletedPart(Constants.COLLECTION_IN_QUERY);
529 ret = ret + " AND ";
530 ret = ret + readableByPart(userName);
531 if (sortOrder.hasOrderByAttribute()) {
532 ret +=
533 " " +
534 CypherQueryHelper.getOrderByPart(
535 Constants.COLLECTION_IN_QUERY,
536 sortOrder.getOrderByAttribute(),
537 sortOrder.getOrderDesc()
538 );
539 }
540 return ret;
541 }
542
543 public static String containerSelectionQueryWithNeo4jId(
544 String JSONQuery,
545 ContainerType containerType,
546 SortingHelper sortOrder,
547 String userName
548 ) {
549 String ret = "MATCH (" + containerType.getTypeAlias() + ":" + containerType.getTypeName() + ")";
550 ret = ret + " WHERE ";
551 ret = ret + getNeo4jWithNeo4jIdString(JSONQuery, containerType.getTypeAlias());
552 ret = ret + " AND ";
553 ret = ret + notDeletedPart(containerType.getTypeAlias());
554 ret = ret + " AND ";
555 ret = ret + CypherQueryHelper.getReadableByQuery(containerType.getTypeAlias(), userName);
556 if (sortOrder.hasOrderByAttribute()) {
557 ret +=
558 " " +
559 CypherQueryHelper.getOrderByPart(
560 containerType.getTypeAlias(),
561 sortOrder.getOrderByAttribute(),
562 sortOrder.getOrderDesc()
563 );
564 }
565 return ret;
566 }
567
568 public static String collectionDataObjectSelectionQueryWithNeo4jId(
569 Long collectionId,
570 String searchBodyQuery,
571 String username
572 ) {
573 String ret = "";
574 ret = ret + collectionDataObjectMatchPartWithoutVersion();
575 ret = ret + " WHERE ";
576 ret = ret + getNeo4jWithNeo4jIdString(searchBodyQuery, Constants.DATAOBJECT_IN_QUERY);
577 ret = ret + " AND ";
578 ret = ret + collectionNeo4jIdWherePart(collectionId);
579 ret = ret + " AND ";
580 ret = ret + notDeletedPart(Constants.DATAOBJECT_IN_QUERY);
581 ret = ret + " AND ";
582 ret = ret + readableByPart(username);
583 return ret;
584 }
585
586 public static String collectionDataObjectDataObjectSelectionQueryWithNeo4jId(
587 SearchScope scope,
588 TraversalRules traversalRule,
589 String searchBodyQuery,
590 String username
591 ) {
592 String ret = "";
593 ret = ret + collectionDataObjectDataObjectMatchPartWithoutVersion(traversalRule);
594 ret = ret + " WHERE ";
595 ret = ret + getNeo4jWithNeo4jIdString(searchBodyQuery, Constants.DATAOBJECT_IN_QUERY);
596 ret = ret + " AND ";
597 ret = ret + collectionDataObjectTraversalNeo4jIdWherePart(scope.getCollectionId(), scope.getDataObjectId());
598 ret = ret + " AND ";
599 ret = ret + notDeletedPart(Constants.DATAOBJECT_IN_QUERY);
600 ret = ret + " AND ";
601 ret = ret + readableByPart(username);
602 return ret;
603 }
604
605 public static String collectionDataObjectDataObjectSelectionQueryWithNeo4jId(
606 SearchScope scope,
607 String searchBodyQuery,
608 String username
609 ) {
610 String ret = "";
611 ret = ret + collectionDataObjectMatchPartWithoutVersion();
612 ret = ret + " WHERE ";
613 ret = ret + getNeo4jWithNeo4jIdString(searchBodyQuery, Constants.DATAOBJECT_IN_QUERY);
614 ret = ret + " AND ";
615 ret = ret + collectionDataObjectNeo4jIdWherePart(scope.getCollectionId(), scope.getDataObjectId());
616 ret = ret + " AND ";
617 ret = ret + notDeletedPart(Constants.DATAOBJECT_IN_QUERY);
618 ret = ret + " AND ";
619 ret = ret + readableByPart(username);
620 return ret;
621 }
622
623 public static String dataObjectSelectionQueryWithNeo4jId(String searchBodyQuery, String username) {
624 String ret = "";
625 ret = ret + collectionDataObjectMatchPartWithoutVersion();
626 ret = ret + " WHERE ";
627 ret = ret + getNeo4jWithNeo4jIdString(searchBodyQuery, Constants.DATAOBJECT_IN_QUERY);
628 ret = ret + " AND ";
629 ret = ret + notDeletedPart(Constants.DATAOBJECT_IN_QUERY);
630 ret = ret + " AND ";
631 ret = ret + readableByPart(username);
632 return ret;
633 }
634
635 public static String basicReferenceSelectionQueryWithNeo4jId(String searchBodyQuery, String username) {
636 String ret = "";
637 ret = ret + basicReferenceMatchPartWithoutVersion();
638 ret = ret + " WHERE ";
639 ret = ret + getNeo4jWithNeo4jIdString(searchBodyQuery, Constants.REFERENCE_IN_QUERY);
640 ret = ret + " AND ";
641 ret = ret + notDeletedPart(Constants.REFERENCE_IN_QUERY);
642 ret = ret + " AND ";
643 ret = ret + readableByPart(username);
644 return ret;
645 }
646
647 public static String collectionBasicReferenceSelectionQueryWithNeo4jId(
648 String searchBodyQuery,
649 Long collectionId,
650 String username
651 ) {
652 String ret = "";
653 ret = ret + basicReferenceMatchPartWithoutVersion();
654 ret = ret + " WHERE ";
655 ret = ret + getNeo4jWithNeo4jIdString(searchBodyQuery, Constants.REFERENCE_IN_QUERY);
656 ret = ret + " AND ";
657 ret = ret + collectionNeo4jIdWherePart(collectionId);
658 ret = ret + " AND ";
659 ret = ret + notDeletedPart(Constants.REFERENCE_IN_QUERY);
660 ret = ret + " AND ";
661 ret = ret + readableByPart(username);
662 return ret;
663 }
664
665 public static String collectionDataObjectReferenceSelectionQueryWithNeo4jId(
666 SearchScope scope,
667 String searchBodyQuery,
668 String username
669 ) {
670 String ret = "";
671 ret = ret + basicReferenceMatchPartWithoutVersion();
672 ret = ret + " WHERE ";
673 ret = ret + getNeo4jWithNeo4jIdString(searchBodyQuery, Constants.REFERENCE_IN_QUERY);
674 ret = ret + " AND ";
675 ret = ret + collectionDataObjectNeo4jIdWherePart(scope.getCollectionId(), scope.getDataObjectId());
676 ret = ret + " AND ";
677 ret = ret + notDeletedPart(Constants.REFERENCE_IN_QUERY);
678 ret = ret + " AND ";
679 ret = ret + readableByPart(username);
680 return ret;
681 }
682
683 public static String collectionDataObjectBasicReferenceSelectionQueryWithNeo4jId(
684 SearchScope scope,
685 TraversalRules traversalRule,
686 String searchBodyQuery,
687 String username
688 ) {
689 String ret = "";
690 ret = ret + collectionDataObjectBasicReferenceMatchPartWithoutVersion(traversalRule);
691 ret = ret + " WHERE ";
692 ret = ret + getNeo4jWithNeo4jIdString(searchBodyQuery, Constants.REFERENCE_IN_QUERY);
693 ret = ret + " AND ";
694 ret = ret + collectionDataObjectTraversalNeo4jIdWherePart(scope.getCollectionId(), scope.getDataObjectId());
695 ret = ret + " AND ";
696 ret = ret + notDeletedPart(Constants.REFERENCE_IN_QUERY);
697 ret = ret + " AND ";
698 ret = ret + readableByPart(username);
699 return ret;
700 }
701
702 private static String collectionDataObjectDataObjectMatchPartWithoutVersion(TraversalRules traversalRule) {
703 String ret =
704 switch (traversalRule) {
705 case children -> "MATCH (" +
706 Constants.COLLECTION_IN_QUERY +
707 ":Collection)-[:has_dataobject]->(d:DataObject)-[:has_child*0..]->(" +
708 Constants.DATAOBJECT_IN_QUERY +
709 ":DataObject)";
710 case parents -> "MATCH (" +
711 Constants.COLLECTION_IN_QUERY +
712 ":Collection)-[:has_dataobject]->(d:DataObject)<-[:has_child*0..]-(" +
713 Constants.DATAOBJECT_IN_QUERY +
714 ":DataObject)";
715 case successors -> "MATCH (" +
716 Constants.COLLECTION_IN_QUERY +
717 ":Collection)-[:has_dataobject]->(d:DataObject)-[:has_successor*0..]->(" +
718 Constants.DATAOBJECT_IN_QUERY +
719 ":DataObject)";
720 case predecessors -> "MATCH (" +
721 Constants.COLLECTION_IN_QUERY +
722 ":Collection)-[:has_dataobject]->(d:DataObject)<-[:has_successor*0..]-(" +
723 Constants.DATAOBJECT_IN_QUERY +
724 ":DataObject)";
725 default -> "";
726 };
727 return ret;
728 }
729
730 private static String collectionDataObjectBasicReferenceMatchPartWithoutVersion(TraversalRules traversalRule) {
731 String ret =
732 switch (traversalRule) {
733 case children -> "MATCH (" +
734 Constants.COLLECTION_IN_QUERY +
735 ":Collection)-[:has_dataobject]->(d:DataObject)-[:has_child*0..]->(" +
736 Constants.DATAOBJECT_IN_QUERY +
737 ":DataObject)-[:has_reference]->(" +
738 Constants.REFERENCE_IN_QUERY +
739 ":BasicReference)";
740 case parents -> "MATCH (" +
741 Constants.COLLECTION_IN_QUERY +
742 ":Collection)-[:has_dataobject]->(d:DataObject)<-[:has_child*0..]-(" +
743 Constants.DATAOBJECT_IN_QUERY +
744 ":DataObject)-[:has_reference]->(" +
745 Constants.REFERENCE_IN_QUERY +
746 ":BasicReference)";
747 case successors -> "MATCH (" +
748 Constants.COLLECTION_IN_QUERY +
749 ":Collection)-[:has_dataobject]->(d:DataObject)-[:has_successor*0..]->(" +
750 Constants.DATAOBJECT_IN_QUERY +
751 ":DataObject)-[:has_reference]->(" +
752 Constants.REFERENCE_IN_QUERY +
753 ":BasicReference)";
754 case predecessors -> "MATCH (" +
755 Constants.COLLECTION_IN_QUERY +
756 ":Collection)-[:has_dataobject]->(d:DataObject)<-[:has_successor*0..]-(" +
757 Constants.DATAOBJECT_IN_QUERY +
758 ":DataObject)-[:has_reference]->(" +
759 Constants.REFERENCE_IN_QUERY +
760 ":BasicReference)";
761 default -> "";
762 };
763 return ret;
764 }
765
766 private static String readableByPart(String username) {
767 String variable = Constants.COLLECTION_IN_QUERY;
768 return CypherQueryHelper.getReadableByQuery(variable, username);
769 }
770
771 public static String userSelectionQuery(String query) {
772 String ret = "";
773 ret = ret + userMatchPart();
774 ret = ret + " WHERE ";
775 ret = ret + getNeo4jWithNeo4jIdString(query, Constants.USER_IN_QUERY);
776 return ret;
777 }
778
779 private static String userMatchPart() {
780 String ret = "";
781 ret = ret + "MATCH (" + Constants.USER_IN_QUERY + ":User)";
782 return ret;
783 }
784
785 public static String userGroupSelectionQuery(String query) {
786 String ret = "";
787 ret = ret + userGroupMatchPart();
788 ret = ret + " WHERE ";
789 ret = ret + getNeo4jWithNeo4jIdString(query, Constants.USERGROUP_IN_QUERY);
790 return ret;
791 }
792
793 private static String userGroupMatchPart() {
794 String ret = "";
795 ret = ret + "MATCH (" + Constants.USERGROUP_IN_QUERY + ":UserGroup)";
796 return ret;
797 }
798 }