1 package de.dlr.shepard.common.neo4j.daos;
2
3 import de.dlr.shepard.common.neo4j.NeoConnector;
4 import de.dlr.shepard.common.util.Constants;
5 import de.dlr.shepard.common.util.CypherQueryHelper;
6 import de.dlr.shepard.common.util.CypherQueryHelper.Neighborhood;
7 import de.dlr.shepard.common.util.TraversalRules;
8 import io.quarkus.logging.Log;
9 import java.util.Collection;
10 import java.util.Collections;
11 import java.util.HashMap;
12 import java.util.Map;
13 import java.util.stream.Stream;
14 import java.util.stream.StreamSupport;
15 import org.neo4j.ogm.cypher.Filter;
16 import org.neo4j.ogm.model.Result;
17 import org.neo4j.ogm.session.Session;
18
19 public abstract class GenericDAO<T> {
20
21 protected static final int DEPTH_ENTITY = 1;
22
23 protected Session session = null;
24
25 protected GenericDAO() {
26 session = NeoConnector.getInstance().getNeo4jSession();
27 }
28
29
30
31
32
33
34 public Collection<T> findAll() {
35 Collection<T> iter = session.loadAll(getEntityType(), DEPTH_ENTITY);
36 return iter;
37 }
38
39
40
41
42
43
44
45 public T findByNeo4jId(long id) {
46 return session.load(getEntityType(), id, DEPTH_ENTITY);
47 }
48
49
50
51
52
53
54
55 public T findLightByNeo4jId(long id) {
56 return session.load(getEntityType(), id, 0);
57 }
58
59
60
61
62
63
64
65 public Collection<T> findMatching(Filter filter) {
66 return session.loadAll(getEntityType(), filter, DEPTH_ENTITY);
67 }
68
69
70
71
72
73
74
75
76
77
78 public boolean deleteByNeo4jId(long id) {
79 T entity = session.load(getEntityType(), id);
80 if (entity != null) {
81 session.delete(entity);
82 return true;
83 }
84 return false;
85 }
86
87
88
89
90
91
92
93 public T createOrUpdate(T entity) {
94 session.save(entity, DEPTH_ENTITY);
95 return entity;
96 }
97
98 public void clearSession() {
99 session.clear();
100 }
101
102
103
104
105
106
107
108
109
110 public Iterable<T> findByQuery(String query, Map<String, Object> paramsMap) {
111 Log.debugf("Run query: %s", query);
112 StringBuilder str = new StringBuilder();
113 for (var entry : paramsMap.entrySet()) {
114 str.append("(" + entry.getKey() + ", " + entry.getValue() + "), ");
115 }
116 Log.debugf("queryParams: %s", str.toString());
117 Iterable<T> iter = session.query(getEntityType(), query, paramsMap);
118 return iter;
119 }
120
121 public Stream<T> findByQuery(String query) {
122 var results = session.query(getEntityType(), query, Collections.emptyMap());
123 return StreamSupport.stream(results.spliterator(), false);
124 }
125
126 public boolean runQuery(String query, Map<String, Object> paramsMap) {
127 Log.debugf("Run query: %s", query);
128 Result result = session.query(query, paramsMap);
129 return result.queryStatistics().containsUpdates();
130 }
131
132 public String getSearchForReachableReferencesByShepardIdQuery(
133 TraversalRules traversalRule,
134 long collectionShepardId,
135 long startShepardId,
136 String userName
137 ) {
138 String ret = "MATCH path = (col:Collection)-[:has_dataobject]->";
139 ret += getTraversalRulesPath(traversalRule);
140 ret += "-[hr:has_reference]->(r:" + getEntityType().getSimpleName() + ")";
141 ret += getWithPart("ns", "ret");
142 ret +=
143 " WHERE d." +
144 Constants.SHEPARD_ID +
145 " = " +
146 startShepardId +
147 " AND col." +
148 Constants.SHEPARD_ID +
149 " = " +
150 collectionShepardId;
151 ret += getReturnPart("ns", "ret", "col", userName);
152 return ret;
153 }
154
155 public String getSearchForReachableReferencesByNeo4jIdQuery(
156 TraversalRules traversalRule,
157 long collectionShepardId,
158 long startShepardId,
159 String userName
160 ) {
161 String ret = "MATCH path = (col:Collection)-[:has_dataobject]->";
162 ret += getTraversalRulesPath(traversalRule);
163 ret += "-[hr:has_reference]->(r:" + getEntityType().getSimpleName() + ")";
164 ret += getWithPart("ns", "ret");
165 ret += " WHERE id(d) = " + startShepardId + " AND id(col) = " + collectionShepardId;
166 ret += getReturnPart("ns", "ret", "col", userName);
167 return ret;
168 }
169
170 private String getTraversalRulesPath(TraversalRules traversalRule) {
171 if (traversalRule == null) return "(d:DataObject)";
172 return switch (traversalRule) {
173 case children -> "(d:DataObject)-[:has_child*0..]->(e:DataObject)";
174 case parents -> "(d:DataObject)<-[:has_child*0..]-(e:DataObject)";
175 case successors -> "(d:DataObject)-[:has_successor*0..]->(e:DataObject)";
176 case predecessors -> "(d:DataObject)<-[:has_successor*0..]-(e:DataObject)";
177 default -> "(d:DataObject)";
178 };
179 }
180
181 public String getSearchForReachableReferencesQuery(long collectionId, String userName) {
182 String ret = "MATCH path = (col:Collection)-[:has_dataobject]->(do:DataObject)";
183 ret += "-[hr:has_reference]->(r:" + getEntityType().getSimpleName() + ")";
184 ret += getWithPart("ns", "ret");
185 ret += " WHERE id(col) = " + collectionId;
186 ret += getReturnPart("ns", "ret", "col", userName);
187 return ret;
188 }
189
190 public String getSearchForReachableReferencesByShepardIdQuery(long collectionShepardId, String userName) {
191 String ret = "MATCH path = (col:Collection)-[:has_dataobject]->(do:DataObject)";
192 ret += "-[hr:has_reference]->(r:" + getEntityType().getSimpleName() + ")";
193 ret += getWithPart("ns", "ret");
194 ret += " WHERE col." + Constants.SHEPARD_ID + " = " + collectionShepardId;
195 ret += getReturnPart("ns", "ret", "col", userName);
196 return ret;
197 }
198
199 public String getSearchForReachableReferencesQuery(long collectionId, long startId, String userName) {
200 String ret = "MATCH path = (col:Collection)-[:has_dataobject]->(d:DataObject)";
201 ret += "-[hr:has_reference]->(r:" + getEntityType().getSimpleName() + ")";
202 ret += getWithPart("ns", "ret");
203 ret += " WHERE id(d) = " + startId + " AND id(col) = " + collectionId;
204 ret += getReturnPart("ns", "ret", "col", userName);
205 return ret;
206 }
207
208 public String getSearchForReachableReferencesByShepardIdQuery(
209 long collectionShepardId,
210 long startShepardId,
211 String userName
212 ) {
213 String ret = "MATCH path = (col:Collection)-[:has_dataobject]->(d:DataObject)";
214 ret += "-[hr:has_reference]->(r:" + getEntityType().getSimpleName() + ")";
215 ret += getWithPart("ns", "ret");
216 ret +=
217 " WHERE d." +
218 Constants.SHEPARD_ID +
219 " = " +
220 startShepardId +
221 " AND col." +
222 Constants.SHEPARD_ID +
223 " = " +
224 collectionShepardId;
225 ret += getReturnPart("ns", "ret", "col", userName);
226 return ret;
227 }
228
229 private String getWithPart(String nodesVar, String retVar) {
230 return " WITH nodes(path) as " + nodesVar + ", r as " + retVar;
231 }
232
233 private String getReturnPart(String nodesVar, String retVar, String collectionVar, String username) {
234 String ret = "";
235 ret += " AND NONE(node IN " + nodesVar + " WHERE (node.deleted = TRUE))";
236 ret += " AND " + CypherQueryHelper.getReadableByQuery(collectionVar, username);
237 ret += " " + CypherQueryHelper.getReturnPart(retVar, Neighborhood.EVERYTHING);
238 return ret;
239 }
240
241 public void deleteRelation(long fromId, long toId, String fromType, String toType, String relationName) {
242 String query =
243 "MATCH (a:%s {shepardId: %s})-[r:%s]->(b:%s {shepardId: %s}) DELETE r;".formatted(
244 fromType,
245 fromId,
246 relationName,
247 toType,
248 toId
249 );
250 session.query(query, new HashMap<String, String>());
251 }
252
253 public abstract Class<T> getEntityType();
254 }