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.Constants;
14  import de.dlr.shepard.util.CypherQueryHelper;
15  import de.dlr.shepard.util.QueryParamHelper;
16  
17  public class DataObjectDAO extends VersionableEntityDAO<DataObject> {
18  
19  	@Override
20  	public Class<DataObject> getEntityType() {
21  		return DataObject.class;
22  	}
23  
24  	/**
25  	 * Searches the database for DataObjects.
26  	 *
27  	 * @param collectionId identifies the Collection
28  	 * @param params       encapsulates possible parameters
29  	 * @return a List of DataObjects
30  	 */
31  	public List<DataObject> findByCollectionByNeo4jIds(long collectionId, QueryParamHelper params) {
32  
33  		Map<String, Object> paramsMap = new HashMap<>();
34  		paramsMap.put("name", params.getName());
35  		if (params.hasPagination()) {
36  			paramsMap.put("offset", params.getPagination().getOffset());
37  			paramsMap.put("size", params.getPagination().getSize());
38  		}
39  		String match = "MATCH (c:Collection)-[hdo:has_dataobject]->"
40  				+ CypherQueryHelper.getObjectPart("d", "DataObject", params.hasName());
41  		String where = " WHERE ID(c)=" + collectionId;
42  
43  		if (params.hasParentId()) {
44  			if (params.getParentId() == -1) {
45  				where += " AND NOT EXISTS((d)<-[:has_child]-(:DataObject {deleted: FALSE}))";
46  			} else {
47  				match += "<-[:has_child]-(parent:DataObject {deleted: FALSE})";
48  				where += " AND ID(parent)=" + params.getParentId();
49  			}
50  		}
51  
52  		if (params.hasPredecessorId()) {
53  			if (params.getPredecessorId() == -1) {
54  				where += " AND NOT EXISTS((d)<-[:has_successor]-(:DataObject {deleted: FALSE}))";
55  			} else {
56  				match += "<-[:has_successor]-(predecessor:DataObject {deleted: FALSE})";
57  				where += " AND ID(predecessor)=" + params.getPredecessorId();
58  			}
59  		}
60  		if (params.hasSuccessorId()) {
61  			if (params.getSuccessorId() == -1) {
62  				where += " AND NOT EXISTS((d)-[:has_successor]->(:DataObject {deleted: FALSE}))";
63  			} else {
64  				match += "-[:has_successor]->(successor:DataObject {deleted: FALSE})";
65  				where += " AND ID(successor)=" + params.getSuccessorId();
66  			}
67  		}
68  
69  		String query = match + where + " WITH d";
70  		if (params.hasOrderByAttribute()) {
71  			query += " " + CypherQueryHelper.getOrderByPart("d", params.getOrderByAttribute(), params.getOrderDesc());
72  		}
73  		if (params.hasPagination()) {
74  			query += " " + CypherQueryHelper.getPaginationPart();
75  		}
76  		query += " " + CypherQueryHelper.getReturnPart("d");
77  		var result = new ArrayList<DataObject>();
78  		for (var obj :
79  
80  		findByQuery(query, paramsMap)) {
81  			List<DataObject> parentList = obj.getParent() != null ? List.of(obj.getParent()) : Collections.emptyList();
82  			if (matchCollection(obj, collectionId) && matchName(obj, params.getName())
83  					&& matchRelated(parentList, params.getParentId())
84  					&& matchRelated(obj.getSuccessors(), params.getSuccessorId())
85  					&& matchRelated(obj.getPredecessors(), params.getPredecessorId())) {
86  				result.add(obj);
87  			}
88  		}
89  
90  		return result;
91  	}
92  
93  	/**
94  	 * Searches the database for DataObjects.
95  	 *
96  	 * @param collectionShepardId  identifies the Collection
97  	 * @param paramsWithShepardIds encapsulates possible parameters
98  	 * @return a List of DataObjects
99  	 */
100 	public List<DataObject> findByCollectionByShepardIds(long collectionShepardId,
101 			QueryParamHelper paramsWithShepardIds) {
102 
103 		Map<String, Object> paramsMap = new HashMap<>();
104 		paramsMap.put("name", paramsWithShepardIds.getName());
105 		if (paramsWithShepardIds.hasPagination()) {
106 			paramsMap.put("offset", paramsWithShepardIds.getPagination().getOffset());
107 			paramsMap.put("size", paramsWithShepardIds.getPagination().getSize());
108 		}
109 		String match = "MATCH (c:Collection)-[hdo:has_dataobject]->"
110 				+ CypherQueryHelper.getObjectPart("d", "DataObject", paramsWithShepardIds.hasName());
111 		String where = " WHERE c." + Constants.SHEPARD_ID + "=" + collectionShepardId;
112 
113 		if (paramsWithShepardIds.hasParentId()) {
114 			if (paramsWithShepardIds.getParentId() == -1) {
115 				where += " AND NOT EXISTS((d)<-[:has_child]-(:DataObject {deleted: FALSE}))";
116 			} else {
117 				match += "<-[:has_child]-(parent:DataObject {deleted: FALSE, " + Constants.SHEPARD_ID + ": "
118 						+ paramsWithShepardIds.getParentId() + "})";
119 
120 			}
121 		}
122 
123 		if (paramsWithShepardIds.hasPredecessorId()) {
124 			if (paramsWithShepardIds.getPredecessorId() == -1) {
125 				where += " AND NOT EXISTS((d)<-[:has_successor]-(:DataObject {deleted: FALSE}))";
126 			} else {
127 				match += "<-[:has_successor]-(predecessor:DataObject {deleted: FALSE, " + Constants.SHEPARD_ID + ": "
128 						+ paramsWithShepardIds.getPredecessorId() + "})";
129 			}
130 		}
131 		if (paramsWithShepardIds.hasSuccessorId()) {
132 			if (paramsWithShepardIds.getSuccessorId() == -1) {
133 				where += " AND NOT EXISTS((d)-[:has_successor]->(:DataObject {deleted: FALSE}))";
134 			} else {
135 				match += "-[:has_successor]->(successor:DataObject {deleted: FALSE, " + Constants.SHEPARD_ID + ": "
136 						+ paramsWithShepardIds.getSuccessorId() + "})";
137 			}
138 		}
139 
140 		String query = match + where + " WITH d";
141 		if (paramsWithShepardIds.hasOrderByAttribute()) {
142 			query += " " + CypherQueryHelper.getOrderByPart("d", paramsWithShepardIds.getOrderByAttribute(),
143 					paramsWithShepardIds.getOrderDesc());
144 		}
145 		if (paramsWithShepardIds.hasPagination()) {
146 			query += " " + CypherQueryHelper.getPaginationPart();
147 		}
148 		query += " " + CypherQueryHelper.getReturnPart("d");
149 		var result = new ArrayList<DataObject>();
150 		for (var obj :
151 
152 		findByQuery(query, paramsMap)) {
153 			List<DataObject> parentList = obj.getParent() != null ? List.of(obj.getParent()) : Collections.emptyList();
154 			if (matchCollectionByShepardId(obj, collectionShepardId) && matchName(obj, paramsWithShepardIds.getName())
155 					&& matchRelatedByShepardId(parentList, paramsWithShepardIds.getParentId())
156 					&& matchRelatedByShepardId(obj.getSuccessors(), paramsWithShepardIds.getSuccessorId())
157 					&& matchRelatedByShepardId(obj.getPredecessors(), paramsWithShepardIds.getPredecessorId())) {
158 				result.add(obj);
159 			}
160 		}
161 
162 		return result;
163 	}
164 
165 	/**
166 	 * Delete dataObject and all related references
167 	 *
168 	 * @param id        identifies the dataObject
169 	 * @param updatedBy current date
170 	 * @param updatedAt current user
171 	 * @return whether the deletion was successful or not
172 	 */
173 	public boolean deleteDataObjectByNeo4jId(long id, User updatedBy, Date updatedAt) {
174 		var dataObject = findByNeo4jId(id);
175 		dataObject.setUpdatedBy(updatedBy);
176 		dataObject.setUpdatedAt(updatedAt);
177 		dataObject.setDeleted(true);
178 		createOrUpdate(dataObject);
179 		String query = String
180 				.format("MATCH (d:DataObject) WHERE ID(d) = %d OPTIONAL MATCH (d)-[:has_reference]->(r:BasicReference) "
181 						+ "FOREACH (n in [d,r] | SET n.deleted = true)", id);
182 		var result = runQuery(query, Collections.emptyMap());
183 		return result;
184 	}
185 
186 	/**
187 	 * Delete dataObject and all related references
188 	 *
189 	 * @param shepardId identifies the dataObject
190 	 * @param updatedBy current date
191 	 * @param updatedAt current user
192 	 * @return whether the deletion was successful or not
193 	 */
194 	public boolean deleteDataObjectByShepardId(long shepardId, User updatedBy, Date updatedAt) {
195 		DataObject dataObject = findByShepardId(shepardId);
196 		dataObject.setUpdatedBy(updatedBy);
197 		dataObject.setUpdatedAt(updatedAt);
198 		dataObject.setDeleted(true);
199 		createOrUpdate(dataObject);
200 		String query = String
201 				.format("MATCH (d:DataObject) WHERE ID(d) = %d OPTIONAL MATCH (d)-[:has_reference]->(r:BasicReference) "
202 						+ "FOREACH (n in [d,r] | SET n.deleted = true)", dataObject.getId());
203 		var result = runQuery(query, Collections.emptyMap());
204 		return result;
205 	}
206 
207 	private boolean matchName(DataObject obj, String name) {
208 		return name == null || name.equalsIgnoreCase(obj.getName());
209 	}
210 
211 	private boolean matchRelated(List<DataObject> related, Long id) {
212 		if (id == null) {
213 			return true;
214 		} else if (id == -1) {
215 			// return true if there is no related object or all objects are deleted
216 			return related.stream().allMatch(DataObject::isDeleted);
217 		} else {
218 			// return true if at least one related object that is not deleted matches the ID
219 			return related.stream().anyMatch(d -> !d.isDeleted() && d.getId().equals(id));
220 		}
221 	}
222 
223 	private boolean matchRelatedByShepardId(List<DataObject> related, Long shepardId) {
224 		if (shepardId == null) {
225 			return true;
226 		} else if (shepardId == -1) {
227 			// return true if there is no related object or all objects are deleted
228 			return related.stream().allMatch(DataObject::isDeleted);
229 		} else {
230 			// return true if at least one related object that is not deleted matches the ID
231 			return related.stream().anyMatch(d -> !d.isDeleted() && d.getShepardId().equals(shepardId));
232 		}
233 	}
234 
235 	private boolean matchCollection(DataObject obj, long collectionId) {
236 		return obj.getCollection() != null && obj.getCollection().getId().equals(collectionId);
237 	}
238 
239 	private boolean matchCollectionByShepardId(DataObject obj, long collectionShepardId) {
240 		return obj.getCollection() != null && obj.getCollection().getShepardId().equals(collectionShepardId);
241 	}
242 
243 	public List<DataObject> getDataObjectsByQuery(String query) {
244 		var queryResult = findByQuery(query, Collections.emptyMap());
245 		List<DataObject> ret = StreamSupport.stream(queryResult.spliterator(), false).toList();
246 		return ret;
247 	}
248 
249 }