Package: JpaFinder
JpaFinder
name | instruction | branch | complexity | line | method | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
JpaFinder(Class, Function, TxManager) |
|
|
|
|
|
||||||||||||||||||||
count() |
|
|
|
|
|
||||||||||||||||||||
createQuery(EntityManager, Class, String) |
|
|
|
|
|
||||||||||||||||||||
from(int) |
|
|
|
|
|
||||||||||||||||||||
lambda$count$2(EntityManager) |
|
|
|
|
|
||||||||||||||||||||
lambda$createQuery$3(Pair, String) |
|
|
|
|
|
||||||||||||||||||||
lambda$createQuery$4(AtomicReference, Pair) |
|
|
|
|
|
||||||||||||||||||||
lambda$optionalFirstResult$0(EntityManager) |
|
|
|
|
|
||||||||||||||||||||
lambda$results$1(EntityManager) |
|
|
|
|
|
||||||||||||||||||||
max(int) |
|
|
|
|
|
||||||||||||||||||||
optionalFirstResult() |
|
|
|
|
|
||||||||||||||||||||
optionalResult() |
|
|
|
|
|
||||||||||||||||||||
results() |
|
|
|
|
|
||||||||||||||||||||
sort(Finder.SortCriterion, Finder.SortDirection) |
|
|
|
|
|
||||||||||||||||||||
static {...} |
|
|
|
|
|
Coverage
1: /*
2: * *************************************************************************************************************************************************************
3: *
4: * TheseFoolishThings: Miscellaneous utilities
5: * http://tidalwave.it/projects/thesefoolishthings
6: *
7: * Copyright (C) 2009 - 2025 by Tidalwave s.a.s. (http://tidalwave.it)
8: *
9: * *************************************************************************************************************************************************************
10: *
11: * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
12: * You may obtain a copy of the License at
13: *
14: * http://www.apache.org/licenses/LICENSE-2.0
15: *
16: * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
17: * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
18: *
19: * *************************************************************************************************************************************************************
20: *
21: * git clone https://bitbucket.org/tidalwave/thesefoolishthings-src
22: * git clone https://github.com/tidalwave-it/thesefoolishthings-src
23: *
24: * *************************************************************************************************************************************************************
25: */
26: package it.tidalwave.thesefoolishthings.examples.jpafinderexample.impl;
27:
28: import javax.annotation.Nonnegative;
29: import javax.annotation.Nonnull;
30: import java.util.ArrayList;
31: import java.util.List;
32: import java.util.Optional;
33: import java.util.concurrent.atomic.AtomicReference;
34: import java.util.function.Function;
35: import java.util.stream.Collectors;
36: import jakarta.persistence.EntityManager;
37: import jakarta.persistence.TypedQuery;
38: import it.tidalwave.util.Finder;
39: import it.tidalwave.util.Pair;
40: import it.tidalwave.thesefoolishthings.examples.jpafinderexample.TxManager;
41: import lombok.AccessLevel;
42: import lombok.AllArgsConstructor;
43: import lombok.RequiredArgsConstructor;
44: import lombok.extern.slf4j.Slf4j;
45: import static it.tidalwave.util.CollectionUtils.concat;
46:
47: /***************************************************************************************************************************************************************
48: *
49: * @author Fabrizio Giudici
50: *
51: **************************************************************************************************************************************************************/
52: // START SNIPPET: JPAExampleFinder
53: @AllArgsConstructor(access = AccessLevel.PRIVATE) @Slf4j
54: public class JpaFinder<T, E> implements Finder<T>
55: {
56: // START SNIPPET: sort-criterion
57: @RequiredArgsConstructor
58: static final class JpaqlSortCriterion implements SortCriterion
59: {
60: @Nonnull
61: private final String field;
62:
63: @Nonnull
64: public String processSql (@Nonnull final String jpaql, @Nonnull final SortDirection sortDirection)
65: {
66: final var orderBy = jpaql.contains("ORDER BY") ? ", " : " ORDER BY ";
67: return jpaql + orderBy + field + ((sortDirection == SortDirection.DESCENDING) ? " DESC" : "");
68: }
69: }
70:
71: public static final SortCriterion BY_FIRST_NAME = new JpaqlSortCriterion("p.firstName");
72: public static final SortCriterion BY_LAST_NAME = new JpaqlSortCriterion("p.lastName");
73: // END SNIPPET: sort-criterion
74:
75: // START SNIPPET: fields
76: @Nonnull
77: private final Class<E> entityClass;
78:
79: @Nonnull
80: private final Function<E, T> fromEntity;
81:
82: @Nonnull
83: private final TxManager txManager;
84:
85: @Nonnegative
86: private final int firstResult;
87:
88: @Nonnegative
89: private final int maxResults;
90:
91: @Nonnull
92: private final List<Pair<JpaqlSortCriterion, SortDirection>> sortCriteria;
93: // END SNIPPET: fields
94:
95: public JpaFinder (@Nonnull final Class<E> entityClass,
96: @Nonnull final Function<E, T> fromEntity,
97: @Nonnull final TxManager txManager)
98: {
99: this(entityClass, fromEntity, txManager, 0, Integer.MAX_VALUE, new ArrayList<>());
100: }
101:
102: // START SNIPPET: intermediate-methods
103: @Override @Nonnull
104: public Finder<T> from (@Nonnegative final int firstResult)
105: {
106: return new JpaFinder<>(entityClass, fromEntity, txManager, firstResult, maxResults, sortCriteria);
107: }
108:
109: @Override @Nonnull
110: public Finder<T> max (@Nonnegative final int maxResults)
111: {
112: return new JpaFinder<>(entityClass, fromEntity, txManager, firstResult, maxResults, sortCriteria);
113: }
114: // END SNIPPET: intermediate-methods
115:
116: // START SNIPPET: sort-method
117: @Override @Nonnull
118: public Finder<T> sort (@Nonnull final SortCriterion criterion, @Nonnull final SortDirection direction)
119: {
120:• if (!(criterion instanceof JpaqlSortCriterion))
121: {
122: throw new IllegalArgumentException("Can't sort by " + criterion);
123: }
124:
125: return new JpaFinder<>(entityClass,
126: fromEntity,
127: txManager,
128: firstResult,
129: maxResults,
130: concat(sortCriteria, Pair.of((JpaqlSortCriterion)criterion, direction)));
131: }
132: // END SNIPPET: sort-method
133:
134: // START SNIPPET: termination-methods
135: @Override @Nonnull
136: public Optional<T> optionalResult()
137: {
138: final var results = results();
139:
140:• if (results.size() > 1)
141: {
142: throw new RuntimeException("More than a single result");
143: }
144:
145: return results.stream().findFirst();
146: }
147:
148: @Override @Nonnull
149: public Optional<T> optionalFirstResult()
150: {
151: // Warning: the stream must be consumed *within* runInTx2()
152: return txManager.computeInTx(em -> createQuery(em, entityClass, "SELECT p")
153: .getResultStream()
154: .findFirst()
155: .map(fromEntity));
156: }
157:
158: @Override @Nonnull
159: public List<T> results()
160: {
161: // Warning: the stream must be consumed *within* runInTx2()
162: return txManager.computeInTx(em -> createQuery(em, entityClass, "SELECT p")
163: .getResultStream()
164: .map(fromEntity)
165: .collect(Collectors.toList()));
166: }
167:
168: @Override @Nonnegative
169: public int count()
170: {
171: return txManager.computeInTx(em -> createQuery(em, Long.class, "SELECT COUNT(p)").getSingleResult()).intValue();
172: }
173: // END SNIPPET: termination-methods
174:
175: // START SNIPPET: createQueryFull
176: @Nonnull
177: private <R> TypedQuery<R> createQuery (@Nonnull final EntityManager em,
178: @Nonnull final Class<R> resultType,
179: @Nonnull final String jpaqlPrefix)
180: {
181: final var buffer = new AtomicReference<>(jpaqlPrefix + " FROM " + entityClass.getSimpleName() + " p");
182: sortCriteria.forEach(p -> buffer.updateAndGet(prev -> p.a.processSql(prev, p.b)));
183: final var jpaql = buffer.get();
184: log.info(">>>> {}", jpaql);
185: // START SNIPPET: createQuery
186: return em.createQuery(jpaql, resultType).setFirstResult(firstResult).setMaxResults(maxResults);
187: // END SNIPPET: createQuery
188: }
189: // END SNIPPET: createQueryFull
190: }
191: // END SNIPPET: JPAExampleFinder