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