1 package de.dlr.shepard.context.collection.daos;
2
3 import de.dlr.shepard.auth.users.entities.User;
4 import de.dlr.shepard.common.util.Constants;
5 import de.dlr.shepard.common.util.CypherQueryHelper;
6 import de.dlr.shepard.common.util.QueryParamHelper;
7 import de.dlr.shepard.context.collection.entities.DataObject;
8 import de.dlr.shepard.context.version.daos.VersionableEntityDAO;
9 import jakarta.enterprise.context.RequestScoped;
10 import java.util.ArrayList;
11 import java.util.Collections;
12 import java.util.Date;
13 import java.util.HashMap;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.UUID;
17 import java.util.stream.StreamSupport;
18 import org.neo4j.cypherdsl.core.Cypher;
19 import org.neo4j.cypherdsl.core.Node;
20
21 @RequestScoped
22 public class DataObjectDAO extends VersionableEntityDAO<DataObject> {
23
24 @Override
25 public Class<DataObject> getEntityType() {
26 return DataObject.class;
27 }
28
29
30
31
32
33
34
35
36 public List<DataObject> findByCollectionByNeo4jIds(long collectionId, QueryParamHelper params) {
37 Map<String, Object> paramsMap = new HashMap<>();
38 paramsMap.put("name", params.getName());
39 if (params.hasPagination()) {
40 paramsMap.put("offset", params.getPagination().getOffset());
41 paramsMap.put("size", params.getPagination().getSize());
42 }
43 String match =
44 "MATCH (c:Collection)-[hdo:has_dataobject]->" +
45 CypherQueryHelper.getObjectPart("d", "DataObject", params.hasName());
46 String where = " WHERE ID(c)=" + collectionId;
47
48 if (params.hasParentId()) {
49 if (params.getParentId() == -1) {
50 where += " AND NOT EXISTS((d)<-[:has_child]-(:DataObject {deleted: FALSE}))";
51 } else {
52 match += "<-[:has_child]-(parent:DataObject {deleted: FALSE})";
53 where += " AND ID(parent)=" + params.getParentId();
54 }
55 }
56
57 if (params.hasPredecessorId()) {
58 if (params.getPredecessorId() == -1) {
59 where += " AND NOT EXISTS((d)<-[:has_successor]-(:DataObject {deleted: FALSE}))";
60 } else {
61 match += "<-[:has_successor]-(predecessor:DataObject {deleted: FALSE})";
62 where += " AND ID(predecessor)=" + params.getPredecessorId();
63 }
64 }
65 if (params.hasSuccessorId()) {
66 if (params.getSuccessorId() == -1) {
67 where += " AND NOT EXISTS((d)-[:has_successor]->(:DataObject {deleted: FALSE}))";
68 } else {
69 match += "-[:has_successor]->(successor:DataObject {deleted: FALSE})";
70 where += " AND ID(successor)=" + params.getSuccessorId();
71 }
72 }
73
74 String query = match + where + " WITH d";
75 if (params.hasOrderByAttribute()) {
76 query += " " + CypherQueryHelper.getOrderByPart("d", params.getOrderByAttribute(), params.getOrderDesc());
77 }
78 if (params.hasPagination()) {
79 query += " " + CypherQueryHelper.getPaginationPart();
80 }
81 query += " " + CypherQueryHelper.getReturnPart("d");
82 var result = new ArrayList<DataObject>();
83 for (var obj : findByQuery(query, paramsMap)) {
84 List<DataObject> parentList = obj.getParent() != null ? List.of(obj.getParent()) : Collections.emptyList();
85 if (
86 matchCollection(obj, collectionId) &&
87 matchName(obj, params.getName()) &&
88 matchRelated(parentList, params.getParentId()) &&
89 matchRelated(obj.getSuccessors(), params.getSuccessorId()) &&
90 matchRelated(obj.getPredecessors(), params.getPredecessorId())
91 ) {
92 result.add(obj);
93 }
94 }
95
96 return result;
97 }
98
99 public List<DataObject> findByCollectionByShepardIds(
100 long collectionShepardId,
101 QueryParamHelper paramsWithShepardIds
102 ) {
103 return findByCollectionByShepardIds(collectionShepardId, paramsWithShepardIds, null);
104 }
105
106
107
108
109 public void deleteHasSuccessorRelation(long predecessorShepardId, long successorShepardId) {
110 deleteRelation(
111 predecessorShepardId,
112 successorShepardId,
113 getEntityType().getSimpleName(),
114 getEntityType().getSimpleName(),
115 Constants.HAS_SUCCESSOR
116 );
117 }
118
119
120
121
122 public void deleteHasChildRelation(long parentShepardId, long childShepardId) {
123 deleteRelation(
124 parentShepardId,
125 childShepardId,
126 getEntityType().getSimpleName(),
127 getEntityType().getSimpleName(),
128 Constants.HAS_CHILD
129 );
130 }
131
132
133
134
135
136 public void deleteAllAttributes(DataObject dataObject) {
137 if (dataObject.getAttributes() == null || dataObject.getAttributes().isEmpty()) return;
138 Node d = Cypher.node("DataObject");
139 String st = Cypher.match(d)
140 .where(d.internalId().isEqualTo(Cypher.literalOf(dataObject.getId())))
141 .remove(dataObject.getAttributes().keySet().stream().map(key -> d.property("attributes||" + key)).toList())
142 .build()
143 .getCypher();
144 session.query(st, new HashMap<String, String>());
145 }
146
147
148
149
150
151
152
153
154 public List<DataObject> findByCollectionByShepardIds(
155 long collectionShepardId,
156 QueryParamHelper paramsWithShepardIds,
157 UUID versionUID
158 ) {
159 Map<String, Object> paramsMap = new HashMap<>();
160 paramsMap.put("name", paramsWithShepardIds.getName());
161 if (paramsWithShepardIds.hasPagination()) {
162 paramsMap.put("offset", paramsWithShepardIds.getPagination().getOffset());
163 paramsMap.put("size", paramsWithShepardIds.getPagination().getSize());
164 }
165 String match =
166 "MATCH (v:Version)<-[:has_version]-(c:Collection)-[hdo:has_dataobject]->" +
167 CypherQueryHelper.getObjectPart("d", "DataObject", paramsWithShepardIds.hasName());
168 String where = " WHERE c." + Constants.SHEPARD_ID + "=" + collectionShepardId + " AND ";
169
170 if (versionUID == null) where = where + CypherQueryHelper.getVersionHeadPart("v");
171
172 else where = where + CypherQueryHelper.getVersionPart("v", versionUID);
173 if (paramsWithShepardIds.hasParentId()) {
174 if (paramsWithShepardIds.getParentId() == -1) {
175 where += " AND NOT EXISTS((d)<-[:has_child]-(:DataObject {deleted: FALSE}))";
176 } else {
177 match +=
178 "<-[:has_child]-(parent:DataObject {deleted: FALSE, " +
179 Constants.SHEPARD_ID +
180 ": " +
181 paramsWithShepardIds.getParentId() +
182 "})";
183 }
184 }
185
186 if (paramsWithShepardIds.hasPredecessorId()) {
187 if (paramsWithShepardIds.getPredecessorId() == -1) {
188 where += " AND NOT EXISTS((d)<-[:has_successor]-(:DataObject {deleted: FALSE}))";
189 } else {
190 match +=
191 "<-[:has_successor]-(predecessor:DataObject {deleted: FALSE, " +
192 Constants.SHEPARD_ID +
193 ": " +
194 paramsWithShepardIds.getPredecessorId() +
195 "})";
196 }
197 }
198 if (paramsWithShepardIds.hasSuccessorId()) {
199 if (paramsWithShepardIds.getSuccessorId() == -1) {
200 where += " AND NOT EXISTS((d)-[:has_successor]->(:DataObject {deleted: FALSE}))";
201 } else {
202 match +=
203 "-[:has_successor]->(successor:DataObject {deleted: FALSE, " +
204 Constants.SHEPARD_ID +
205 ": " +
206 paramsWithShepardIds.getSuccessorId() +
207 "})";
208 }
209 }
210
211 String query = match + where + " WITH d";
212 if (paramsWithShepardIds.hasOrderByAttribute()) {
213 query +=
214 " " +
215 CypherQueryHelper.getOrderByPart(
216 "d",
217 paramsWithShepardIds.getOrderByAttribute(),
218 paramsWithShepardIds.getOrderDesc()
219 );
220 }
221 if (paramsWithShepardIds.hasPagination()) {
222 query += " " + CypherQueryHelper.getPaginationPart();
223 }
224 query += " " + CypherQueryHelper.getReturnPart("d");
225 var result = new ArrayList<DataObject>();
226 for (var obj : findByQuery(query, paramsMap)) {
227 List<DataObject> parentList = obj.getParent() != null ? List.of(obj.getParent()) : Collections.emptyList();
228 if (
229 matchCollectionByShepardId(obj, collectionShepardId) &&
230 matchName(obj, paramsWithShepardIds.getName()) &&
231 matchRelatedByShepardId(parentList, paramsWithShepardIds.getParentId()) &&
232 matchRelatedByShepardId(obj.getSuccessors(), paramsWithShepardIds.getSuccessorId()) &&
233 matchRelatedByShepardId(obj.getPredecessors(), paramsWithShepardIds.getPredecessorId())
234 ) {
235 result.add(obj);
236 }
237 }
238
239 return result;
240 }
241
242
243
244
245
246
247
248
249
250 public boolean deleteDataObjectByNeo4jId(long id, User updatedBy, Date updatedAt) {
251 var dataObject = findByNeo4jId(id);
252 dataObject.setUpdatedBy(updatedBy);
253 dataObject.setUpdatedAt(updatedAt);
254 dataObject.setDeleted(true);
255 createOrUpdate(dataObject);
256 String query = String.format(
257 "MATCH (d:DataObject) WHERE ID(d) = %d OPTIONAL MATCH (d)-[:has_reference]->(r:BasicReference) " +
258 "FOREACH (n in [d,r] | SET n.deleted = true)",
259 id
260 );
261 var result = runQuery(query, Collections.emptyMap());
262 return result;
263 }
264
265
266
267
268
269
270
271
272
273 public boolean deleteDataObjectByShepardId(long shepardId, User updatedBy, Date updatedAt) {
274 DataObject dataObject = findByShepardId(shepardId);
275 dataObject.setUpdatedBy(updatedBy);
276 dataObject.setUpdatedAt(updatedAt);
277 dataObject.setDeleted(true);
278 createOrUpdate(dataObject);
279 String query = String.format(
280 "MATCH (d:DataObject) WHERE ID(d) = %d OPTIONAL MATCH (d)-[:has_reference]->(r:BasicReference) " +
281 "FOREACH (n in [d,r] | SET n.deleted = true)",
282 dataObject.getId()
283 );
284 var result = runQuery(query, Collections.emptyMap());
285 return result;
286 }
287
288 private boolean matchName(DataObject obj, String name) {
289 return name == null || name.equalsIgnoreCase(obj.getName());
290 }
291
292 private boolean matchRelated(List<DataObject> related, Long id) {
293 if (id == null) {
294 return true;
295 } else if (id == -1) {
296
297 return related.stream().allMatch(DataObject::isDeleted);
298 } else {
299
300 return related.stream().anyMatch(d -> !d.isDeleted() && d.getId().equals(id));
301 }
302 }
303
304 private boolean matchRelatedByShepardId(List<DataObject> related, Long shepardId) {
305 if (shepardId == null) {
306 return true;
307 } else if (shepardId == -1) {
308
309 return related.stream().allMatch(DataObject::isDeleted);
310 } else {
311
312 return related.stream().anyMatch(d -> !d.isDeleted() && d.getShepardId().equals(shepardId));
313 }
314 }
315
316 private boolean matchCollection(DataObject obj, long collectionId) {
317 return obj.getCollection() != null && obj.getCollection().getId().equals(collectionId);
318 }
319
320 private boolean matchCollectionByShepardId(DataObject obj, long collectionShepardId) {
321 return obj.getCollection() != null && obj.getCollection().getShepardId().equals(collectionShepardId);
322 }
323
324 public List<DataObject> getDataObjectsByQuery(String query) {
325 var queryResult = findByQuery(query, Collections.emptyMap());
326 List<DataObject> ret = StreamSupport.stream(queryResult.spliterator(), false).toList();
327 return ret;
328 }
329 }