/**
*
* Copyright
* 2009-2015 Jayway Products AB
* 2016-2017 Föreningen Sambruk
*
* Licensed under AGPL, Version 3.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.gnu.org/licenses/agpl.txt
*
* 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 CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package se.streamsource.streamflow.web.context.util;
import java.util.ArrayList;
import java.util.List;
import org.qi4j.api.injection.scope.Service;
import org.qi4j.api.injection.scope.Structure;
import org.qi4j.api.injection.scope.Uses;
import org.qi4j.api.property.Property;
import org.qi4j.api.query.Query;
import org.qi4j.api.query.QueryExpressions;
import org.qi4j.api.query.grammar.OrderBy;
import org.qi4j.api.query.grammar.OrderBy.Order;
import org.qi4j.api.query.grammar.PropertyReference;
import org.qi4j.api.structure.Module;
import se.streamsource.dci.value.table.TableQuery;
import se.streamsource.dci.value.table.gdq.OrderByDirection;
import se.streamsource.dci.value.table.gdq.OrderByElement;
import se.streamsource.streamflow.web.application.defaults.SystemDefaultsService;
import se.streamsource.streamflow.web.domain.Describable;
import se.streamsource.streamflow.web.domain.interaction.gtd.Assignable;
import se.streamsource.streamflow.web.domain.interaction.gtd.Assignee;
import se.streamsource.streamflow.web.domain.interaction.gtd.DueOn;
import se.streamsource.streamflow.web.domain.interaction.gtd.Ownable;
import se.streamsource.streamflow.web.domain.interaction.gtd.Owner;
import se.streamsource.streamflow.web.domain.interaction.gtd.Status;
import se.streamsource.streamflow.web.domain.structure.casetype.TypedCase;
import se.streamsource.streamflow.web.domain.structure.caze.Case;
import se.streamsource.streamflow.web.domain.structure.caze.CasePriority;
import se.streamsource.streamflow.web.domain.structure.created.CreatedOn;
import se.streamsource.streamflow.web.domain.structure.organization.PrioritySettings;
/** Converter for converting a Query<Case> by applying query arguments such as ordering
* and pagination from a TableQuery object.
*/
public class TableQueryConverter {
private TableQuery tableQuery;
@Structure
Module module;
@Service
SystemDefaultsService systemConfig;
public TableQueryConverter(@Uses TableQuery tableQuery) {
this.tableQuery = tableQuery;
}
public Query<Case> convert(Iterable<Case> originalQuery) {
Query<Case> caseQuery = module.queryBuilderFactory().newQueryBuilder( Case.class ).newQuery( originalQuery )
.orderBy( QueryExpressions.orderBy( QueryExpressions.templateFor( CreatedOn.class ).createdOn(), OrderBy.Order.DESCENDING ) );
if( systemConfig.config().configuration().sortOrderAscending().get())
{
caseQuery.orderBy( QueryExpressions.orderBy( QueryExpressions.templateFor(CreatedOn.class).createdOn(), OrderBy.Order.ASCENDING) );
}
// Paging
if (tableQuery.offset() != null)
caseQuery.firstResult(tableQuery.offset());
if (tableQuery.limit() != null)
caseQuery.maxResults(tableQuery.limit());
if (tableQuery.orderBy() != null && tableQuery.orderBy().size()>0) {
caseQuery.orderBy(tableQueryToOrderByArray(tableQuery.orderBy()));
}
return caseQuery;
}
private static OrderBy[] tableQueryToOrderByArray(List<OrderByElement> orderByList) {
ArrayList<OrderBy> orderBys = new ArrayList<OrderBy>();
for (OrderByElement element: orderByList) {
orderBys.add(orderByElementToOrderBy(element));
}
return orderBys.toArray(new OrderBy[0]);
}
private static OrderBy orderByElementToOrderBy(OrderByElement element) {
Order order = element.direction == OrderByDirection.DESCENDING ? Order.DESCENDING : Order.ASCENDING;
if (element.name.equals("status")) {
return QueryExpressions.orderBy(QueryExpressions.templateFor(Status.Data.class).status(), order);
}
else if (element.name.equals("description")) {
return QueryExpressions.orderBy(QueryExpressions.templateFor(Describable.Data.class).description(), order);
}
else if (element.name.equals("dueOn")) {
return QueryExpressions.orderBy(QueryExpressions.templateFor(DueOn.Data.class).dueOn(), order);
}
else if (element.name.equals("createdOn")) {
return QueryExpressions.orderBy(QueryExpressions.templateFor(CreatedOn.class).createdOn(), order);
}
else if (element.name.equals("caseType")) {
return QueryExpressions.orderBy(
QueryExpressions.templateFor(Describable.Data.class, QueryExpressions.templateFor(TypedCase.Data.class).caseType().get()).description(), order);
}
else if (element.name.equals("assignedTo")) {
return orderByMapper(caseToAssigneeDescriptionMapper, order);
}
else if (element.name.equals("project")) {
return orderByMapper(caseToOwnerDescriptionMapper, order);
}
else if (element.name.equals( "priority" )) {
return QueryExpressions.orderBy(
QueryExpressions.templateFor( PrioritySettings.Data.class, QueryExpressions.templateFor( CasePriority.Data.class ).casepriority().get() ).priority(), revertSortOrder( order ) );
}
else {
throw new IllegalArgumentException("Order by '"+element.name+"' not supported");
}
}
private static OrderBy.Order revertSortOrder( OrderBy.Order order )
{
if( OrderBy.Order.ASCENDING.equals( order ))
return OrderBy.Order.DESCENDING;
else
return OrderBy.Order.ASCENDING;
}
private static <T> OrderBy orderByMapper(final PropertyReference<T> mapper, final OrderBy.Order order) {
return new OrderBy() {
@Override
public PropertyReference<?> propertyReference() {
return mapper;
}
@Override
public Order order() {
return order;
}
};
}
private static DerivedPropertyReference<String> caseToAssigneeDescriptionMapper = new DerivedPropertyReference<String>(String.class) {
@Override
public Property<String> eval(Object target) {
Assignable.Data assignableData = (Assignable.Data) target;
Assignee assignee = assignableData.assignedTo().get();
if (assignee instanceof Describable.Data) {
return ((Describable.Data) assignee).description();
}
return null;
}
};
private static DerivedPropertyReference<String> caseToOwnerDescriptionMapper = new DerivedPropertyReference<String>(String.class) {
@Override
public Property<String> eval(Object target) {
Ownable.Data ownableData = (Ownable.Data) target;
Owner owner = ownableData.owner().get();
if (owner instanceof Describable.Data) {
return ((Describable.Data) owner).description();
}
return null;
}
};
}