package uk.ac.ox.zoo.seeg.abraid.mp.common.dao; import com.vividsolutions.jts.geom.Point; import org.hibernate.SQLQuery; import org.hibernate.SessionFactory; import static uk.ac.ox.zoo.seeg.abraid.mp.common.dao.NativeSQLConstants.*; /** * Contains routines that interact with the PostGIS database using native SQL. * * Copyright (c) 2014 University of Oxford */ public class NativeSQLImpl implements NativeSQL { private SessionFactory sessionFactory; public NativeSQLImpl(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } /** * Finds the first admin unit that contains the specified point. * @param point The point. * @param isGlobal True to use admin units for global diseases, false for tropical diseases. * @return The GAUL code of the first global admin unit that contains the specified point, or null if no * admin units found. */ @Override public Integer findAdminUnitThatContainsPoint(Point point, boolean isGlobal) { String query = String.format(ADMIN_UNIT_CONTAINS_POINT_QUERY, getGlobalOrTropical(isGlobal)); return (Integer) uniqueResult(query, "point", point); } /** * Finds the country that contains the specified point. * @param point The point. * @return The GAUL code of the country that contains the specified point. */ @Override public Integer findCountryThatContainsPoint(Point point) { return (Integer) uniqueResult(COUNTRY_CONTAINS_POINT_QUERY, "point", point); } /** * Determines whether one of the land-sea border geometries contains the point. * @param point The point. * @return True if the point is on land, otherwise false. */ @Override public boolean doesLandSeaBorderContainPoint(Point point) { Object id = uniqueResult(LAND_SEA_BORDER_CONTAINS_POINT_QUERY, "point", point); return (id != null); } /** * Updates the disease_extent table for the specified disease. This is done by using the * admin_unit_disease_extent_class table to aggregate the relevant geometries in the admin_unit_global/tropical * table. * @param diseaseGroupId The disease group ID. * @param isGlobal True if the disease is global, false if tropical. */ @Override public void updateAggregatedDiseaseExtent(int diseaseGroupId, boolean isGlobal) { // Flush the session to ensure that the latest admin_unit_disease_extent_class entries are available sessionFactory.getCurrentSession().flush(); String updateQuery = String.format(UPDATE_DISEASE_EXTENT_QUERY, getGlobalOrTropical(isGlobal)); executeUpdate(updateQuery, "diseaseGroupId", diseaseGroupId); } /** * Calculates the distance between the specified location and the boundaries of the disease extent of the specified * disease group. If the specified point is within the disease extent, it returns zero. * @param diseaseGroupId The ID of the disease group. * @param isGlobal True to use admin units for global diseases, false for tropical diseases. * @param locationId The location. * @return The distance outside the disease extent, or 0. */ @Override public Double findDistanceOutsideDiseaseExtent(int diseaseGroupId, boolean isGlobal, int locationId) { String query = String.format(DISTANCE_OUTSIDE_DISEASE_EXTENT, getGlobalOrTropical(isGlobal)); return (Double) uniqueResult(query, "diseaseGroupId", diseaseGroupId, "locationId", locationId); } /** * Calculates the distance between the specified location and the boundaries of the nearest admin unit not in the * disease extent of the specified disease group. * @param diseaseGroupId The ID of the disease group. * @param isGlobal True to use admin units for global diseases, false for tropical diseases. * @param locationId The location. * @return The distance inside the disease extent, or 0. */ @Override public Double findDistanceInsideDiseaseExtent(int diseaseGroupId, boolean isGlobal, int locationId) { String query = String.format(DISTANCE_INSIDE_DISEASE_EXTENT, getGlobalOrTropical(isGlobal)); return (Double) uniqueResult(query, "diseaseGroupId", diseaseGroupId, "locationId", locationId); } private SQLQuery createSQLQuery(String queryString) { return sessionFactory.getCurrentSession().createSQLQuery(queryString); } private Object uniqueResult(String queryString, Object... parameterNamesAndValues) { SQLQuery parameterisedSQLQuery = getParameterisedSQLQuery(queryString, parameterNamesAndValues); return parameterisedSQLQuery.uniqueResult(); } private Object executeUpdate(String queryString, Object... parameterNamesAndValues) { return getParameterisedSQLQuery(queryString, parameterNamesAndValues).executeUpdate(); } private SQLQuery getParameterisedSQLQuery(String queryString, Object... parameterNamesAndValues) { SQLQuery query = createSQLQuery(queryString); for (int i = 0; i < parameterNamesAndValues.length; i += 2) { query.setParameter((String) parameterNamesAndValues[i], parameterNamesAndValues[i + 1]); } return query; } private String getGlobalOrTropical(boolean isGlobal) { return isGlobal ? GLOBAL : TROPICAL; } }