package com.novoda.downloadmanager.lib; import java.util.ArrayList; import java.util.Arrays; import java.util.List; class Criteria { private final String selection; private final String sort; private final String[] selectionArguments; Criteria(String selection, String[] selectionArguments, String sort) { this.selection = selection; this.sort = sort; this.selectionArguments = selectionArguments; } public String getSelection() { return selection; } public String[] getSelectionArguments() { return Arrays.copyOf(selectionArguments, selectionArguments.length); } public String getSort() { return sort; } public static class Builder { private static final String SPACE = " "; private static final String AND_BETWEEN_SELECTIONS = "AND"; private static final String OR_BETWEEN_SELECTIONS = "OR"; private static final String OPEN_BRACKET = "("; private static final String CLOSE_BRACKET = ")"; private final ArgumentBuilder argumentBuilder; private final SortBuilder sortBuilder; private final SelectionBuilder selectionBuilder; public Builder() { argumentBuilder = new ArgumentBuilder(this); sortBuilder = new SortBuilder(this); selectionBuilder = new SelectionBuilder(this); } public ArgumentBuilder withSelection(String selection, Wildcard wildcard) { selectionBuilder.withSelection(selection).withWildcard(wildcard); return argumentBuilder; } public Builder withInnerCriteria(Criteria criteria) { selectionBuilder.withSelection(OPEN_BRACKET + criteria.getSelection() + CLOSE_BRACKET); argumentBuilder.withArguments(criteria.getSelectionArguments()); return this; } public Builder and() { selectionBuilder.withSelection(SPACE + AND_BETWEEN_SELECTIONS + SPACE); return this; } public Builder or() { selectionBuilder.withSelection(SPACE + OR_BETWEEN_SELECTIONS + SPACE); return this; } public Builder joinWithOr(List<Criteria> criteriaList) { for (Criteria criteria : criteriaList) { selectionBuilder.withSelection(criteria.getSelection()); argumentBuilder.withArguments(criteria.getSelectionArguments()); if (isNotLastIn(criteriaList, criteria)) { or(); } } return this; } private boolean isNotLastIn(List<Criteria> criteriaList, Criteria criteria) { return criteriaList.indexOf(criteria) != criteriaList.size() - 1; } public SortBuilder sortBy(String sortColumn) { return sortBuilder.sortBy(sortColumn); } public Criteria build() { return new Criteria(selectionBuilder.build(), argumentBuilder.build(), sortBuilder.build()); } public static class SelectionBuilder { private final Builder builder; private String selection = ""; public SelectionBuilder(Builder builder) { this.builder = builder; } private SelectionBuilder withSelection(String selection) { this.selection += selection; return this; } private Builder withWildcard(Wildcard wildcard) { this.selection += wildcard.toSql(); return builder; } String build() { return selection; } } public static class ArgumentBuilder { private final Builder builder; private final List<String> selectionArguments; ArgumentBuilder(Builder builder) { this.builder = builder; this.selectionArguments = new ArrayList<>(); } public Builder withArgument(String argument) { selectionArguments.add(argument); return builder; } private Builder withArguments(String[] arguments) { selectionArguments.addAll(Arrays.asList(arguments)); return builder; } String[] build() { return selectionArguments.toArray(new String[selectionArguments.size()]); } } public static class SortBuilder { private static final String ASCENDING_SORT = "ASC"; private static final String DESCENDING_SORT = "DESC"; private final Builder builder; private String sort = ""; public SortBuilder(Builder builder) { this.builder = builder; } public Builder ascending() { this.sort += (SPACE + ASCENDING_SORT + SPACE); return builder; } public Builder descending() { this.sort += (SPACE + DESCENDING_SORT + SPACE); return builder; } private SortBuilder sortBy(String sort) { this.sort += sort; return this; } String build() { return sort; } } } public enum Wildcard { EQUALS("=?"), LESS_THAN("<?"), MORE_THAN(">?"), MORE_THAN_EQUAL(">=?"), NOT_EQUALS("!=?"); private final String sqlValue; Wildcard(String wildcard) { this.sqlValue = wildcard; } String toSql() { return sqlValue; } } }