All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.rx.core.NQuery Maven / Gradle / Ivy

package org.rx.core;

import com.google.common.collect.Streams;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import org.apache.commons.collections4.IterableUtils;
import org.apache.commons.collections4.IteratorUtils;
import org.rx.annotation.ErrorCode;
import org.rx.beans.Tuple;

import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.*;
import java.util.Collections;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import static org.rx.core.Contract.*;

/**
 * https://msdn.microsoft.com/en-us/library/bb738550(v=vs.110).aspx
 *
 * @param 
 */
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public final class NQuery implements Iterable, Serializable {
    //region nestedTypes
    @FunctionalInterface
    public interface IndexSelector {
        TR apply(T t, int index);
    }

    @FunctionalInterface
    public interface IndexPredicate {
        boolean test(T t, int index);

        default IndexPredicate negate() {
            return (t, i) -> !test(t, i);
        }
    }
    //endregion

    //region staticMembers
    @SuppressWarnings(NonWarning)
    @ErrorCode(value = "argError", messageKeys = {"$type"})
    public static  List asList(Object arrayOrIterable) {
        require(arrayOrIterable);

        Class type = arrayOrIterable.getClass();
        if (type.isArray()) {
            int length = Array.getLength(arrayOrIterable);
            List list = new ArrayList<>(length);
            for (int i = 0; i < length; i++) {
                Object item = Array.get(arrayOrIterable, i);
                list.add((T) item);
            }
            return list;
        }

        Iterable iterable;
        if ((iterable = as(arrayOrIterable, Iterable.class)) != null) {
            return toList(iterable);
        }

        throw new SystemException(values(type.getSimpleName()), "argError");
    }

    public static  List toList(Iterable iterable) {
        return IterableUtils.toList(iterable);
    }

    public static  List toList(Iterator iterator) {
        return IteratorUtils.toList(iterator);
    }

    public static  NQuery of(T one) {
        return of(Arrays.toList(one));
    }

    @SafeVarargs
    public static  NQuery of(T... set) {
        return of(Arrays.toList(set));
    }

    public static  NQuery of(Iterable iterable) {
        return of(iterable.iterator());
    }

    public static  NQuery of(Iterator iterator) {
        return of(toList(iterator));
    }

    public static  NQuery of(Stream stream) {
        require(stream);

        return of(stream.collect(Collectors.toList()), stream.isParallel());
    }

    public static  NQuery of(Collection set) {
        return of(set, false);
    }

    public static  NQuery of(Collection set, boolean isParallel) {
        require(set);

        return new NQuery<>(set, isParallel);
    }
    //endregion

    //region Member
    private Collection current;
    private boolean isParallel;

    public Stream stream() {
        return isParallel ? current.parallelStream() : current.stream();
    }

    @Override
    public Iterator iterator() {
        return stream().iterator();
    }

    private  List newList() {
        int count = count();
        return isParallel ? new Vector<>(count) : new ArrayList<>(count);//CopyOnWriteArrayList 写性能差
    }

    private  Set newSet() {
        int count = count();
        return isParallel ? Collections.synchronizedSet(new LinkedHashSet<>(count)) : new LinkedHashSet<>(count);
    }

    private  Map newMap() {
        int count = count();
        return isParallel ? Collections.synchronizedMap(new LinkedHashMap<>(count)) : new LinkedHashMap<>(count);
    }

    private  Stream newStream(Collection set) {
        return isParallel ? set.parallelStream() : set.stream();
    }

    private  NQuery me(Collection set) {
        return of(set, isParallel);
    }

    private  NQuery me(Stream stream) {
        return me(stream.collect(Collectors.toList()));
    }

    private NQuery me(EachFunc func) {
        return me(stream(), func);
    }

    private  NQuery me(Stream stream, EachFunc func) {
        boolean isParallel = stream.isParallel();
        Spliterator spliterator = stream.spliterator();
        return me(StreamSupport.stream(new Spliterators.AbstractSpliterator(spliterator.estimateSize(), spliterator.characteristics()) {
            AtomicBoolean breaker = new AtomicBoolean();
            AtomicInteger counter = new AtomicInteger();

            @SuppressWarnings(NonWarning)
            @Override
            public boolean tryAdvance(Consumer action) {
                return spliterator.tryAdvance(p -> {
                    int flags = func.each(p, counter.getAndIncrement());
                    if ((flags & EachFunc.Accept) == EachFunc.Accept) {
                        action.accept(p);
                    }
                    if ((flags & EachFunc.Break) == EachFunc.Break) {
                        breaker.set(true);
                    }
                }) && !breaker.get();
            }
        }, isParallel));
    }

    @FunctionalInterface
    private interface EachFunc {
        int None = 0;
        int Accept = 1;
        int Break = 1 << 1;
        int All = Accept | Break;

        int each(T t, int index);
    }
    //endregion

    public NQuery each(IndexPredicate func) {
        Iterator tor = this.iterator();
        int i = 0;
        while (tor.hasNext()) {
            if (!func.test(tor.next(), i++)) {
                break;
            }
        }
        return this;
    }

    public  NQuery select(Function selector) {
        return me(stream().map(selector));
    }

    public  NQuery select(IndexSelector selector) {
        AtomicInteger counter = new AtomicInteger();
        return me(stream().map(p -> selector.apply(p, counter.getAndIncrement())));
    }

    public  NQuery selectMany(Function> selector) {
        return me(stream().flatMap(p -> newStream(selector.apply(p))));
    }

    public  NQuery selectMany(IndexSelector> selector) {
        AtomicInteger counter = new AtomicInteger();
        return me(stream().flatMap(p -> newStream(selector.apply(p, counter.getAndIncrement()))));
    }

    public NQuery where(Predicate predicate) {
        return me(stream().filter(predicate));
    }

    public NQuery where(IndexPredicate predicate) {
        AtomicInteger counter = new AtomicInteger();
        return me(stream().filter(p -> predicate.test(p, counter.getAndIncrement())));
    }

    public  NQuery join(Collection inner, BiPredicate keySelector, BiFunction resultSelector) {
        return me(stream().flatMap(p -> newStream(inner).filter(p2 -> keySelector.test(p, p2)).map(p3 -> resultSelector.apply(p, p3))));
    }

    public  NQuery join(Function innerSelector, BiPredicate keySelector, BiFunction resultSelector) {
        return join(stream().map(innerSelector).collect(Collectors.toList()), keySelector, resultSelector);
    }

    public  NQuery joinMany(Function> innerSelector, BiPredicate keySelector, BiFunction resultSelector) {
        return join(stream().flatMap(p -> newStream(innerSelector.apply(p))).collect(Collectors.toList()), keySelector, resultSelector);
    }

    @SuppressWarnings(NonWarning)
    public  NQuery leftJoin(Collection inner, BiPredicate keySelector, BiFunction resultSelector) {
        return me(stream().flatMap(p -> {
            if (!newStream(inner).anyMatch(p2 -> keySelector.test(p, p2))) {
                return Stream.of(resultSelector.apply(p, null));
            }
            return newStream(inner).filter(p2 -> keySelector.test(p, p2)).map(p3 -> resultSelector.apply(p, p3));
        }));
    }

    public  NQuery leftJoin(Function innerSelector, BiPredicate keySelector, BiFunction resultSelector) {
        return leftJoin(stream().map(innerSelector).collect(Collectors.toList()), keySelector, resultSelector);
    }

    public  NQuery leftJoinMany(Function> innerSelector, BiPredicate keySelector, BiFunction resultSelector) {
        return leftJoin(stream().flatMap(p -> newStream(innerSelector.apply(p))).collect(Collectors.toList()), keySelector, resultSelector);
    }

    public boolean all(Predicate predicate) {
        return stream().allMatch(predicate);
    }

    public boolean any() {
        return stream().findAny().isPresent();
    }

    public boolean any(Predicate predicate) {
        return stream().anyMatch(predicate);
    }

    public boolean contains(T item) {
        return stream().anyMatch(p -> p.equals(item));
    }

    public NQuery concat(Iterable set) {
        return concat(toList(set));
    }

    public NQuery concat(Collection set) {
        return me(Stream.concat(stream(), newStream(set)));
    }

    public NQuery distinct() {
        return me(stream().distinct());
    }

    public NQuery except(Iterable set) {
        return except(toList(set));
    }

    @SuppressWarnings(NonWarning)
    public NQuery except(Collection set) {
        return me(stream().filter(p -> !newStream(set).anyMatch(p2 -> p2.equals(p))));
    }

    public NQuery intersect(Iterable set) {
        return intersect(toList(set));
    }

    public NQuery intersect(Collection set) {
        return me(stream().filter(p -> newStream(set).anyMatch(p2 -> p2.equals(p))));
    }

    public NQuery union(Iterable set) {
        return union(toList(set));
    }

    public NQuery union(Collection set) {
        return concat(set);
    }

    public  NQuery orderBy(Function keySelector) {
        return me(stream().sorted(getComparator(keySelector)));
    }

    @SuppressWarnings(NonWarning)
    public static  Comparator getComparator(Function keySelector) {
        return (p1, p2) -> {
            Comparable c1 = as(keySelector.apply(p1), Comparable.class);
            Comparable c2 = as(keySelector.apply(p2), Comparable.class);
            if (c1 == null || c2 == null) {
                return 0;
            }
            return c1.compareTo(c2);
        };
    }

    public  NQuery orderByDescending(Function keySelector) {
        return me(stream().sorted(getComparator(keySelector).reversed()));
    }

    public NQuery orderByMany(Function keySelector) {
        return me(stream().sorted(getComparatorMany(keySelector)));
    }

    @SuppressWarnings(NonWarning)
    public static  Comparator getComparatorMany(Function keySelector) {
        return (p1, p2) -> {
            Object[] k1s = keySelector.apply(p1);
            Object[] k2s = keySelector.apply(p2);
            for (int i = 0; i < k1s.length; i++) {
                Comparable c1 = as(k1s[i], Comparable.class);
                Comparable c2 = as(k2s[i], Comparable.class);
                if (c1 == null || c2 == null) {
                    continue;
                }
                int r = c1.compareTo(c2);
                if (r == 0) {
                    continue;
                }
                return r;
            }
            return 0;
        };
    }

    public NQuery orderByDescendingMany(Function keySelector) {
        return me(stream().sorted(getComparatorMany(keySelector).reversed()));
    }

    @SuppressWarnings(NonWarning)
    public NQuery reverse() {
        return me(stream().sorted((Comparator) Comparator.reverseOrder()));
    }

    public  NQuery groupBy(Function keySelector, BiFunction, TR> resultSelector) {
        Map> map = newMap();
        stream().forEach(t -> map.computeIfAbsent(keySelector.apply(t), p -> newList()).add(t));
        List result = newList();
        for (Map.Entry> entry : map.entrySet()) {
            result.add(resultSelector.apply(entry.getKey(), of(entry.getValue())));
        }
        return me(result);
    }

    public  NQuery groupByMany(Function keySelector, BiFunction, TR> resultSelector) {
        Map>> map = newMap();
        stream().forEach(t -> {
            Object[] ks = keySelector.apply(t);
            map.computeIfAbsent(toJsonString(ks), p -> Tuple.of(ks, newList())).right.add(t);
        });
        List result = newList();
        for (Tuple> entry : map.values()) {
            result.add(resultSelector.apply(entry.left, of(entry.right)));
        }
        return me(result);
    }

    public Double average(ToDoubleFunction selector) {
        OptionalDouble q = stream().mapToDouble(selector).average();
        return q.isPresent() ? q.getAsDouble() : null;
    }

    public int count() {
        return current.size();
    }

    public int count(Predicate predicate) {
        return (int) stream().filter(predicate).count();
    }

    public T max() {
        return max(stream());
    }

    @SuppressWarnings(NonWarning)
    private  TR max(Stream stream) {
        return stream.max((Comparator) Comparator.naturalOrder()).orElse(null);
    }

    public  TR max(Function selector) {
        return max(stream().map(selector));
    }

    public T min() {
        return min(stream());
    }

    @SuppressWarnings(NonWarning)
    private  TR min(Stream stream) {
        return stream.min((Comparator) Comparator.naturalOrder()).orElse(null);
    }

    public  TR min(Function selector) {
        return min(stream().map(selector));
    }

    public double sum(ToDoubleFunction selector) {
        return stream().mapToDouble(selector).sum();
    }

    @SuppressWarnings(NonWarning)
    public  NQuery cast() {
        return (NQuery) this;
    }

    @SuppressWarnings(NonWarning)
    public  NQuery ofType(Class type) {
        return where(p -> Reflects.isInstance(p, type)).select(p -> (TR) p);
    }

    @SuppressWarnings(NonWarning)
    public T first() {
        return stream().findFirst().get();
    }

    public T first(Predicate predicate) {
        return where(predicate).first();
    }

    public T firstOrDefault() {
        return firstOrDefault((T) null);
    }

    public T firstOrDefault(T defaultValue) {
        return stream().findFirst().orElse(defaultValue);
    }

    public T firstOrDefault(Predicate predicate) {
        return where(predicate).firstOrDefault();
    }

    @SuppressWarnings(NonWarning)
    public T last() {
        return Streams.findLast(stream()).get();
    }

    public T last(Predicate predicate) {
        return where(predicate).last();
    }

    public T lastOrDefault() {
        return lastOrDefault((T) null);
    }

    public T lastOrDefault(T defaultValue) {
        return Streams.findLast(stream()).orElse(defaultValue);
    }

    public T lastOrDefault(Predicate predicate) {
        return where(predicate).lastOrDefault();
    }

    @ErrorCode(messageKeys = {"$count"})
    public T single() {
        int count = count();
        if (count != 1) {
            throw new SystemException(values(count));
        }
        return first();
    }

    public T single(Predicate predicate) {
        return where(predicate).single();
    }

    @ErrorCode(messageKeys = {"$count"})
    public T singleOrDefault() {
        int count = count();
        if (count > 1) {
            throw new SystemException(values(count));
        }
        return firstOrDefault();
    }

    public T singleOrDefault(Predicate predicate) {
        return where(predicate).singleOrDefault();
    }

    public NQuery skip(int count) {
        return me(stream().skip(count));
    }

    public NQuery skipWhile(Predicate predicate) {
        return skipWhile((p, i) -> predicate.test(p));
    }

    public NQuery skipWhile(IndexPredicate predicate) {
        AtomicBoolean doAccept = new AtomicBoolean();
        return me((p, i) -> {
            int flags = EachFunc.None;
            if (doAccept.get()) {
                flags |= EachFunc.Accept;
                return flags;
            }
            if (!predicate.test(p, i)) {
                doAccept.set(true);
                flags |= EachFunc.Accept;
            }
            return flags;
        });
    }

    public NQuery take(int count) {
        return me(stream().limit(count));
    }

    public NQuery takeWhile(Predicate predicate) {
        return takeWhile((p, i) -> predicate.test(p));
    }

    public NQuery takeWhile(IndexPredicate predicate) {
        return me((p, i) -> {
            int flags = EachFunc.None;
            if (!predicate.test(p, i)) {
                flags |= EachFunc.Break;
                return flags;
            }
            flags |= EachFunc.Accept;
            return flags;
        });
    }

    public Collection asCollection() {
        return current;
    }

    public String toJoinString(String delimiter, Function selector) {
        return String.join(delimiter, select(selector));
    }

    @SuppressWarnings(NonWarning)
    public T[] toArray() {
        List result = toList();
        Class type = null;
        for (T t : result) {
            if (t == null) {
                continue;
            }
            type = t.getClass();
            break;
        }
        if (type == null) {
            throw new InvalidOperationException("Empty Result");
        }
        T[] array = (T[]) Array.newInstance(type, result.size());
        result.toArray(array);
        return array;
    }

    @SuppressWarnings(NonWarning)
    public T[] toArray(Class type) {
        List result = toList();
        T[] array = (T[]) Array.newInstance(type, result.size());
        result.toArray(array);
        return array;
    }

    public List toList() {
        List result = newList();
        result.addAll(current);
        return result;
    }

    public Set toSet() {
        Set result = newSet();
        result.addAll(current);
        return result;
    }

    public  Map toMap(Function keySelector) {
        return toMap(keySelector, p -> p);
    }

    //Collectors.toMap 会校验value为null的情况
    public  Map toMap(Function keySelector, Function resultSelector) {
        Map result = newMap();
        for (T item : current) {
            result.put(keySelector.apply(item), resultSelector.apply(item));
        }
        return result;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy