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