@JsonInclude(JsonInclude.Include.NON_NULL)
public abstract class Context {

    private Integer timeout;
    private Integer priority;
    private String queryId;
    private Boolean useCache;
    private Boolean populateCache;
    private Boolean bySegment;
    private Boolean finalize;
    private Period chunkPeriod;

    Context(Integer timeout, Integer priority, String queryId, Boolean useCache, Boolean populateCache,
            Boolean bySegment, Boolean finalize, Period chunkPeriod) {
        this.timeout = timeout;
        this.priority = priority;
        this.queryId = queryId;
        this.useCache = useCache;
        this.populateCache = populateCache;
        this.bySegment = bySegment;
        this.finalize = finalize;
        this.chunkPeriod = chunkPeriod;
    }

    public Integer getTimeout() {
        return timeout;
    }

    public Integer getPriority() {
        return priority;
    }

    public String getQueryId() {
        return queryId;
    }

    public Boolean getUseCache() {
        return useCache;
    }

    public Boolean getPopulateCache() {
        return populateCache;
    }

    public Boolean getBySegment() {
        return bySegment;
    }

    public Boolean getFinalize() {
        return finalize;
    }

    public Period getChunkPeriod() {
        return chunkPeriod;
    }

    @SuppressWarnings(value = {"unchecked"})
    protected static abstract class ContextBuilder<T extends ContextBuilder<?>> {

        Integer timeout;
        Integer priority;
        String queryId;
        Boolean useCache;
        Boolean populateCache;
        Boolean bySegment;
        Boolean finalize;
        Period chunkPeriod;

        ContextBuilder() {

        }

        public T withTimeout(Integer timeout) {
            this.timeout = timeout;
            return (T) this;
        }

        public T withPriority(Integer priority) {
            this.priority = priority;
            return (T) this;
        }

        public T withQueryId(String queryId) {
            this.queryId = queryId;
            return (T) this;
        }

        public T withUseCache(Boolean useCache) {
            this.useCache = useCache;
            return (T) this;
        }

        public T withPopulateCache(Boolean populateCache) {
            this.populateCache = populateCache;
            return (T) this;
        }

        public T withBySegment(Boolean bySegment) {
            this.bySegment = bySegment;
            return (T) this;
        }

        public T withFinalize(Boolean finalize) {
            this.finalize = finalize;
            return (T) this;
        }

        public T withChunkPeriod(Period chunkPeriod) {
            this.chunkPeriod = chunkPeriod;
            return (T) this;
        }

        public T withChunkPeriod(String chunkPeriod) {
            this.chunkPeriod = Period.parse(chunkPeriod);
            return (T) this;
        }
    }
} public interface DataSource {
    String getType();
} @JsonInclude(JsonInclude.Include.NON_NULL)
public class TableDataSource implements DataSource {

    private final String type = "table";

    private String name;

    TableDataSource(String name) {
        Properties.assertRequired(name, "Name is a required property");
        this.name = name;
    }

    @Override
    public String getType() {
        return type;
    }

    public String getName() {
        return name;
    }

    public static TableDataSourceBuilder builder() {
        return new TableDataSourceBuilder();
    }

    public static class TableDataSourceBuilder {
        private String name;

        TableDataSourceBuilder() {

        }

        public TableDataSourceBuilder withName(String name) {
            this.name = name;
            return this;
        }

        public TableDataSource build() {
            return new TableDataSource(name);
        }
    }
} @JsonInclude(JsonInclude.Include.NON_NULL)
public class DefaultDimension implements Dimension {

    private final String type = "default";

    private String dimension;
    private String outputName;

    DefaultDimension(String dimension, String outputName) {
        Properties.assertRequired(dimension, "Dimension is a required property");

        this.dimension = dimension;
        this.outputName = outputName;
    }

    @Override
    public String getType() {
        return type;
    }

    public String getDimension() {
        return dimension;
    }

    public String getOutputName() {
        return outputName;
    }

    public static DefaultDimensionBuilder builder() {
        return new DefaultDimensionBuilder();
    }

    public static class DefaultDimensionBuilder {

        private String dimension;
        private String outputName;

        DefaultDimensionBuilder() {

        }

        public DefaultDimensionBuilder withDimension(String dimension) {
            this.dimension = dimension;
            return this;
        }

        public DefaultDimensionBuilder withOutputName(String outputName) {
            this.outputName = outputName;
            return this;
        }

        public DefaultDimension build() {
            return new DefaultDimension(dimension, outputName);
        }
    }
} public interface Dimension {
    String getType();
} public interface Filter {
    String getType();
} public interface Granularity {
    String getType();
} public interface SearchQuerySpec {
    String getType();
} public class SearchSortSpec {
    private SortingOrder type;

    public SearchSortSpec(SortingOrder type) {
        this.type = type;
    }

    public SortingOrder getType() {
        return type;
    }
} public enum SortingOrder {

    /**
     * Sorts values by converting Strings to their UTF-8 byte array representations and comparing lexicgraphically,
     * byte-by-byte.
     */
    LEXICOGRAPHIC("lexicographic"),

    /**
     * Suitable for strings with both numeric and non-numeric content, e.g.: "file12 sorts after file2"
     * <p>
     * See <a href="https://github.com/amjjd/java-alphanum">https://github.com/amjjd/java-alphanum</a> for more details
     * on how this ordering sorts values.
     * <p>
     * This ordering is not suitable for numbers with decimal points or negative numbers. For example, "1.3" precedes
     * "1.15" in this ordering because "15" has more significant digits than "3". Negative numbers are sorted after
     * positive numbers (because numeric characters precede the "-" in the negative numbers).
     */
    ALPHANUMERIC("alphanumeric"),

    /**
     * Sorts values as numbers, supports integers and floating point values. Negative values are supported.
     * <p>
     * This sorting order will try to parse all string values as numbers. Unparseable values are treated as nulls, and
     * nulls precede numbers.
     * <p>
     * When comparing two unparseable values (e.g., "hello" and "world"), this ordering will sort by comparing the
     * unparsed strings lexicographically.
     */
    NUMERIC("numeric"),

    /**
     * Sorts values by the their string lengths. When there is a tie, this comparator falls back to using the String
     * compareTo method.
     */
    STRLEN("strlen");

    private final String value;

    SortingOrder(String value) {
        this.value = value;
    }

    @JsonValue
    public String getValue() {
        return value;
    }
} public final class Properties {

    private Properties() {

    }

    public static <T> void assertRequired(T property, String errorMessage) {
        if (property == null) {
            throw new RequiredPropertyException(errorMessage);
        }
    }

    public static <T, E> void assertRequiredDependency(T property, E dependency, String errorMessage) {
        if (property != null && dependency == null) {
            throw new RequiredPropertyException(errorMessage);
        }
    }

    public static <T> void assertValid(T property, Function<T, Boolean> booleanExpression, String errorMessage) {
        if (!booleanExpression.apply(property)) {
            throw new InvalidPropertyException(errorMessage);
        }
    }
}
import com.fasterxml.jackson.annotation.JsonInclude;
import com.github.levin81.daelic.druid.context.Context;
import com.github.levin81.daelic.druid.datasource.DataSource;
import com.github.levin81.daelic.druid.datasource.TableDataSource;
import com.github.levin81.daelic.druid.dimension.DefaultDimension;
import com.github.levin81.daelic.druid.dimension.Dimension;
import com.github.levin81.daelic.druid.filter.Filter;
import com.github.levin81.daelic.druid.granularity.Granularity;
import com.github.levin81.daelic.druid.searchqueryspec.SearchQuerySpec;
import com.github.levin81.daelic.druid.sorting.SearchSortSpec;
import com.github.levin81.daelic.druid.sorting.SortingOrder;
import com.github.levin81.daelic.util.Properties;
import java.util.ArrayList;
import java.util.List;
package com.github.levin81.daelic.druid;



@JsonInclude(JsonInclude.Include.NON_NULL)
public class Search {

    private final String queryType = "search";

    private DataSource dataSource;