package com.github.davidmoten.rx.jdbc; import static com.github.davidmoten.rx.RxUtil.concatButIgnoreFirstSequence; import static com.github.davidmoten.rx.jdbc.Util.TO_EMPTY_PARAMETER_LIST; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Map.Entry; import rx.Observable; import rx.functions.Func1; /** * Utility methods for queries. */ final class Queries { private static final Func1<Parameter, Observable<Parameter>> FLATTEN_NAMED_MAPS = new Func1<Parameter, Observable<Parameter>>() { @SuppressWarnings("unchecked") @Override public Observable<Parameter> call(Parameter p) { if (p.value() instanceof Map) { List<Parameter> list = new ArrayList<Parameter>(); for (Entry<String, ?> entry : ((Map<String, ?>) p.value()).entrySet()) { list.add(new Parameter(entry.getKey(), entry.getValue())); } return Observable.from(list); } else return Observable.from(Arrays.asList(p)); } }; /** * Private constructor to prevent instantiation. */ private Queries() { // prevent instantiation } /** * Returns the number of parameters required to run this query once. Roughly * corresponds to the number of ? characters in the sql but have to watch * out for ? characters within quoted strings. * * @return number of parameters in query sql */ static int numParamsPerQuery(Query query) { return Util.parametersCount(query); } /** * Returns query.getParameters() {@link Observable} but only after query * dependencies have been fully emitted (and ignored). * * @return query parameters */ static Observable<Parameter> parametersAfterDependencies(Query query) { return concatButIgnoreFirstSequence(query.depends(), query.parameters()); } /** * Returns {@link Observable} with one item 1 but only after query * dependencies have been fully emitted (and ignored). * * @param query * * @return {@link Observable} with one element 1 */ static Observable<Integer> singleIntegerAfterDependencies(Query query) { return concatButIgnoreFirstSequence(query.depends(), Observable.just(1)); } /** * If the number of parameters in a query is >0 then group the parameters in * lists of that number in size but only after the dependencies have been * completed. If the number of parameteres is zero then return an observable * containing one item being an empty list. * * @param query * @return */ static Observable<List<Parameter>> bufferedParameters(Query query) { int numParamsPerQuery = numParamsPerQuery(query); if (numParamsPerQuery > 0) // we don't check that parameters is empty after this because by // general design we want nothing to happen if a query is passed no // parameters when it expects them return parametersAfterDependencies(query).concatMap(FLATTEN_NAMED_MAPS) .buffer(numParamsPerQuery); else return singleIntegerAfterDependencies(query).map(TO_EMPTY_PARAMETER_LIST); } }