Package fr.upem.query

Source Code of fr.upem.query.Query$With

package fr.upem.query;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.ToIntFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import fr.upem.query.Donor;
import fr.upem.query.Query.With;
import fr.upem.query.Query.With.Operator;

/**
* A query that can be executed on a list of {@link Donor}.
*
* By example, the queries:
* <ul>
*   <li>all limit 10
*   <br>
*    is a Query object: selector=ALL, withs=[], sortedBy=NO_SORT, limit=10
*   <li>name sorted by amount
*   <br>
*    is a Query object: selector=name, withs=[], sortedBy=amount, limit=NO_LIMIT
*   <li>all with name less than john
*   <br>
*    is a Query object: selector=ALL, withs=[name LESS_THAN john], sortedBy=NO_SORT, limit=NO_LIMIT
* </ul>
*/
public class Query {
    // name of the field of {@link Donor} among
    // { name, gender, company, amount } or ALL
    // used to return only the value of the selected field for each {@link Donor}.
    private final String selector;

    // a list of {@link With} object used to filter the donor list
    private final ArrayList<With> withs;

    // name of the field of {@link Donor} among
    // { name, gender, company, amount }
    // used to sort by or NO_SORT if there is no sort.
    private final String sortedBy;

    // number of result of a query or NO_LIMIT if there is no limit
    private final int limit;

    static final String ALL = "all";
    static final String NO_SORT ="NO_SORT";
    static final int NO_LIMIT = -1;

    /**
     * Represent a filter of the query.
     */
    static class With {
        enum Operator {
            GREATER_THAN, LESS_THAN, EQUALS_TO
        }

        // name of the field of {@link Donor} among
        // { name, gender, company, amount }
        private final String field;

        // an operator among {GREATER_THAN, LESS_THAN, EQUALS_TO}
        private final Operator operator;

        // a constant value (as a String)
        private final String constant;

        With(String field, Operator operator, String constant) {
            this.field = Objects.requireNonNull(field);
            this.operator = Objects.requireNonNull(operator);
            this.constant = Objects.requireNonNull(constant);
        }
    }

    Query(String selector, ArrayList<With> withs, String sortedBy, int limit) {
        if (limit < -1) {
            throw new IllegalArgumentException("invalid limit");
        }
        this.selector = Objects.requireNonNull(selector);
        this.withs = Objects.requireNonNull(withs);
        this.sortedBy = Objects.requireNonNull(sortedBy);
        this.limit = limit;
    }

    public static Query parse(String query) throws ParseException {
        return QueryParser.parse(query);
    }

    public <T> List<T> execute(List<Donor> donors, Class<T> returnType) {
        List<T> result;
        result = retrieveBySelector(donors);

        if (this.withs.size() > 0) {
            for (With with : this.withs) {
                result = processWith(result, with);
            }
        }

        if (this.sortedBy != NO_SORT) {
            result = (List<T>) sort((List<Donor>) result);
        }

        if (this.limit == NO_LIMIT) {
            return result;
        } else {
            return result.subList(0, this.limit);
        }
    }

    @SuppressWarnings("unchecked")
    private <T> List<T> processWith(List<T> donors, With with) {
        List<T> result = new ArrayList<>(donors);

        switch (with.field) {
            case "name":
                result.stream()
                        .filter(d -> {
                            Donor donor = (Donor) d;
                            if (with.operator == Operator.GREATER_THAN) {
                                return (0 > donor.getName().compareTo(with.constant));
                            } else if (with.operator == Operator.LESS_THAN) {
                                return (0 < donor.getName().compareTo(with.constant));
                            } else {
                                return (0 == donor.getName().compareTo(with.constant));
                            }
                        });
                break;
            case "amount":
                result.stream()
                        .filter(d -> {
                            Donor donor = (Donor) d;
                            if (with.operator == Operator.GREATER_THAN) {
                                return (Integer.getInteger(with.constant) > donor.getAmount());
                            } else if (with.operator == Operator.LESS_THAN) {
                                return (Integer.getInteger(with.constant) < donor.getAmount());
                            } else {
                                return (Integer.getInteger(with.constant) == donor.getAmount());
                            }
                        });
            default:
                throw new UnsupportedOperationException();
        }

        return result;
    }

    private List<Donor> sort(List<Donor> donors) {
        List<Donor> result = new ArrayList<>(donors);

        if (this.sortedBy == NO_SORT) {
            System.out.println("no sort");
        } else {
            switch (this.sortedBy) {
                case "name":
                    result.sort((donor1, donor2) -> {
                        return donor1.getName().compareTo(donor2.getName());
                    });
                    break;
                case "gender":
                    throw new UnsupportedOperationException(
                            "Cannot compare donors by gender.");
                case "company":
                    result.sort((donor1, donor2) -> {
                        return donor1.getCompany().compareTo(
                                donor2.getCompany());
                    });
                    break;
                case "amount":
                    result.sort((donor1, donor2) -> {
                        if (donor1.getAmount() > donor2.getAmount()) return 1;
                        else return -1;
                    });
                    break;
                default:
                    throw new UnsupportedOperationException();
            }
        }

        return result;
    }

    @SuppressWarnings("unchecked")
    private <T> List<T> retrieveBySelector(List<Donor> donors) {
        List<T> result;
        switch (this.selector) {
            case ALL:
                result = (List<T>) donors;
                break;
            case "name":
                result = (List<T>) donors.stream()
                        .map(Donor::getName)
                        .collect(Collectors.<String>toList());
                break;
            case "gender":
                result = (List<T>) donors.stream()
                        .map(Donor::getGender)
                        .collect(Collectors.<Gender>toList());
                break;
            case "company":
                result = (List<T>) donors.stream()
                        .map(Donor::getCompany)
                        .collect(Collectors.<Company>toList());
                break;
            case "amount":
                result = (List<T>) donors.stream()
                        .map(Donor::getAmount)
                        .collect(Collectors.<Long>toList());
                break;
            default:
                throw new UnsupportedOperationException();
        }
        return result;
    }
}
TOP

Related Classes of fr.upem.query.Query$With

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.