/* * Copyright (C) 2014 GG-Net GmbH - Oliver Günther * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package eu.ggnet.dwoss.uniqueunit.eao; import java.util.*; import java.util.stream.Collectors; import javax.persistence.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import eu.ggnet.dwoss.rules.Step; import eu.ggnet.dwoss.rules.TradeName; import eu.ggnet.dwoss.uniqueunit.entity.UniqueUnit; import eu.ggnet.dwoss.uniqueunit.entity.UniqueUnitHistory; import eu.ggnet.dwoss.util.DateFormats; import eu.ggnet.dwoss.util.persistence.eao.AbstractEao; import com.mysema.query.jpa.impl.JPAQuery; import static eu.ggnet.dwoss.uniqueunit.entity.QProduct.product; import static eu.ggnet.dwoss.uniqueunit.entity.QUniqueUnitHistory.uniqueUnitHistory; /** * */ public class UniqueUnitEao extends AbstractEao<UniqueUnit> { private final Logger L = LoggerFactory.getLogger(UniqueUnitEao.class); private EntityManager em; public UniqueUnitEao(EntityManager em) { super(UniqueUnit.class); this.em = em; } @Override public EntityManager getEntityManager() { return em; } /** * Return exectly one unit or null if no match is found. * * @param type * @param search the exact identifier * @return exectly one unit or null if no match is found. */ public UniqueUnit findByIdentifier(UniqueUnit.Identifier type, String search) { if ( type == null ) return null; // TODO: Replace native Query Query query = em.createNativeQuery("SELECT b.UniqueUnit_id FROM UniqueUnit_identifiers as b where b.identifiers_KEY = :type and b.identifiers = :id"); query.setParameter("type", type.ordinal()); query.setParameter("id", search); try { Integer id = (Integer)query.getSingleResult(); return findById(id); } catch (NoResultException e) { return null; // TODO: All other exceptions will go up, think about } } /** * Returns all Units, which match the indentifier type and search. * <p> * @param type the type to match * @param searches the searchs * @return all Units, which match the indentifier type and search. */ public List<UniqueUnit> findByIdentifiers(UniqueUnit.Identifier type, Collection<String> searches) { if ( type == null ) return null; // TODO: Replace native Query // With: return em.createNamedQuery("UnqiueUnit.findByIdenfiersTypeValue").setParameter(1, type).setParameter(2, searches).getResultList(); // If Hibernate Bug is fixed. Query query = em.createNativeQuery( "SELECT b.UniqueUnit_id FROM UniqueUnit_identifiers b where b.identifiers_KEY = ?1 and b.identifiers IN (?2)"); query.setParameter(1, type.ordinal()); query.setParameter(2, searches); List<Integer> ids = query.getResultList(); return findByIds(ids); } /** * Returns all UniqueUnits with a supplied partNo. * <p/> * @param partNo the partNo * @return all UniqueUnits with a supplied partNo. */ public List<UniqueUnit> findByProductPartNo(String partNo) { return em.createNamedQuery("UniqueUnit.byProductPartNo", UniqueUnit.class).setParameter(1, partNo).getResultList(); } /** * Returns all UniqueUnits between the supplied inputDate and with a matching Product. * <p/> * @param partNos the partNos of the prodcut * @param start the starting Date, must not be null * @param end the ending Date, must not be null * @return all UniqueUnits between the supplied inputDate and with a matching Product. */ public List<UniqueUnit> findByProductPartNosInputDate(Collection<String> partNos, Date start, Date end) { if ( partNos == null || partNos.isEmpty() || start == null || end == null ) return new ArrayList<>(); return em.createNamedQuery("UniqueUnit.byProductPartNosInputDate", UniqueUnit.class) .setParameter(1, partNos).setParameter(2, start).setParameter(3, end).getResultList(); } /** * Returns a list of UniqueUnits which match the search string. * * @param search the search string, may start or end with '*' as wildcard, may not be null * @return a list of UniqueUnits which match the search string. */ public List<UniqueUnit> find(String search) { List<UniqueUnit> result = Collections.EMPTY_LIST; if ( search == null ) return result; // TODO: Replace native Query Query query = em.createNativeQuery("SELECT a.id FROM UniqueUnit as a join UniqueUnit_identifiers as b on a.id = b.UniqueUnit_id where b.identifiers like :search"); query.setParameter("search", search.replaceAll("\\*", "%")); List<Integer> ids = (List<Integer>)query.getResultList(); return findByIds(ids); } /** * Returns a list of UniqueUnits which match the search string. * * @param type the type, if null an empty list is returned * @param search the search string, may start or end with '*' as wildcard, may not be null * @return a list of UniqueUnits which match the search string. */ public List<UniqueUnit> findByPartialIdentifier(UniqueUnit.Identifier type, String search) { List<UniqueUnit> result = Collections.EMPTY_LIST; if ( type == null ) return result; if ( search == null ) return result; // TODO: Replace native Query Query query = em.createNativeQuery("SELECT a.id FROM UniqueUnit as a join UniqueUnit_identifiers as b on a.id = b.UniqueUnit_id where b.identifiers_KEY = :type and b.identifiers like :search"); query.setParameter("type", type.ordinal()); query.setParameter("search", search.replaceAll("\\*", "%")); List<Integer> ids = (List<Integer>)query.getResultList(); return findByIds(ids); } /** * Returns a list of units, which corespond to the ids * * @param idList the list of ids * @return a list of units, which corespond to the ids, never null. */ public List<UniqueUnit> findByIds(List<Integer> idList) { if ( idList == null || idList.isEmpty() ) return Collections.EMPTY_LIST; return em.createNamedQuery("UniqueUnit.findByIds", UniqueUnit.class).setParameter("idList", idList).getResultList(); } /** * Returns all UniqueUnits with an inputDate between start and end (including). * * @param start the start date * @param end the end date * @return all UniqueUnits with an inputDate between start and end (including) */ public List<UniqueUnit> findBetweenInputDates(Date start, Date end) { return em.createNamedQuery("UnqiueUnit.betweenInputDates", UniqueUnit.class).setParameter(1, start).setParameter(2, end).getResultList(); } /** * Returns all UniqueUnits with an inputDate between start and end (including) and its contractor. * * @param start the start date * @param end the end date * @param contractor the contractor * @return all UniqueUnits with an inputDate between start and end (including) and its contractor */ public List<UniqueUnit> findBetweenInputDatesAndContractor(Date start, Date end, TradeName contractor) { return em.createNamedQuery("UnqiueUnit.betweenInputDatesAndContractor", UniqueUnit.class).setParameter(1, start).setParameter(2, end).setParameter(3, contractor).getResultList(); } /** * Return all UniqueUnits which have the supplied contractor. * <p/> * @param contractor the contractor. * @return all UniqueUnits which have the supplied contractor. */ public List<UniqueUnit> findByContractor(TradeName contractor) { return em.createNamedQuery("UnqiueUnit.byContractor", UniqueUnit.class).setParameter(1, contractor).getResultList(); } /** * Return the {@link UniqueUnit} assoiated with a refurbished id that occured in any {@link UniqueUnitHistory}. * <p> * @param refurbishedId * @return the {@link UniqueUnit} assoiated with a refurbished id that occured in any {@link UniqueUnitHistory}. */ public UniqueUnit findByRefurbishedIdInHistory(String refurbishedId) { UniqueUnitHistory result = new JPAQuery(em).from(uniqueUnitHistory).where( uniqueUnitHistory.comment.like("Changed Identifier(type=REFURBISHED_ID) from '" + refurbishedId + "' to%") .or(uniqueUnitHistory.comment.like("Unit changed refurbishedId=" + refurbishedId + " to%") .or(uniqueUnitHistory.comment.eq("REFURBISHED_ID set to " + refurbishedId)))).singleResult(uniqueUnitHistory); return (result == null ? null : result.getUniqueUnit()); } /** * Returns a collection of manufactures, which are used by any product, like product.tradeName.getManufacturer. * <p> * @return a collection of manufactures, which are used by any product, like product.tradeName.getManufacturer. */ public NavigableSet<TradeName> findUsedManufactuers() { return new JPAQuery(em).from(product).groupBy(product.tradeName).list(product.tradeName) .stream().map(TradeName::getManufacturer).collect(Collectors.toCollection(() -> new TreeSet<>())); } /** * Returns the amount of unique units, split by date, contractor and brand. * <p> * @param start * @param step the step size. * @param end * @return the amount of unique units, split by date, contractor and brand. */ public NavigableMap<Date, BrandContractorCount> countByInputDateContractor(Date start, Date end, Step step) { TypedQuery<CountHolder> q = em.createNamedQuery("UniqueUnit.countByInputDateContractor", CountHolder.class) .setParameter("start", start).setParameter("end", end); NavigableMap<Date, BrandContractorCount> result = prepare(start, end, step); for (CountHolder holder : q.getResultList()) { BrandContractorCount count = result.get(step.truncate(holder.getInputDate())); // Highly unlikely case, but if it happens a detail message might help. if ( count == null ) throw new RuntimeException("No prepared BrandContractorCount found for " + step.name() + ":inputDate=" + DateFormats.ISO.format(holder.getInputDate()) + ",truncated=" + DateFormats.ISO.format(step.truncate(holder.getInputDate())) + ",keys=" + nice(result.keySet(), step) ); count.addTo(holder.getBrand(), holder.getContractor(), holder.getCount()); } return result; } private NavigableMap<Date, BrandContractorCount> prepare(Date start, Date end, Step step) { NavigableMap<Date, BrandContractorCount> result = new TreeMap<>(); Date actual = step.truncate(start); end = step.prepareEnd(end); while (actual.before(end)) { result.put(actual, new BrandContractorCount()); actual = step.incement(actual); } return result; } private List<String> nice(Set<Date> dates, Step step) { List<String> result = new ArrayList<>(); for (Date date : dates) { result.add(step.format(date) + "(" + DateFormats.ISO.format(date) + ")"); } return result; } }