Skip to content

Commit 9cb42d0

Browse files
committed
impl repo layer for search
add classes need for new search platform also implement basic feature in repository layer and add test method for that.
1 parent a4d6140 commit 9cb42d0

21 files changed

Lines changed: 359 additions & 27 deletions

src/main/java/ir/bigz/springbootreal/commons/util/Utils.java

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
package ir.bigz.springbootreal.commons.util;
22

3+
import ir.bigz.springbootreal.dto.ValueCondition;
4+
35
import java.sql.Timestamp;
46
import java.time.LocalDateTime;
57
import java.time.ZoneId;
68
import java.time.ZonedDateTime;
79
import java.time.format.DateTimeFormatter;
10+
import java.util.Arrays;
11+
import java.util.Map;
12+
13+
import static ir.bigz.springbootreal.dto.ValueCondition.*;
814

915
public class Utils {
1016

@@ -32,4 +38,72 @@ public static Timestamp convertTimeString(String time){
3238
LocalDateTime from = LocalDateTime.from(SIMPLE_FORMATTER.parse(time));
3339
return Timestamp.valueOf(from);
3440
}
41+
public static boolean isNotNull(String s) {
42+
return !isNull(s);
43+
}
44+
45+
public static boolean isNull(String s) {
46+
return s == null || s.equals("") || s.toLowerCase().equals("null");
47+
}
48+
49+
public static boolean isNotNull(Object obj) {
50+
return !isNull(obj);
51+
}
52+
53+
public static boolean isNull(Object obj) {
54+
if (obj == null)
55+
return true;
56+
String str = obj.toString();
57+
return isNull(str);
58+
}
59+
60+
public static boolean isEqual(String s1, String s2) {
61+
return (!isNull(s1) && !isNull(s2) && s1.equals(s2));
62+
}
63+
64+
65+
@SuppressWarnings("unchecked")
66+
public static <T> T getQueryString(Map<String, String> queryString,
67+
String key,
68+
ValueCondition condition,
69+
T defaultValue,
70+
Class<T> type){
71+
72+
if(queryString == null){
73+
return null;
74+
}
75+
76+
String value = queryString.get(key);
77+
T returnValue = null;
78+
if(type.equals(String.class)){
79+
returnValue = (T)"";
80+
}
81+
82+
if(value != null){
83+
if(condition == EQUAL){
84+
if (type.equals(Integer.class))
85+
returnValue = (T) Integer.valueOf(value);
86+
if (type.equals(Double.class))
87+
returnValue = (T) Double.valueOf(value);
88+
if (type.equals(Long.class))
89+
returnValue = (T) Long.valueOf(value);
90+
if (type.equals(Boolean.class))
91+
returnValue = (T) Boolean.valueOf(value);
92+
if (type.equals(String.class)){
93+
returnValue = (T) value;
94+
}
95+
}
96+
else if (condition == CONTAINS) returnValue = (T) ("%" + value + "%");
97+
else if (condition == STARTS_WITH) returnValue = (T) (value + "%");
98+
else if (condition == ENDS_WITH) returnValue = (T) ("%" + value);
99+
else if (condition == IN){
100+
String[] array = value.split(",");
101+
returnValue = (T) Arrays.asList(array);
102+
}
103+
}else if(isNotNull(defaultValue)){
104+
returnValue = defaultValue;
105+
}
106+
107+
return returnValue;
108+
}
35109
}

src/main/java/ir/bigz/springbootreal/configuration/DataSourceConfiguration.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public DataSourceConfiguration(@Qualifier("HikariDataSourceInit") DataSource dat
3030
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
3131
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
3232
factory.setDataSource(dataSource);
33-
factory.setPackagesToScan(new String[]{"ir.bigz.springbootreal.dao"});
33+
factory.setPackagesToScan(new String[]{env.getProperty("demo.enity.packageScan")});
3434
factory.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
3535

3636
Properties jpaProperties = new Properties();

src/main/java/ir/bigz/springbootreal/configuration/HikariDataSourceInit.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.zaxxer.hikari.HikariConfig;
44
import com.zaxxer.hikari.HikariDataSource;
55
import org.springframework.beans.factory.annotation.Autowired;
6+
import org.springframework.boot.jdbc.DataSourceBuilder;
67
import org.springframework.context.annotation.Bean;
78
import org.springframework.context.annotation.Configuration;
89
import org.springframework.core.env.Environment;
@@ -13,8 +14,12 @@
1314
/**
1415
* {@link HikariDataSourceInit} use for build connection-pool base on HikariCp with customize properties,
1516
* and then added to {@link DataSourceConfiguration} class as datasource for use in app.
17+
* also if you want use for production un comment line 30 and comment line 31 and 32
18+
* and if you want test with testContainer uncomment line 31 and 32 and comment line 30
1619
*/
1720

21+
//todo i must be find better solution for use hikariDataSource between production and test with testContainer
22+
1823
@Configuration
1924
public class HikariDataSourceInit{
2025

@@ -23,7 +28,9 @@ public class HikariDataSourceInit{
2328

2429
@Bean(name = "HikariDataSourceInit")
2530
public DataSource dataSource(){
26-
HikariConfig hikariConfig = new HikariConfig(hikariProperties());
31+
// HikariConfig hikariConfig = new HikariConfig(hikariProperties()); // use for production
32+
HikariConfig hikariConfig = new HikariConfig();
33+
hikariConfig.setDataSource(InitDataSource());
2734
int cpuCores = Runtime.getRuntime().availableProcessors();
2835
hikariConfig.setMaximumPoolSize(cpuCores * 4);
2936
hikariConfig.setConnectionTimeout(Long.parseLong(env.getProperty("hikari.connectionTimeout")));
@@ -32,6 +39,15 @@ public DataSource dataSource(){
3239
return new HikariDataSource(hikariConfig);
3340
}
3441

42+
protected DataSource InitDataSource(){
43+
return DataSourceBuilder.create()
44+
.driverClassName(env.getProperty("demo.datasource.driver-class-name"))
45+
.url(env.getProperty("demo.datasource.url"))
46+
.username(env.getProperty("demo.datasource.username"))
47+
.password(env.getProperty("demo.datasource.password"))
48+
.build();
49+
}
50+
3551
protected Properties hikariProperties(){
3652
Properties hikariProps = new Properties();
3753
hikariProps.setProperty("dataSourceClassName", env.getProperty("hikari.dataSourceClassName"));

src/main/java/ir/bigz/springbootreal/dal/DaoRepository.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package ir.bigz.springbootreal.dal;
22

3+
import ir.bigz.springbootreal.dto.PageResult;
4+
import ir.bigz.springbootreal.dto.PagedQuery;
35
import org.springframework.data.domain.Page;
46
import org.springframework.data.domain.Pageable;
57
import org.springframework.data.domain.Sort;
@@ -8,6 +10,7 @@
810
import java.io.Serializable;
911
import javax.persistence.criteria.CriteriaQuery;
1012
import java.util.List;
13+
import java.util.Map;
1114
import java.util.Optional;
1215
import java.util.stream.Stream;
1316

@@ -27,6 +30,8 @@ public interface DaoRepository<T, K extends Serializable> {
2730
<S extends T> List<S> find(List<K> entityIds);
2831
<S extends T> List<S> find(String entityName);
2932
List<T> genericSearch(String query);
33+
List<T> nativeQuery(String query, Map<String, Object> parameters);
34+
PageResult<T> pageCreateQuery(String nativeQuery, PagedQuery pagedQuery, Map<String, Object> parameterMap);
3035
void flush();
3136
void clear();
3237

src/main/java/ir/bigz/springbootreal/dal/DaoRepositoryImpl.java

Lines changed: 102 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
package ir.bigz.springbootreal.dal;
2+
import ir.bigz.springbootreal.dto.PageResult;
3+
import ir.bigz.springbootreal.dto.PagedQuery;
24
import org.hibernate.Session;
35
import org.hibernate.jpa.QueryHints;
46
import org.springframework.data.domain.Page;
@@ -14,12 +16,11 @@
1416
import javax.persistence.*;
1517
import javax.persistence.criteria.*;
1618
import java.io.Serializable;
19+
import java.lang.reflect.Field;
1720
import java.lang.reflect.ParameterizedType;
1821
import java.lang.reflect.Type;
19-
import java.util.ArrayList;
20-
import java.util.Iterator;
21-
import java.util.List;
22-
import java.util.Optional;
22+
import java.text.MessageFormat;
23+
import java.util.*;
2324
import java.util.stream.Stream;
2425

2526
@Component
@@ -32,6 +33,8 @@ public abstract class DaoRepositoryImpl<T, K extends Serializable> implements Da
3233

3334
protected CriteriaBuilder criteriaBuilder;
3435

36+
private static int maxPageSize = 1000;
37+
3538
@SuppressWarnings("unchecked")
3639
protected DaoRepositoryImpl() {
3740
Type t = getClass().getGenericSuperclass();
@@ -124,6 +127,80 @@ public List<T> genericSearch(String query) {
124127
return entityManager.createQuery(query, daoType).getResultList();
125128
}
126129

130+
@Override
131+
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
132+
public List<T> nativeQuery(String query, Map<String, Object> parameters) {
133+
134+
Query nativeQuery = entityManager.createNativeQuery(query, daoType);
135+
parameters.keySet().forEach(s -> nativeQuery.setParameter(s, parameters.get(s)));
136+
return nativeQuery.getResultList();
137+
}
138+
139+
@Override
140+
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
141+
public PageResult<T> pageCreateQuery(String nativeQuery, PagedQuery pagedQuery, Map<String, Object> parameterMap) {
142+
143+
StringBuffer orderString = new StringBuffer();
144+
String queryString = nativeQuery;
145+
pagedQuery.getOrdering().forEach(
146+
orderParam -> {
147+
try {
148+
orderParam = orderParam.trim();
149+
String[] orderField = orderParam.split("_");
150+
Field field = getDeclaredField(daoType, orderField[0]);
151+
if(field == null){
152+
System.out.println("wrong ordering field = " + orderParam);
153+
return;
154+
}
155+
String orderColumn = field.getName().replaceAll("([A-Z])", "_$1").toLowerCase();
156+
if (orderString.length() > 0) {
157+
orderString.append(", ");
158+
}
159+
String order = PagedQuery.ORDER_ASC;
160+
if (orderField.length > 1 && orderField[1].equalsIgnoreCase(PagedQuery.ORDER_DESC)) {
161+
order = PagedQuery.ORDER_DESC;
162+
}
163+
orderString.append(orderColumn + " " + order);
164+
}catch (Exception e){
165+
System.out.println("wrong ordering field = " + orderParam);
166+
}
167+
}
168+
);
169+
170+
if (orderString.length() > 0) {
171+
queryString = "SELECT * FROM (" + removeDefaultOrderBy(queryString) + ") as q ORDER BY " + orderString;
172+
}
173+
174+
Query query = entityManager.createNativeQuery(queryString, daoType);
175+
parameterMap.keySet().forEach(s -> query.setParameter(s, parameterMap.get(s)));
176+
177+
//todo paginationWindow must be improve
178+
if (pagedQuery.getPageSize() > 0 && pagedQuery.getPageSize() < maxPageSize && pagedQuery.getPageNumber() > 0) {
179+
int start = ((pagedQuery.getPageNumber() - 1) * pagedQuery.getPageSize());
180+
int end = (pagedQuery.getPageNumber() * pagedQuery.getPageSize());
181+
182+
// queryString = MessageFormat.format(
183+
// "SELECT * FROM ( " +
184+
// " SELECT q.*, rownum r_ FROM ({0}) q " +
185+
// " WHERE rownum < {1,number,#}) " +
186+
// "WHERE r_ >= {2,number,#} ", queryString, end, start);
187+
188+
query.setFirstResult(start);
189+
query.setMaxResults(end);
190+
}
191+
192+
List<T> resultQuery = query.getResultList();
193+
194+
PageResult<T> pagedResult = new PageResult<T>(
195+
resultQuery
196+
, (pagedQuery.getPageSize() > -1 ? pagedQuery.getPageSize() : resultQuery.size())
197+
, pagedQuery.getPageNumber()
198+
, pagedQuery.getOffset()
199+
, resultQuery.size()
200+
);
201+
return pagedResult;
202+
}
203+
127204
@Override
128205
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
129206
public void flush() {
@@ -240,4 +317,25 @@ protected List<Order> orderByClauseBuilder(Root<T> root, Sort sort){
240317
}
241318
return orders;
242319
}
320+
321+
protected Field getDeclaredField(Class className, String fieldName) {
322+
Field field = null;
323+
while (className != null && field == null) {
324+
try {
325+
field = className.getDeclaredField(fieldName);
326+
} catch (NoSuchFieldException ex) {
327+
}
328+
className = className.getSuperclass();
329+
}
330+
return field;
331+
}
332+
333+
protected static String removeDefaultOrderBy(String query) {
334+
int defaultOrderIndex = query.toLowerCase().lastIndexOf("order by");
335+
int lastParenthesisIndex = query.lastIndexOf(")");
336+
if (defaultOrderIndex > 0 && defaultOrderIndex > lastParenthesisIndex) {
337+
return query.substring(0, defaultOrderIndex);
338+
}
339+
return query;
340+
}
243341
}

src/main/java/ir/bigz/springbootreal/dal/UserRepository.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package ir.bigz.springbootreal.dal;
22

3-
import ir.bigz.springbootreal.dto.User;
3+
import ir.bigz.springbootreal.dto.entity.User;
44
import ir.bigz.springbootreal.viewmodel.search.UserSearchDto;
55
import org.springframework.data.domain.Page;
66
import org.springframework.data.domain.Pageable;

src/main/java/ir/bigz/springbootreal/dal/UserRepositoryImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package ir.bigz.springbootreal.dal;
22

33
import com.fasterxml.jackson.databind.ObjectMapper;
4-
import ir.bigz.springbootreal.dto.User;
4+
import ir.bigz.springbootreal.dto.entity.User;
55
import ir.bigz.springbootreal.viewmodel.search.UserSearchDto;
66
import org.springframework.data.domain.Page;
77
import org.springframework.data.domain.Pageable;

src/main/java/ir/bigz/springbootreal/datagenerator/DataGenerator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import com.github.javafaker.Faker;
44
import ir.bigz.springbootreal.dal.UserRepository;
5-
import ir.bigz.springbootreal.dto.User;
5+
import ir.bigz.springbootreal.dto.entity.User;
66
import org.springframework.boot.CommandLineRunner;
77
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
88
import org.springframework.stereotype.Component;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package ir.bigz.springbootreal.dto;
2+
3+
import lombok.Getter;
4+
5+
import java.util.List;
6+
7+
@Getter
8+
public class PageResult<T> {
9+
10+
private final List<T> result;
11+
private final int pageSize;
12+
private final int pageNumber;
13+
private final int offset;
14+
private final long total;
15+
16+
public PageResult(List<T> result, int pageSize, int pageNumber, int offset, long total) {
17+
this.result = result;
18+
this.pageSize = pageSize;
19+
this.pageNumber = pageNumber;
20+
this.offset = offset;
21+
this.total = total;
22+
}
23+
}

0 commit comments

Comments
 (0)