View Javadoc
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 }