package com.nooul.apihelpers.springbootrest.services; import com.google.common.base.CaseFormat; import com.nooul.apihelpers.springbootrest.entities.QueryParamWrapper; import com.nooul.apihelpers.springbootrest.repositories.BaseRepository; import com.nooul.apihelpers.springbootrest.specifications.CustomSpecifications; import org.json.JSONArray; import org.json.JSONObject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.env.Environment; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Service; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Set; @Service //from: https://github.com/zifnab87/spring-boot-rest-api-helpers/blob/master/src/main/java/springboot/rest/services/FilterService.java public class FilterService<T, I extends Serializable> { @Autowired private Environment env; @Autowired private CustomSpecifications<T> specifications; public long countBy(QueryParamWrapper queryParamWrapper, BaseRepository<T, I> repo) { JSONObject filter = queryParamWrapper.getFilter(); JSONArray filterOr = queryParamWrapper.getFilterOr(); String usesSnakeCase = env.getProperty("spring-boot-rest-api-helpers.use-snake-case"); if (filter != null && filter.length() > 0) { HashMap<String, Object> map = (HashMap<String, Object>) filter.toMap(); if (usesSnakeCase != null && usesSnakeCase.equals("true")) { map = convertToCamelCase(map); } return repo.count( specifications.customSpecificationBuilder(map)); } else if (filterOr != null && filterOr.length() > 0) { return repo.count((Specification<T>) (root, query, builder) -> { List list = filterOr.toList(); if (usesSnakeCase != null && usesSnakeCase.equals("true")) { //map = convertToCamelCase(map); TODO for list } return specifications.customSpecificationBuilder(builder, query, root, list); }); } else { return repo.count(); } } public Page<T> filterBy(QueryParamWrapper queryParamWrapper, BaseRepository<T, I> repo) { return filterByHelper(repo, specifications, queryParamWrapper, "id", new ArrayList<>()); } public Page<T> filterBy(QueryParamWrapper queryParamWrapper, BaseRepository<T, I> repo, String primaryKeyName) { return filterByHelper(repo, specifications, queryParamWrapper, primaryKeyName, new ArrayList<>()); } public Page<T> filterBy(QueryParamWrapper queryParamWrapper, BaseRepository<T, I> repo, String primaryKeyName, List<String> searchOnlyInFields) { return filterByHelper(repo, specifications, queryParamWrapper, primaryKeyName, searchOnlyInFields); } public Page<T> filterBy(QueryParamWrapper queryParamWrapper, BaseRepository<T, I> repo, List<String> searchOnlyInFields) { return filterByHelper(repo, specifications, queryParamWrapper, "id", searchOnlyInFields); } private List<Sort.Order> sortHelper(JSONArray sort, String primaryKeyName) { List<Sort.Order> sortOrders = new ArrayList<>(); String usesSnakeCase = env.getProperty("spring-boot-rest-api-helpers.use-snake-case"); if (sort.length() % 2 != 0) { throw new IllegalArgumentException("sort should have even length given as array e.g ['name', 'ASC', 'birthDate', 'DESC']"); } for (int i = 0; i < sort.length(); i = i + 2) { String sortBy; if (usesSnakeCase != null && usesSnakeCase.equals("true")) { sortBy = convertToCamelCase((String) sort.get(i)); } else { sortBy = (String) sort.get(i); } sortOrders.add(new Sort.Order(Sort.Direction.valueOf((String) sort.get(i + 1)), sortBy)); } if (sortOrders.isEmpty()) { sortOrders.add(new Sort.Order(Sort.Direction.ASC, primaryKeyName)); } return sortOrders; } private <T> Page<T> filterByHelper(BaseRepository<T, I> repo, CustomSpecifications<T> specifications, QueryParamWrapper queryParamWrapper, String primaryKeyName, List<String> searchOnlyInFields) { String usesSnakeCase = env.getProperty("spring-boot-rest-api-helpers.use-snake-case"); Sort sortObj; JSONObject filter = queryParamWrapper.getFilter(); JSONArray filterOr = queryParamWrapper.getFilterOr(); JSONArray range = queryParamWrapper.getRange(); JSONArray sort = queryParamWrapper.getSort(); int page = 0; int size = Integer.MAX_VALUE; if (range.length() == 2) { page = (Integer) range.get(0); size = (Integer) range.get(1); } sortObj = Sort.by(sortHelper(sort, primaryKeyName)); Page result; if (filter != null && filter.length() > 0) { result = repo.findAll( (Specification<T>) (root, query, builder) -> { HashMap<String, Object> map = (HashMap<String, Object>) filter.toMap(); if (usesSnakeCase != null && usesSnakeCase.equals("true")) { map = convertToCamelCase(map); } return specifications.customSpecificationBuilder(builder, query, root, map, searchOnlyInFields ); }, PageRequest.of(page, size, sortObj)); } else if (filterOr != null && filterOr.length() > 0) { result = repo.findAll( (Specification<T>) (root, query, builder) -> { List list = filterOr.toList(); if (usesSnakeCase != null && usesSnakeCase.equals("true")) { //map = convertToCamelCase(map); TODO for list } return specifications.customSpecificationBuilder(builder, query, root, list); } , PageRequest.of(page, size, sortObj)); } else { result = repo.findAll(PageRequest.of(page, size, sortObj)); } return result; } private HashMap<String, Object> convertToCamelCase(HashMap<String, Object> snakeCaseMap) { Set<String> keys = snakeCaseMap.keySet(); HashMap<String, Object> camelCaseMap = new HashMap<>(snakeCaseMap); for (String key : keys) { Object val = snakeCaseMap.get(key); camelCaseMap.put(convertToCamelCase(key), val); } return camelCaseMap; } private String convertToCamelCase(String snakeCaseStr) { return CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, snakeCaseStr); } }