View Javadoc
1   package de.dlr.shepard.neo4Core.dao;
2   
3   import java.util.ArrayList;
4   import java.util.Collections;
5   import java.util.Date;
6   import java.util.HashMap;
7   import java.util.List;
8   import java.util.Map;
9   import java.util.stream.StreamSupport;
10  
11  import de.dlr.shepard.neo4Core.entities.DataObject;
12  import de.dlr.shepard.neo4Core.entities.User;
13  import de.dlr.shepard.util.CypherQueryHelper;
14  import de.dlr.shepard.util.QueryParamHelper;
15  
16  public class DataObjectDAO extends GenericDAO<DataObject> {
17  
18  	@Override
19  	public Class<DataObject> getEntityType() {
20  		return DataObject.class;
21  	}
22  
23  	/**
24  	 * Searches the database for DataObjects.
25  	 *
26  	 * @param collectionId identifies the Collection
27  	 * @param params       encapsulates possible parameters
28  	 * @return a List of DataObjects
29  	 */
30  	public List<DataObject> findByCollection(long collectionId, QueryParamHelper params) {
31  
32  		Map<String, Object> paramsMap = new HashMap<>();
33  		paramsMap.put("name", params.getName());
34  		if (params.hasPagination()) {
35  			paramsMap.put("offset", params.getPagination().getOffset());
36  			paramsMap.put("size", params.getPagination().getSize());
37  		}
38  		String match = "MATCH (c:Collection)-[hdo:has_dataobject]->"
39  				+ CypherQueryHelper.getObjectPart("d", "DataObject", params.hasName());
40  		String where = " WHERE ID(c)=" + collectionId;
41  
42  		if (params.hasParentId()) {
43  			if (params.getParentId() == -1) {
44  				where += " AND NOT EXISTS((d)<-[:has_child]-(:DataObject {deleted: FALSE}))";
45  			} else {
46  				match += "<-[:has_child]-(parent:DataObject {deleted: FALSE})";
47  				where += " AND ID(parent)=" + params.getParentId();
48  			}
49  		}
50  
51  		if (params.hasPredecessorId()) {
52  			if (params.getPredecessorId() == -1) {
53  				where += " AND NOT EXISTS((d)<-[:has_successor]-(:DataObject {deleted: FALSE}))";
54  			} else {
55  				match += "<-[:has_successor]-(predecessor:DataObject {deleted: FALSE})";
56  				where += " AND ID(predecessor)=" + params.getPredecessorId();
57  			}
58  		}
59  		if (params.hasSuccessorId()) {
60  			if (params.getSuccessorId() == -1) {
61  				where += " AND NOT EXISTS((d)-[:has_successor]->(:DataObject {deleted: FALSE}))";
62  			} else {
63  				match += "-[:has_successor]->(successor:DataObject {deleted: FALSE})";
64  				where += " AND ID(successor)=" + params.getSuccessorId();
65  			}
66  		}
67  
68  		String query = match + where + " WITH d";
69  		if (params.hasOrderByAttribute()) {
70  			query += " " + CypherQueryHelper.getOrderByPart("d", params.getOrderByAttribute(), params.getOrderDesc());
71  		}
72  		if (params.hasPagination()) {
73  			query += " " + CypherQueryHelper.getPaginationPart();
74  		}
75  		query += " " + CypherQueryHelper.getReturnPart("d");
76  		var result = new ArrayList<DataObject>();
77  		for (var obj :
78  
79  		findByQuery(query, paramsMap)) {
80  			List<DataObject> parentList = obj.getParent() != null ? List.of(obj.getParent()) : Collections.emptyList();
81  			if (matchCollection(obj, collectionId) && matchName(obj, params.getName())
82  					&& matchRelated(parentList, params.getParentId())
83  					&& matchRelated(obj.getSuccessors(), params.getSuccessorId())
84  					&& matchRelated(obj.getPredecessors(), params.getPredecessorId())) {
85  				result.add(obj);
86  			}
87  		}
88  
89  		return result;
90  	}
91  
92  	/**
93  	 * Delete dataObject and all related references
94  	 *
95  	 * @param id        identifies the dataObject
96  	 * @param updatedBy current date
97  	 * @param updatedAt current user
98  	 * @return whether the deletion was successful or not
99  	 */
100 	public boolean deleteDataObject(long id, User updatedBy, Date updatedAt) {
101 		var dataObject = find(id);
102 		dataObject.setUpdatedBy(updatedBy);
103 		dataObject.setUpdatedAt(updatedAt);
104 		dataObject.setDeleted(true);
105 		createOrUpdate(dataObject);
106 		String query = String
107 				.format("MATCH (d:DataObject) WHERE ID(d) = %d OPTIONAL MATCH (d)-[:has_reference]->(r:BasicReference) "
108 						+ "FOREACH (n in [d,r] | SET n.deleted = true)", id);
109 		var result = runQuery(query, Collections.emptyMap());
110 		return result;
111 	}
112 
113 	private boolean matchName(DataObject obj, String name) {
114 		return name == null || name.equalsIgnoreCase(obj.getName());
115 	}
116 
117 	private boolean matchRelated(List<DataObject> related, Long id) {
118 		if (id == null) {
119 			return true;
120 		} else if (id == -1) {
121 			// return true if there is no related object or all objects are deleted
122 			return related.stream().allMatch(DataObject::isDeleted);
123 		} else {
124 			// return true if at least one related object that is not deleted matches the ID
125 			return related.stream().anyMatch(d -> !d.isDeleted() && d.getId().equals(id));
126 		}
127 	}
128 
129 	private boolean matchCollection(DataObject obj, long collectionId) {
130 		return obj.getCollection() != null && obj.getCollection().getId().equals(collectionId);
131 	}
132 
133 	public List<DataObject> getDataObjectsByQuery(String query) {
134 		var queryResult = findByQuery(query, Collections.emptyMap());
135 		List<DataObject> ret = StreamSupport.stream(queryResult.spliterator(), false).toList();
136 		return ret;
137 	}
138 
139 }