/* * Adapted from com.querydsl.core.group.GMap<K, V, M>, whose copyright was: * * Copyright 2015, The Querydsl Team (http://www.querydsl.com/team) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package fr.openwide.core.jpa.querydsl.group; import java.util.Comparator; import java.util.LinkedHashMap; import java.util.Map; import org.javatuples.Triplet; import com.google.common.collect.HashBasedTable; import com.google.common.collect.RowSortedTable; import com.google.common.collect.Table; import com.google.common.collect.TreeBasedTable; import com.querydsl.core.group.AbstractGroupExpression; import com.querydsl.core.group.GroupCollector; import com.querydsl.core.group.GroupExpression; abstract class GTable<R, C, V, T extends Table<R, C, V>> extends AbstractGroupExpression<Triplet<R, C, V>, T> { private static final long serialVersionUID = 7106389414200843920L; public GTable(QTriplet<R, C, V> qtriplet) { super(Table.class, qtriplet); } protected abstract T createTable(); public static <R, C, V> GTable<R, C, V, Table<R, C, V>> createLinked(QTriplet<R, C, V> expr) { return new GTable<R, C, V, Table<R, C, V>>(expr) { private static final long serialVersionUID = 1L; @Override protected Table<R, C, V> createTable() { return HashBasedTable.create(); } }; } @SuppressWarnings("rawtypes") public static <R extends Comparable, C extends Comparable, V> GTable<R, C, V, RowSortedTable<R, C, V>> createSorted(QTriplet<R, C, V> expr) { return new GTable<R, C, V, RowSortedTable<R, C, V>>(expr) { private static final long serialVersionUID = 1L; @Override protected RowSortedTable<R, C, V> createTable() { return TreeBasedTable.<R, C, V>create(); } }; } public static <R, C, V> GTable<R, C, V, RowSortedTable<R, C, V>> createSorted(QTriplet<R, C, V> expr, final Comparator<? super R> rowComparator, final Comparator<? super C> columnComparator) { return new GTable<R, C, V, RowSortedTable<R, C, V>>(expr) { private static final long serialVersionUID = 1L; @Override protected RowSortedTable<R, C, V> createTable() { return TreeBasedTable.<R, C, V>create(rowComparator, columnComparator); } }; } @Override public GroupCollector<Triplet<R, C, V>, T> createGroupCollector() { return new GroupCollector<Triplet<R, C, V>, T>() { private final T table = createTable(); @Override public void add(Triplet<R, C, V> triplet) { table.put(triplet.getValue0(), triplet.getValue1(), triplet.getValue2()); } @Override public T get() { return table; } }; } static class Mixin<R, C, V, R2, C2, V2, T extends Table<? super R2, ? super C2, ? super V2>> extends AbstractGroupExpression<Triplet<R, C, V>, T> { private static final long serialVersionUID = 1939989270493531116L; private class GroupCollectorImpl implements GroupCollector<Triplet<R, C, V>, T> { private final GroupCollector<Triplet<R2, C2, V2>, T> groupCollector; private final Map<R, GroupCollector<R, R2>> rowCollectors = new LinkedHashMap<R, GroupCollector<R, R2>>(); private final Map<C, GroupCollector<C, C2>> columnCollectors = new LinkedHashMap<C, GroupCollector<C, C2>>(); private final Table<GroupCollector<R, R2>, GroupCollector<C, C2>, GroupCollector<V, V2>> valueCollectors = HashBasedTable.create(); public GroupCollectorImpl() { this.groupCollector = mixin.createGroupCollector(); } @Override public void add(Triplet<R, C, V> triplet) { R row = triplet.getValue0(); GroupCollector<R, R2> rowCollector = rowCollectors.get(row); if (rowCollector == null) { rowCollector = rowExpression.createGroupCollector(); rowCollectors.put(row, rowCollector); } rowCollector.add(row); C column = triplet.getValue1(); GroupCollector<C, C2> columnCollector = columnCollectors.get(column); if (columnCollector == null) { columnCollector = columnExpression.createGroupCollector(); columnCollectors.put(column, columnCollector); } columnCollector.add(column); GroupCollector<V, V2> valueCollector = valueCollectors.get(rowCollector, columnCollector); if (valueCollector == null) { valueCollector = valueExpression.createGroupCollector(); valueCollectors.put(rowCollector, columnCollector, valueCollector); } V value = triplet.getValue2(); valueCollector.add(value); } @Override public T get() { for (Map.Entry<GroupCollector<R, R2>, Map<GroupCollector<C, C2>, GroupCollector<V, V2>>> rowEntry : valueCollectors.rowMap().entrySet()) { GroupCollector<R, R2> rowCollector = rowEntry.getKey(); R2 row = rowCollector.get(); Map<GroupCollector<C, C2>, GroupCollector<V, V2>> columnMap = rowEntry.getValue(); for (Map.Entry<GroupCollector<C, C2>, GroupCollector<V, V2>> columnEntry : columnMap.entrySet()) { GroupCollector<C, C2> columnCollector = columnEntry.getKey(); C2 column = columnCollector.get(); GroupCollector<V, V2> valueCollector = columnEntry.getValue(); V2 value = valueCollector.get(); groupCollector.add(Triplet.with(row, column, value)); } } rowCollectors.clear(); columnCollectors.clear(); valueCollectors.clear(); return groupCollector.get(); } } private final GroupExpression<Triplet<R2, C2, V2>, T> mixin; private final GroupExpression<R, R2> rowExpression; private final GroupExpression<C, C2> columnExpression; private final GroupExpression<V, V2> valueExpression; @SuppressWarnings({ "rawtypes", "unchecked" }) public Mixin(GroupExpression<R, R2> rowExpression, GroupExpression<C, C2> columnExpression, GroupExpression<V, V2> valueExpression, AbstractGroupExpression<Triplet<R2, C2, V2>, T> mixin) { super((Class) mixin.getType(), QTriplet.create(rowExpression.getExpression(), columnExpression.getExpression(), valueExpression.getExpression())); this.rowExpression = rowExpression; this.columnExpression = columnExpression; this.valueExpression = valueExpression; this.mixin = mixin; } @Override public GroupCollector<Triplet<R, C, V>, T> createGroupCollector() { return new GroupCollectorImpl(); } } }