package com.constellio.model.services.search.query.logical; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; import com.constellio.data.utils.KeySetMap; import com.constellio.model.entities.records.wrappers.User; import com.constellio.model.entities.schemas.DataStoreField; import com.constellio.model.entities.schemas.MetadataSchema; import com.constellio.model.entities.schemas.MetadataValueType; import com.constellio.model.entities.security.Role; import com.constellio.model.services.search.StatusFilter; import com.constellio.model.services.search.entities.SearchBoost; import com.constellio.model.services.search.query.FilterUtils; import com.constellio.model.services.search.query.ResultsProjection; import com.constellio.model.services.search.query.ReturnedMetadatasFilter; import com.constellio.model.services.search.query.SearchQuery; import com.constellio.model.services.search.query.logical.condition.LogicalSearchCondition; import com.constellio.model.services.search.query.logical.condition.SchemaFilters; import com.constellio.model.services.search.query.logical.condition.SolrQueryBuilderParams; //TODO Remove inheritance, rename to LogicalQuery public class LogicalSearchQuery implements SearchQuery { private static final String HIGHLIGHTING_FIELDS = "search_*"; //This condition will be inserted in Filter Query LogicalSearchCondition condition; //This condition will be inserted in Query private LogicalSearchCondition queryCondition; private LogicalSearchQueryFacetFilters facetFilters = new LogicalSearchQueryFacetFilters(); private String freeTextQuery; UserFilter userFilter; String filterStatus; private int numberOfRows; private int startRow; private ReturnedMetadatasFilter returnedMetadatasFilter; private List<LogicalSearchQuerySort> sortFields = new ArrayList<>(); private ResultsProjection resultsProjection; private KeySetMap<String, String> queryFacets = new KeySetMap<>(); private List<String> fieldFacets = new ArrayList<>(); private List<String> statisticFields = new ArrayList<>(); private List<String> moreLikeThisFields = new ArrayList<>(); private int fieldFacetLimit; private boolean highlighting = false; private boolean spellcheck = false; private boolean moreLikeThis = false; private boolean preferAnalyzedFields = false; private List<SearchBoost> fieldBoosts = new ArrayList<>(); private List<SearchBoost> queryBoosts = new ArrayList<>(); private Map<String, String[]> overridedQueryParams = new HashMap<>(); public LogicalSearchQuery() { numberOfRows = 100000; startRow = 0; fieldFacetLimit = 0; } public LogicalSearchQuery(LogicalSearchCondition condition) { this(); if (condition == null) { throw new IllegalArgumentException("Condition must not be null"); } this.condition = condition; } public LogicalSearchQuery(LogicalSearchQuery query) { condition = query.condition; queryCondition = query.queryCondition; facetFilters = new LogicalSearchQueryFacetFilters(query.facetFilters); freeTextQuery = query.freeTextQuery; userFilter = query.userFilter; filterStatus = query.filterStatus; numberOfRows = query.numberOfRows; startRow = query.startRow; returnedMetadatasFilter = query.returnedMetadatasFilter; sortFields = new ArrayList<>(query.sortFields); resultsProjection = query.resultsProjection; queryFacets = new KeySetMap<>(query.queryFacets); fieldFacets = new ArrayList<>(query.fieldFacets); statisticFields = new ArrayList<>(query.statisticFields); fieldFacetLimit = query.fieldFacetLimit; highlighting = query.highlighting; spellcheck = query.spellcheck; preferAnalyzedFields = query.preferAnalyzedFields; fieldBoosts = new ArrayList<>(query.fieldBoosts); queryBoosts = new ArrayList<>(query.queryBoosts); } // The following methods are attribute accessors public boolean isPreferAnalyzedFields() { return preferAnalyzedFields; } public LogicalSearchQuery setPreferAnalyzedFields(boolean preferAnalyzedFields) { this.preferAnalyzedFields = preferAnalyzedFields; return this; } public LogicalSearchCondition getCondition() { return condition; } public LogicalSearchQuery setCondition(LogicalSearchCondition condition) { this.condition = condition; return this; } public String getFreeTextQuery() { return freeTextQuery; } public LogicalSearchQuery setFreeTextQuery(String freeTextQuery) { this.freeTextQuery = freeTextQuery; return this; } @Override public LogicalSearchQuery filteredWithUser(User user) { return filteredWithUser(user, Role.READ); } @Override public LogicalSearchQuery filteredWithUser(User user, String accessOrPermission) { if (user == null) { throw new IllegalArgumentException("user required"); } if (accessOrPermission == null) { throw new IllegalArgumentException("access/permission required"); } userFilter = new UserFilter(user, accessOrPermission); return this; } public LogicalSearchQuery filteredWithUserWrite(User user) { return filteredWithUser(user, Role.WRITE); } public LogicalSearchQuery filteredWithUserDelete(User user) { return filteredWithUser(user, Role.DELETE); } public UserFilter getUserFilter() { return userFilter; } public LogicalSearchQuery filteredByStatus(StatusFilter status) { filterStatus = FilterUtils.statusFilter(status); return this; } @Override public LogicalSearchQuery computeStatsOnField(DataStoreField field) { this.statisticFields.add(field.getDataStoreCode()); return this; } @Override public int getStartRow() { return this.startRow; } @Override public LogicalSearchQuery setStartRow(int row) { startRow = row; return this; } @Override public int getNumberOfRows() { return numberOfRows; } @Override public LogicalSearchQuery setNumberOfRows(int number) { numberOfRows = number; return this; } public ReturnedMetadatasFilter getReturnedMetadatas() { return returnedMetadatasFilter == null ? ReturnedMetadatasFilter.all() : returnedMetadatasFilter; } public LogicalSearchQuery setReturnedMetadatas(ReturnedMetadatasFilter filter) { this.returnedMetadatasFilter = filter; return this; } public void clearSort() { sortFields.clear(); } public LogicalSearchQuery sortAsc(DataStoreField field) { if (!field.isMultivalue() && field.getType() != MetadataValueType.TEXT) { DataStoreField sortField = field.getSortField(); if (sortField != null) { sortFields.add(new LogicalSearchQuerySort(sortField.getDataStoreCode(), true)); } sortFields.add(new LogicalSearchQuerySort(field.getDataStoreCode(), true)); } return this; } public LogicalSearchQuery sortDesc(DataStoreField field) { if (!field.isMultivalue() && field.getType() != MetadataValueType.TEXT) { DataStoreField sortField = field.getSortField(); if (sortField != null) { sortFields.add(new LogicalSearchQuerySort(sortField.getDataStoreCode(), false)); } sortFields.add(new LogicalSearchQuerySort(field.getDataStoreCode(), false)); } return this; } public ResultsProjection getResultsProjection() { return resultsProjection; } public LogicalSearchQuery setResultsProjection(ResultsProjection resultsProjection) { this.resultsProjection = resultsProjection; return this; } public KeySetMap<String, String> getQueryFacets() { return queryFacets; } public LogicalSearchQuery addQueryFacets(String facetGroup, List<String> queryFacets) { for (String queryFacet : queryFacets) { this.queryFacets.add(facetGroup, queryFacet); } return this; } public LogicalSearchQuery addQueryFacet(String facetGroup, String queryFacet) { queryFacets.add(facetGroup, queryFacet); return this; } public List<String> getFieldFacets() { return fieldFacets; } public List<String> getStatisticFields() { return statisticFields; } public LogicalSearchQuery addFieldFacet(String fieldFacet) { fieldFacets.add(fieldFacet); return this; } public LogicalSearchQueryFacetFilters getFacetFilters() { return facetFilters; } public int getFieldFacetLimit() { return fieldFacetLimit; } public LogicalSearchQuery setFieldFacetLimit(int fieldFacetLimit) { this.fieldFacetLimit = fieldFacetLimit; return this; } public LogicalSearchQuery setHighlighting(boolean highlighting) { this.highlighting = highlighting; return this; } public boolean isHighlighting() { return highlighting; } public boolean isSpellcheck() { return spellcheck; } public LogicalSearchQuery setSpellcheck(boolean spellcheck) { this.spellcheck = spellcheck; return this; } public Map<String, String[]> getOverridedQueryParams() { return overridedQueryParams; } public LogicalSearchQuery setOverridedQueryParams(Map<String, String[]> overridedQueryParams) { this.overridedQueryParams = overridedQueryParams; return this; } public List<SearchBoost> getFieldBoosts() { return fieldBoosts; } public LogicalSearchQuery setFieldBoosts(List<SearchBoost> fieldBoosts) { this.fieldBoosts = fieldBoosts; return this; } public List<SearchBoost> getQueryBoosts() { return queryBoosts; } public LogicalSearchQuery setQueryBoosts(List<SearchBoost> queryBoosts) { this.queryBoosts = queryBoosts; return this; } // The following methods are mainly used by the SPE itself @Override public String getQuery(String language) { SolrQueryBuilderParams params = new SolrQueryBuilderParams(preferAnalyzedFields, language); return condition.getSolrQuery(params); } @Override public List<String> getFilterQueries() { List<String> filterQueries = new ArrayList<>(); if (condition.getFilters() != null) { for (String filterQuery : condition.getFilters().getFilterQueries(userFilter != null)) { filterQueries.add(filterQuery); } } if (filterStatus != null) { filterQueries.add(filterStatus); } filterQueries.addAll(facetFilters.toSolrFilterQueries()); return filterQueries; } public String getSort() { StringBuilder stringBuilder = new StringBuilder(); for (LogicalSearchQuerySort sort : sortFields) { if (stringBuilder.length() > 0) { stringBuilder.append(", "); } String sorFieldName = sortFieldName(sort); stringBuilder.append(sorFieldName); stringBuilder.append(" "); stringBuilder.append(sort.isAscending() ? "asc" : "desc"); } return stringBuilder.toString(); } private String sortFieldName(LogicalSearchQuerySort sort) { String fieldName = sort.getFieldName(); if (fieldName != null && fieldName.endsWith("_s")) { return fieldName.substring(0, fieldName.length() - 2) + "_fs-s"; } return fieldName; } @Deprecated public MetadataSchema getSchemaCondition() { return ((SchemaFilters) condition.getFilters()).getSchema(); } public String getHighlightingFields() { return HIGHLIGHTING_FIELDS; } @Override public int hashCode() { return HashCodeBuilder.reflectionHashCode(this); } @Override public boolean equals(Object obj) { return EqualsBuilder.reflectionEquals(this, obj); } public static LogicalSearchQuery returningNoResults() { return new LogicalSearchQuery(LogicalSearchQueryOperators.fromAllSchemasIn("inexistentCollection42").returnAll()); } public void setMoreLikeThis(boolean moreLikeThis) { this.moreLikeThis = moreLikeThis; } public void addMoreLikeThisField(DataStoreField... fields) { for (DataStoreField field : fields) { // String dataStoreType; // switch (field.getDataStoreType()) { // case "ss": // dataStoreType = "txt"; // break; // case "s": // dataStoreType = "t"; // break; // default: // dataStoreType = field.getDataStoreType(); // break; // } for (String lang : new String[] { "en", "fr", "ar" }) { moreLikeThisFields.add(field.getAnalyzedField(lang).getDataStoreCode()); } } } public List<String> getMoreLikeThisFields() { return moreLikeThisFields; } public boolean isMoreLikeThis() { return moreLikeThis; } public void setQueryCondition(LogicalSearchCondition queryCondition) { this.queryCondition = queryCondition; } public LogicalSearchCondition getQueryCondition() { return queryCondition; } public static class UserFilter { private final User user; private final String access; public UserFilter(User user, String access) { this.user = user; this.access = access; } public User getUser() { return user; } public String getAccess() { return access; } } public static LogicalSearchQuery query(LogicalSearchCondition condition) { return new LogicalSearchQuery(condition); } }