1 package model.repository;
2
3 import model.entity.Post;
4 import model.entity.Section;
5 import model.entity.User;
6
7 import javax.persistence.EntityManager;
8 import javax.persistence.PersistenceContext;
9 import javax.persistence.TypedQuery;
10 import javax.persistence.criteria.*;
11 import java.io.Serializable;
12 import java.time.Instant;
13 import java.util.ArrayList;
14 import java.util.Collections;
15 import java.util.List;
16
17 /**
18 * Classe che incapsula la logica per il recupero di entità di tipo {@link Post}
19 */
20 public class PostRepository implements Serializable {
21
22 @PersistenceContext
23 protected EntityManager em;
24
25 /**
26 * Restituisce una nuova istanza di PostFinder
27 * @return nuova istanza di PostFinder
28 */
29 public PostFinder getFinder(){
30 return new PostFinder();
31 }
32
33 private enum SortCriteria {OLDEST, NEWEST, MOSTVOTED};
34
35 /**
36 * Classe interna usata per specificare i parametri di ricerca di un post
37 */
38 public class PostFinder {
39 private User author;
40 private List<Section> sections;
41 private Instant before;
42 private Instant after;
43 private int offset = 0;
44 private int pageSize = 30;
45 private String content;
46 private boolean includeBody = false;
47 private User joinUserFollows;
48 private SortCriteria sortCriteria = PostRepository.SortCriteria.NEWEST;
49
50 protected PostFinder(){ }
51
52 /**
53 * Setta il campo author e restituisce l'istanza passata di PostFinder
54 * @param author entità User dell'autore dei post
55 * @return istanza passata di PostFinder
56 */
57 public PostFinder byAuthor(User author){
58 this.author = author;
59 return this;
60 }
61
62 /**
63 * Setta il campo content e restituisce l'istanza passata di PostFinder
64 * @param author text contenuto dei post
65 * @return istanza passata di PostFinder
66 */
67 public PostFinder byContent(String text){
68 this.content = text;
69 return this;
70 }
71
72 /**
73 * Setta il campo sections e restituisce l'istanza passata di PostFinder
74 * @param sections lista di sezioni
75 * @return istanza passata di PostFinder
76 */
77 public PostFinder bySections(List<Section> sections){
78 this.sections = sections;
79 return this;
80 }
81
82 /**
83 * Setta il campo sections e restituisce l'istanza passata di PostFinder
84 * @param sections sezione dei post
85 * @return istanza passata di PostFinder
86 */
87 public PostFinder bySection(Section section){
88 this.sections = Collections.singletonList(section);
89 return this;
90 }
91
92 /**
93 * Setta il campo postedAfter e restituisce l'istanza passata di PostFinder
94 * @param after data dopo la quale i post da trovare sono stati postati
95 * @return istanza passata di PostFinder
96 */
97 public PostFinder postedAfter(Instant after){
98 this.after = after;
99 return this;
100 }
101
102 /**
103 * Setta il campo postedBefore e restituisce l'istanza passata di PostFinder
104 * @param before data prima della quale i post da trovare sono stati postati
105 * @return istanza passata di PostFinder
106 */
107 public PostFinder postedBefore(Instant before){
108 this.before = before;
109 return this;
110 }
111
112 /**
113 * Setta il campo offset e restituisce l'istanza passata di PostFinder
114 * @param n offset per la paginazione
115 * @return istanza passata di PostFinder
116 */
117 public PostFinder offset(int n){
118 offset = n;
119 return this;
120 }
121
122 /**
123 * Setta il campo limit e restituisce l'istanza passata di PostFinder
124 * @param n limite di post da caricare
125 * @return istanza passata di PostFinder
126 */
127 public PostFinder limit(int n){
128 pageSize = n;
129 return this;
130 }
131
132 /**
133 * Setta il campo sortCriteria a oldest e restituisce l'istanza passata di PostFinder
134 * @return istanza passata di PostFinder
135 */
136 public PostFinder getOldest(){
137 sortCriteria = SortCriteria.OLDEST;
138 return this;
139 }
140
141 /**
142 * Setta il campo sortCriteria a newest e restituisce l'istanza passata di PostFinder
143 * @return istanza passata di PostFinder
144 */
145 public PostFinder getNewest(){
146 sortCriteria = SortCriteria.NEWEST;
147 return this;
148 }
149
150 /**
151 * Setta il campo sortCriteria a most voted e restituisce l'istanza passata di PostFinder
152 * @return istanza passata di PostFinder
153 */
154 public PostFinder getMostVoted(){
155 sortCriteria = SortCriteria.MOSTVOTED;
156 return this;
157 }
158
159 /**
160 * Setta il campo includeBody a true e restituisce l'istanza passata di PostFinder
161 * @return istanza passata di PostFinder
162 */
163 public PostFinder includeBody(){
164 includeBody = true;
165 return this;
166 }
167
168 /**
169 * Setta il campo joinUserFollows e restituisce l'istanza passata di PostFinder
170 * @param user entita utente da cui ottenere le sezioni seguite
171 * @return istanza passata di PostFinder
172 */
173 public PostFinder joinUserFollows(User user){
174 joinUserFollows = user;
175 return this;
176 }
177
178 /**
179 * Restituisce tutti i post che rispettano i criteri di ricerca
180 * @return lista di entità Post
181 */
182 public List<Post> getResults(){
183 CriteriaBuilder cb = em.getCriteriaBuilder();
184 CriteriaQuery<Post> cq = cb.createQuery(Post.class);
185 Root<Post> root = cq.from(Post.class);
186
187 List<Predicate> predicates = new ArrayList<>();
188
189 if(author != null) {
190 predicates.add(cb.equal(root.get("author"), author));
191 }
192
193 if(sections != null && !sections.isEmpty()) {
194 predicates.add(root.get("section").in(sections));
195 }
196
197 if(after != null) {
198 predicates.add(cb.greaterThanOrEqualTo(root.get("creationDate"), after));
199 }
200
201 if(before != null) {
202 predicates.add(cb.lessThanOrEqualTo(root.get("creationDate"), before));
203 }
204
205 if(content != null) {
206 if(includeBody) {
207 predicates.add(
208 cb.or(
209 cb.like(root.get("title"), '%' + content + '%'),
210 cb.and(
211 cb.notEqual(root.get("type"), Post.Type.IMG),
212 cb.like(root.get("content"), '%' + content + '%')
213 )));
214 } else {
215 predicates.add(cb.like(root.get("title"), '%' + content + '%'));
216 }
217 }
218
219 if(joinUserFollows != null){
220 Join<Object, Object> joinFollow = root.join("section").join("follows");
221 predicates.add(cb.equal(joinFollow.get("user"), joinUserFollows));
222 }
223
224 cq.where(cb.and(predicates.toArray(Predicate[]::new)));
225
226 switch (sortCriteria) {
227 case MOSTVOTED:
228 cq.orderBy(cb.desc(root.get("votesCount")));
229 break;
230 case OLDEST:
231 cq.orderBy(cb.asc(root.get("creationDate")));
232 break;
233 case NEWEST:
234 default:
235 cq.orderBy(cb.desc(root.get("creationDate")));
236 break;
237 }
238
239
240 TypedQuery<Post> tq = em.createQuery(cq);
241 if(offset >= 0)
242 tq.setFirstResult(offset);
243 if(pageSize>=0)
244 tq.setMaxResults(pageSize);
245
246 return tq.getResultList();
247 }
248 }
249 }