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