22
33import static java .util .stream .Collectors .toList ;
44
5- import com .blazebit .persistence .CriteriaBuilder ;
6- import com .blazebit .persistence .CriteriaBuilderFactory ;
75import eu .mulk .mulkcms2 .benki .accesscontrol .Role ;
86import eu .mulk .mulkcms2 .benki .bookmarks .Bookmark ;
97import eu .mulk .mulkcms2 .benki .lazychat .LazychatMessage ;
108import eu .mulk .mulkcms2 .benki .newsletter .Newsletter ;
119import eu .mulk .mulkcms2 .benki .users .User ;
12- import org .hibernate .annotations .JdbcTypeCode ;
13- import org .hibernate .type .SqlTypes ;
10+ import eu .mulk .mulkcms2 .benki .users .User_ ;
1411import io .quarkus .hibernate .orm .panache .PanacheEntityBase ;
1512import jakarta .annotation .Nullable ;
1613import jakarta .json .bind .annotation .JsonbTransient ;
1714import jakarta .persistence .CascadeType ;
1815import jakarta .persistence .Column ;
1916import jakarta .persistence .Entity ;
20- import jakarta .persistence .EntityManager ;
2117import jakarta .persistence .EnumType ;
2218import jakarta .persistence .Enumerated ;
2319import jakarta .persistence .FetchType ;
3531import jakarta .persistence .OrderBy ;
3632import jakarta .persistence .SequenceGenerator ;
3733import jakarta .persistence .Table ;
34+ import jakarta .persistence .criteria .CriteriaBuilder ;
35+ import jakarta .persistence .criteria .CriteriaQuery ;
36+ import jakarta .persistence .criteria .From ;
37+ import jakarta .persistence .criteria .JoinType ;
38+ import jakarta .persistence .criteria .Predicate ;
3839import java .time .LocalDate ;
3940import java .time .OffsetDateTime ;
4041import java .util .ArrayList ;
4849import java .util .TimeZone ;
4950import java .util .regex .Pattern ;
5051import java .util .stream .Collectors ;
52+ import java .util .stream .Stream ;
5153import javax .annotation .CheckForNull ;
52- import org .hibernate .annotations .Type ;
54+ import org .hibernate .Session ;
55+ import org .hibernate .annotations .JdbcTypeCode ;
5356import org .hibernate .annotations .SQLRestriction ;
57+ import org .hibernate .type .SqlTypes ;
5458
5559@ Entity
5660@ Table (name = "posts" , schema = "benki" )
@@ -171,76 +175,80 @@ public Visibility getVisibility() {
171175 }
172176 }
173177
174- protected static <T extends Post <?>> CriteriaBuilder <T > queryViewable (
178+ protected static <T extends Post > CriteriaQuery <T > queryViewable (
175179 Class <T > entityClass ,
176180 @ CheckForNull User reader ,
177181 @ CheckForNull User owner ,
178182 @ CheckForNull Integer cursor ,
179- EntityManager em ,
180- CriteriaBuilderFactory cbf ,
183+ CriteriaBuilder cb ,
181184 boolean forward ,
182185 @ CheckForNull String searchQuery ) {
186+ CriteriaQuery <T > query = cb .createQuery (entityClass );
183187
184- CriteriaBuilder < T > cb = cbf . create ( em , entityClass ). select ( "post" );
188+ var conditions = new ArrayList < Predicate >( );
185189
190+ From <?, T > post ;
186191 if (reader == null ) {
187- cb =
188- cb .from (entityClass , "post" )
189- .innerJoin ("post.targets" , "role" )
190- .where ("'world'" )
191- .isMemberOf ("role.tags" );
192+ post = query .from (entityClass );
193+ var target = post .join (Post_ .targets );
194+ conditions .add (cb .equal (target , Role .getWorld ()));
192195 } else {
193- cb = cb .from (User .class , "user" ).where ("user" ).eq (reader );
196+ var root = query .from (User .class );
197+ conditions .add (cb .equal (root , reader ));
194198 if (entityClass .isAssignableFrom (Post .class )) {
195- cb = cb . innerJoin ( "user .visiblePosts" , "post" );
199+ post = ( From <?, T >) root . join ( User_ .visiblePosts );
196200 } else if (entityClass .isAssignableFrom (Bookmark .class )) {
197- cb = cb . innerJoin ( "user .visibleBookmarks" , "post" );
201+ post = ( From <?, T >) root . join ( User_ .visibleBookmarks );
198202 } else if (entityClass .isAssignableFrom (LazychatMessage .class )) {
199- cb = cb . innerJoin ( "user .visibleLazychatMessages" , "post" );
203+ post = ( From <?, T >) root . join ( User_ .visibleLazychatMessages );
200204 } else {
201205 throw new IllegalArgumentException ();
202206 }
203207 }
204208
205- cb = cb .fetch ("post.owner" );
209+ query .select (post );
210+ post .fetch (Post_ .owner , JoinType .LEFT );
206211
207212 if (owner != null ) {
208- cb = cb . where ( " post.owner" ). eq ( owner );
213+ conditions . add ( cb . equal ( post .get ( Post_ . owner ), owner ) );
209214 }
210215
211216 if (forward ) {
212- cb = cb . orderByDesc ( " post.id" );
217+ query . orderBy ( cb . desc ( post .get ( Post_ . id )) );
213218 } else {
214- cb = cb . orderByAsc ( " post.id" );
219+ query . orderBy ( cb . asc ( post .get ( Post_ . id )) );
215220 }
216221
217222 if (cursor != null ) {
218223 if (forward ) {
219- cb = cb . where ( " post.id" ). le ( cursor );
224+ conditions . add ( cb . le ( post .get ( Post_ . id ), cursor ) );
220225 } else {
221- cb = cb . where ( " post.id" ). gt ( cursor );
226+ conditions . add ( cb . gt ( post .get ( Post_ . id ), cursor ) );
222227 }
223228 }
224229
225230 if (searchQuery != null && !searchQuery .isBlank ()) {
226- cb =
227- cb .whereExists ()
228- .from (PostText .class , "postText" )
229- .where ("postText.post" )
230- .eqExpression ("post" )
231- .whereOr ()
232- .whereExpression (
233- "post_matches_websearch(postText.searchTerms, 'de', :searchQueryText) = true" )
234- .whereExpression (
235- "post_matches_websearch(postText.searchTerms, 'en', :searchQueryText) = true" )
236- .endOr ()
237- .end ()
238- .setParameter ("searchQueryText" , searchQuery );
231+ var postTexts = post .join (Post_ .texts );
232+ var localizedSearches =
233+ Stream .of ("de" , "en" )
234+ .map (
235+ language ->
236+ cb .isTrue (
237+ cb .function (
238+ "post_matches_websearch" ,
239+ Boolean .class ,
240+ postTexts .get (PostText_ .searchTerms ),
241+ cb .literal (language ),
242+ cb .literal (searchQuery ))))
243+ .toArray (n -> new Predicate [n ]);
244+ conditions .add (cb .or (localizedSearches ));
239245 }
240246
241- cb = cb . where ( " post.scope" ). eq ( Scope .top_level );
247+ conditions . add ( cb . equal ( post .get ( Post_ . scope ), Scope .top_level ) );
242248
243- return cb ;
249+ query .where (conditions .toArray (new Predicate [0 ]));
250+
251+ return query ;
244252 }
245253
246254 public final boolean isVisibleTo (@ Nullable User user ) {
@@ -312,18 +320,13 @@ public List<Day<T>> days() {
312320 }
313321
314322 public static PostPage <Post <? extends PostText <?>>> findViewable (
315- PostFilter postFilter ,
316- EntityManager em ,
317- CriteriaBuilderFactory cbf ,
318- @ CheckForNull User viewer ,
319- @ CheckForNull User owner ) {
320- return findViewable (postFilter , em , cbf , viewer , owner , null , null , null );
323+ PostFilter postFilter , Session session , @ CheckForNull User viewer , @ CheckForNull User owner ) {
324+ return findViewable (postFilter , session , viewer , owner , null , null , null );
321325 }
322326
323327 public static PostPage <Post <? extends PostText <?>>> findViewable (
324328 PostFilter postFilter ,
325- EntityManager em ,
326- CriteriaBuilderFactory cbf ,
329+ Session session ,
327330 @ CheckForNull User viewer ,
328331 @ CheckForNull User owner ,
329332 @ CheckForNull Integer cursor ,
@@ -340,13 +343,12 @@ public static PostPage<Post<? extends PostText<?>>> findViewable(
340343 default :
341344 entityClass = Post .class ;
342345 }
343- return findViewable (entityClass , em , cbf , viewer , owner , cursor , count , searchQuery );
346+ return findViewable (entityClass , session , viewer , owner , cursor , count , searchQuery );
344347 }
345348
346349 protected static <T extends Post <? extends PostText <?>>> PostPage <T > findViewable (
347350 Class <? extends T > entityClass ,
348- EntityManager em ,
349- CriteriaBuilderFactory cbf ,
351+ Session session ,
350352 @ CheckForNull User viewer ,
351353 @ CheckForNull User owner ,
352354 @ CheckForNull Integer cursor ,
@@ -357,9 +359,10 @@ protected static <T extends Post<? extends PostText<?>>> PostPage<T> findViewabl
357359 Objects .requireNonNull (count );
358360 }
359361
360- var forwardCriteria =
361- queryViewable (entityClass , viewer , owner , cursor , em , cbf , true , searchQuery );
362- var forwardQuery = forwardCriteria .getQuery ();
362+ var cb = session .getCriteriaBuilder ();
363+
364+ var forwardCriteria = queryViewable (entityClass , viewer , owner , cursor , cb , true , searchQuery );
365+ var forwardQuery = session .createQuery (forwardCriteria );
363366
364367 if (count != null ) {
365368 forwardQuery .setMaxResults (count + 1 );
@@ -371,16 +374,16 @@ protected static <T extends Post<? extends PostText<?>>> PostPage<T> findViewabl
371374 if (cursor != null ) {
372375 // Look backwards as well so we can find the prevCursor.
373376 var backwardCriteria =
374- queryViewable (entityClass , viewer , owner , cursor , em , cbf , false , searchQuery );
375- var backwardQuery = backwardCriteria . getQuery ( );
377+ queryViewable (entityClass , viewer , owner , cursor , cb , false , searchQuery );
378+ var backwardQuery = session . createQuery ( backwardCriteria );
376379 backwardQuery .setMaxResults (count );
377380 var backwardResults = backwardQuery .getResultList ();
378381 if (!backwardResults .isEmpty ()) {
379382 prevCursor = backwardResults .get (backwardResults .size () - 1 ).id ;
380383 }
381384 }
382385
383- var forwardResults = new ArrayList <T >( forwardQuery .getResultList () );
386+ var forwardResults = ( List <T >) forwardQuery .getResultList ();
384387 if (count != null ) {
385388 if (forwardResults .size () == count + 1 ) {
386389 nextCursor = forwardResults .get (count ).id ;
0 commit comments