// Path: src/main/java/org/blackdread/filtersortjooqapi/exception/FilteringApiException.java
// public class FilteringApiException extends BadUsageApiException {
// 
//     public FilteringApiException(final String message) {
//         super(message);
//     }
// }


import com.google.common.collect.ImmutableList;
import org.apache.commons.lang3.StringUtils;
import org.blackdread.filtersortjooqapi.exception.FilteringApiException;
import org.jooq.Condition;
import org.jooq.impl.DSL;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
package org.blackdread.filtersortjooqapi.filter;



/**
 * <p>Interface to  be implemented by repository that wants to provide filtering</p>
 * <p>It allows to be consistent through the app for filtering</p>
 * Created by Yoann CAPLAIN on 2017/8/25.
 */
public interface FilteringJooq {

    // TODO Idea for Filter chaining AND/OR -> so kind of strategy pattern -> default on is all are AND, if overridden then it follow the one given (done via default method and overrides), we pass the whole context -> all values that matched and are ready to be filtered
    // See Operator from jOOQ

    static final List<String> DEFAULT_IGNORED_KEY_FOR_FILTERING = ImmutableList.of("sort", "page", "size");

    /**
     * @param requestParams Keys and values to filter on
     * @return Fully constructed condition chaining (with nested conditions if implementation has)
     * @throws FilteringApiException if any filter field given cannot be found (it should result in a 400 error message)
     */
    @NotNull
    default Condition buildConditions(final Map<String, String> requestParams) {
        final List<Condition> conditions = new ArrayList<>(requestParams.size());

//        final List<String> usedKeys = new ArrayList<>(requestParams.size());
        final List<String> usedKeys = new ArrayList<>(getFilterValues().stream()
            .mapToInt(FilterValue::size)
            .sum());

        for (Map.Entry<String, String> entry : requestParams.entrySet()) {
            if (getIgnoredKeys().contains(entry.getKey()))
                continue;

            if (usedKeys.contains(entry.getKey()))
                continue;

            final FilterValue filterValue = getFilter(entry.getKey())
// Path: src/main/java/org/blackdread/filtersortjooqapi/exception/FilteringApiException.java
// public class FilteringApiException extends BadUsageApiException {
// 
//     public FilteringApiException(final String message) {
//         super(message);
//     }
// }


// Path: src/main/java/org/blackdread/filtersortjooqapi/filter/FilteringJooq.java
import com.google.common.collect.ImmutableList;
import org.apache.commons.lang3.StringUtils;
import org.blackdread.filtersortjooqapi.exception.FilteringApiException;
import org.jooq.Condition;
import org.jooq.impl.DSL;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;

package org.blackdread.filtersortjooqapi.filter;



/**
 * <p>Interface to  be implemented by repository that wants to provide filtering</p>
 * <p>It allows to be consistent through the app for filtering</p>
 * Created by Yoann CAPLAIN on 2017/8/25.
 */
public interface FilteringJooq {

    // TODO Idea for Filter chaining AND/OR -> so kind of strategy pattern -> default on is all are AND, if overridden then it follow the one given (done via default method and overrides), we pass the whole context -> all values that matched and are ready to be filtered
    // See Operator from jOOQ

    static final List<String> DEFAULT_IGNORED_KEY_FOR_FILTERING = ImmutableList.of("sort", "page", "size");

    /**
     * @param requestParams Keys and values to filter on
     * @return Fully constructed condition chaining (with nested conditions if implementation has)
     * @throws FilteringApiException if any filter field given cannot be found (it should result in a 400 error message)
     */
    @NotNull
    default Condition buildConditions(final Map<String, String> requestParams) {
        final List<Condition> conditions = new ArrayList<>(requestParams.size());

//        final List<String> usedKeys = new ArrayList<>(requestParams.size());
        final List<String> usedKeys = new ArrayList<>(getFilterValues().stream()
            .mapToInt(FilterValue::size)
            .sum());

        for (Map.Entry<String, String> entry : requestParams.entrySet()) {
            if (getIgnoredKeys().contains(entry.getKey()))
                continue;

            if (usedKeys.contains(entry.getKey()))
                continue;

            final FilterValue filterValue = getFilter(entry.getKey())
                .orElseThrow(() -> new FilteringApiException("No filter found with key (" + entry.getKey() + ")"));