basic global search implementation
This commit is contained in:
+98
@@ -0,0 +1,98 @@
|
||||
package org.mifosplatform.portfolio.search;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class SearchConstants {
|
||||
|
||||
public static enum SEARCH_RESPONSE_PARAMETERS {
|
||||
ENTITY_ID("entityId"), ENTITY_ACCOUNT_NO("entityAccountNo"), ENTITY_EXTERNAL_ID("entityExternalId"), ENTITY_NAME("entityName"), ENTITY_TYPE(
|
||||
"entityType"), PARENT_ID("parentId"), PARENT_NAME("parentName");
|
||||
|
||||
private final String value;
|
||||
|
||||
private SEARCH_RESPONSE_PARAMETERS(final String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
private static final Set<String> values = new HashSet<String>();
|
||||
static {
|
||||
for (SEARCH_RESPONSE_PARAMETERS param : SEARCH_RESPONSE_PARAMETERS.values()) {
|
||||
values.add(param.value);
|
||||
}
|
||||
}
|
||||
|
||||
public static Set<String> getAllValues() {
|
||||
return values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name().toString().replaceAll("_", " ");
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
|
||||
public static enum SEARCH_SUPPORTED_PARAMETERS {
|
||||
QUERY("query"), RESOURCE("resource");
|
||||
|
||||
private final String value;
|
||||
|
||||
private SEARCH_SUPPORTED_PARAMETERS(final String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
private static final Set<String> values = new HashSet<String>();
|
||||
static {
|
||||
for (SEARCH_SUPPORTED_PARAMETERS param : SEARCH_SUPPORTED_PARAMETERS.values()) {
|
||||
values.add(param.value);
|
||||
}
|
||||
}
|
||||
|
||||
public static Set<String> getAllValues() {
|
||||
return values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name().toString().replaceAll("_", " ");
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
|
||||
public static enum SEARCH_SUPPORTED_RESOURCES {
|
||||
CLIENT("client"), GROUP("group"), LOAN("loan");
|
||||
|
||||
private final String value;
|
||||
|
||||
private SEARCH_SUPPORTED_RESOURCES(final String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
private static final Set<String> values = new HashSet<String>();
|
||||
static {
|
||||
for (SEARCH_SUPPORTED_RESOURCES param : SEARCH_SUPPORTED_RESOURCES.values()) {
|
||||
values.add(param.value);
|
||||
}
|
||||
}
|
||||
|
||||
public static Set<String> getAllValues() {
|
||||
return values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name().toString().replaceAll("_", " ");
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
package org.mifosplatform.portfolio.search.api;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper;
|
||||
import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
|
||||
import org.mifosplatform.infrastructure.core.serialization.ToApiJsonSerializer;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.portfolio.search.SearchConstants.SEARCH_RESPONSE_PARAMETERS;
|
||||
import org.mifosplatform.portfolio.search.data.SearchConditions;
|
||||
import org.mifosplatform.portfolio.search.data.SearchData;
|
||||
import org.mifosplatform.portfolio.search.service.SearchReadPlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Path("/search")
|
||||
@Component
|
||||
@Scope("singleton")
|
||||
public class SearchApiResource {
|
||||
|
||||
private final Set<String> searchResponseParameters = SEARCH_RESPONSE_PARAMETERS.getAllValues();
|
||||
|
||||
private final PlatformSecurityContext context;
|
||||
private final SearchReadPlatformService searchReadPlatformService;
|
||||
private final ToApiJsonSerializer<SearchData> toApiJsonSerializer;
|
||||
private final ApiRequestParameterHelper apiRequestParameterHelper;
|
||||
|
||||
@Autowired
|
||||
public SearchApiResource(final PlatformSecurityContext context, final SearchReadPlatformService searchReadPlatformService, final ToApiJsonSerializer<SearchData> toApiJsonSerializer, final ApiRequestParameterHelper apiRequestParameterHelper) {
|
||||
|
||||
this.context = context;
|
||||
this.searchReadPlatformService = searchReadPlatformService;
|
||||
this.toApiJsonSerializer = toApiJsonSerializer;
|
||||
this.apiRequestParameterHelper = apiRequestParameterHelper;
|
||||
|
||||
}
|
||||
|
||||
@GET
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String searchData(@Context final UriInfo uriInfo, @QueryParam("query") final String query, @QueryParam("resource") final String resource) {
|
||||
|
||||
// FIXME - Do we need to validate for permissions
|
||||
|
||||
SearchConditions searchConditions = new SearchConditions(query, resource);
|
||||
|
||||
final Collection<SearchData> searchResults = this.searchReadPlatformService.retriveMatchingData(searchConditions);
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
return this.toApiJsonSerializer.serialize(settings, searchResults, searchResponseParameters);
|
||||
}
|
||||
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
package org.mifosplatform.portfolio.search.data;
|
||||
|
||||
import org.mifosplatform.portfolio.search.SearchConstants.SEARCH_SUPPORTED_RESOURCES;
|
||||
|
||||
|
||||
public class SearchConditions {
|
||||
|
||||
private final String searchQuery;
|
||||
private final String searchResource;
|
||||
private final Boolean clientSearch;
|
||||
private final Boolean groupSearch;
|
||||
private final Boolean loanSeach;
|
||||
public SearchConditions(String searchQueryParam, String searchResource) {
|
||||
this.searchQuery = searchQueryParam;
|
||||
this.searchResource = searchResource;
|
||||
this.clientSearch = (null == searchResource || searchResource.toLowerCase().contains(SEARCH_SUPPORTED_RESOURCES.CLIENT.name().toLowerCase()))? true : false;
|
||||
this.groupSearch = (null == searchResource || searchResource.toLowerCase().contains(SEARCH_SUPPORTED_RESOURCES.GROUP.name().toLowerCase()))? true : false;
|
||||
this.loanSeach = (null == searchResource || searchResource.toLowerCase().contains(SEARCH_SUPPORTED_RESOURCES.LOAN.name().toLowerCase()))? true : false;
|
||||
}
|
||||
public SearchConditions(String searchQueryParam, String searchResource, Boolean clientSearch, Boolean groupSearch, Boolean loanSeach) {
|
||||
this.searchQuery = searchQueryParam;
|
||||
this.searchResource = searchResource;
|
||||
this.clientSearch = clientSearch;
|
||||
this.groupSearch = groupSearch;
|
||||
this.loanSeach = loanSeach;
|
||||
}
|
||||
|
||||
public String getSearchQuery() {
|
||||
return this.searchQuery;
|
||||
}
|
||||
|
||||
public String getSearchResource() {
|
||||
return this.searchResource;
|
||||
}
|
||||
|
||||
public Boolean isClientSearch() {
|
||||
return this.clientSearch;
|
||||
}
|
||||
|
||||
public Boolean isGroupSearch() {
|
||||
return this.groupSearch;
|
||||
}
|
||||
|
||||
public Boolean isLoanSeach() {
|
||||
return this.loanSeach;
|
||||
}
|
||||
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
package org.mifosplatform.portfolio.search.data;
|
||||
|
||||
|
||||
public class SearchData {
|
||||
|
||||
private final Long entityId;
|
||||
private final String entityAccountNo;
|
||||
private final String entityExternalId;
|
||||
private final String entityName;
|
||||
private final String entityType;
|
||||
private final Long parentId;
|
||||
private final String parentName;
|
||||
|
||||
public SearchData(Long entityId, String entityAccountNo, String entityExternalId, String entityName, String entityType, Long parentId, String parentName) {
|
||||
|
||||
this.entityId = entityId;
|
||||
this.entityAccountNo = entityAccountNo;
|
||||
this.entityExternalId = entityExternalId;
|
||||
this.entityName = entityName;
|
||||
this.entityType = entityType;
|
||||
this.parentId = parentId;
|
||||
this.parentName = parentName;
|
||||
}
|
||||
|
||||
|
||||
public Long getEntityId() {
|
||||
return this.entityId;
|
||||
}
|
||||
|
||||
|
||||
public String getEntityAccountNo() {
|
||||
return this.entityAccountNo;
|
||||
}
|
||||
|
||||
|
||||
public String getEntityExternalId() {
|
||||
return this.entityExternalId;
|
||||
}
|
||||
|
||||
|
||||
public String getEntityName() {
|
||||
return this.entityName;
|
||||
}
|
||||
|
||||
|
||||
public String getEntityType() {
|
||||
return this.entityType;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Long getParentId() {
|
||||
return this.parentId;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public String getParentName() {
|
||||
return this.parentName;
|
||||
}
|
||||
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package org.mifosplatform.portfolio.search.service;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.mifosplatform.portfolio.search.data.SearchConditions;
|
||||
import org.mifosplatform.portfolio.search.data.SearchData;
|
||||
|
||||
|
||||
public interface SearchReadPlatformService {
|
||||
Collection<SearchData> retriveMatchingData(SearchConditions searchConditions);
|
||||
}
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
package org.mifosplatform.portfolio.search.service;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
|
||||
import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.portfolio.search.data.SearchConditions;
|
||||
import org.mifosplatform.portfolio.search.data.SearchData;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class SearchReadPlatformServiceImpl implements SearchReadPlatformService {
|
||||
|
||||
private final NamedParameterJdbcTemplate namedParameterjdbcTemplate;
|
||||
private final PlatformSecurityContext context;
|
||||
|
||||
@Autowired
|
||||
public SearchReadPlatformServiceImpl(final PlatformSecurityContext context, final TenantAwareRoutingDataSource dataSource) {
|
||||
this.context = context;
|
||||
this.namedParameterjdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SearchData> retriveMatchingData(SearchConditions searchConditions) {
|
||||
AppUser currentUser = context.authenticatedUser();
|
||||
String hierarchy = currentUser.getOffice().getHierarchy();
|
||||
|
||||
SearchMapper rm = new SearchMapper();
|
||||
|
||||
MapSqlParameterSource params = new MapSqlParameterSource();
|
||||
params.addValue("hierarchy", hierarchy + "%");
|
||||
params.addValue("search", searchConditions.getSearchQuery());
|
||||
params.addValue("partialSearch", "%" + searchConditions.getSearchQuery() + "%");
|
||||
|
||||
return this.namedParameterjdbcTemplate.query(rm.searchSchema(searchConditions), params, rm);
|
||||
}
|
||||
|
||||
private static final class SearchMapper implements RowMapper<SearchData> {
|
||||
|
||||
public String searchSchema(SearchConditions searchConditions) {
|
||||
|
||||
String union = " union all ";
|
||||
String clientExactMatchSql = " (select 'CLIENT' as entityType, c.id as entityId, c.display_name as entityName, c.external_id as entityExternalId, c.account_no as entityAccountNo "
|
||||
+ " , c.office_id as parentId, o.name as parentName "
|
||||
+ " from m_client c join m_office o on o.id = c.office_id where o.hierarchy like :hierarchy and (c.account_no like :search or c.display_name like :search or c.external_id like :search)) ";
|
||||
|
||||
String clientMatchSql = " (select 'CLIENT' as entityType, c.id as entityId, c.display_name as entityName, c.external_id as entityExternalId, c.account_no as entityAccountNo "
|
||||
+ " , c.office_id as parentId, o.name as parentName "
|
||||
+ " from m_client c join m_office o on o.id = c.office_id where o.hierarchy like :hierarchy and (c.account_no like :partialSearch and c.account_no not like :search) or "
|
||||
+ "(c.display_name like :partialSearch and c.display_name not like :search) or "
|
||||
+ "(c.external_id like :partialSearch and c.external_id not like :search))";
|
||||
|
||||
String loanExactMatchSql = " (select 'LOAN' as entityType, l.id as entityId, l.account_no as entityName, l.external_id as entityExternalId, l.account_no as entityAccountNo "
|
||||
+ " , c.id as parentId, c.display_name as parentName "
|
||||
+ " from m_loan l join m_client c on l.client_id = c.id join m_office o on o.id = c.office_id where o.hierarchy like :hierarchy and l.account_no like :search) ";
|
||||
|
||||
String loanMatchSql = " (select 'LOAN' as entityType, l.id as entityId, l.account_no as entityName, l.external_id as entityExternalId, l.account_no as entityAccountNo "
|
||||
+ " , c.id as parentId, c.display_name as parentName "
|
||||
+ " from m_loan l join m_client c on l.client_id = c.id join m_office o on o.id = c.office_id where o.hierarchy like :hierarchy and l.account_no like :partialSearch and l.account_no not like :search) ";
|
||||
|
||||
String groupExactMatchSql = " (select 'GROUP' as entityType, g.id as entityId, g.name as entityName, g.external_id as entityExternalId, NULL as entityAccountNo "
|
||||
+ " , g.office_id as parentId, o.name as parentName "
|
||||
+ " from m_group g join m_office o on o.id = g.office_id where o.hierarchy like :hierarchy and g.name like :search) ";
|
||||
|
||||
String groupMatchSql = " (select 'GROUP' as entityType, g.id as entityId, g.name as entityName, g.external_id as entityExternalId, NULL as entityAccountNo "
|
||||
+ " , g.office_id as parentId, o.name as parentName "
|
||||
+ " from m_group g join m_office o on o.id = g.office_id where o.hierarchy like :hierarchy and g.name like :partialSearch and g.name not like :search) ";
|
||||
|
||||
StringBuffer sql = new StringBuffer();
|
||||
|
||||
// first include all exact matches
|
||||
if (searchConditions.isClientSearch()) {
|
||||
sql.append(clientExactMatchSql).append(union);
|
||||
}
|
||||
|
||||
if (searchConditions.isLoanSeach()) {
|
||||
sql.append(loanExactMatchSql).append(union);
|
||||
}
|
||||
|
||||
if (searchConditions.isGroupSearch()) {
|
||||
sql.append(groupExactMatchSql).append(union);
|
||||
}
|
||||
|
||||
// include all matching records
|
||||
if (searchConditions.isClientSearch()) {
|
||||
sql.append(clientMatchSql).append(union);
|
||||
}
|
||||
|
||||
if (searchConditions.isLoanSeach()) {
|
||||
sql.append(loanMatchSql).append(union);
|
||||
}
|
||||
|
||||
if (searchConditions.isGroupSearch()) {
|
||||
sql.append(groupMatchSql).append(union);
|
||||
}
|
||||
|
||||
sql.replace(sql.lastIndexOf(union), sql.length(), "");
|
||||
|
||||
// remove last occurrence of "union all" string
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SearchData mapRow(ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
||||
final Long entityId = JdbcSupport.getLong(rs, "entityId");
|
||||
final String entityAccountNo = rs.getString("entityAccountNo");
|
||||
final String entityExternalId = rs.getString("entityExternalId");
|
||||
final String entityName = rs.getString("entityName");
|
||||
final String entityType = rs.getString("entityType");
|
||||
final Long parentId = JdbcSupport.getLong(rs, "parentId");
|
||||
final String parentName = rs.getString("parentName");
|
||||
return new SearchData(entityId, entityAccountNo, entityExternalId, entityName, entityType, parentId, parentName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user