package org.gbif.occurrence.download.query; import org.gbif.api.model.occurrence.predicate.ConjunctionPredicate; import org.gbif.api.model.occurrence.predicate.DisjunctionPredicate; import org.gbif.api.model.occurrence.predicate.EqualsPredicate; import org.gbif.api.model.occurrence.predicate.GreaterThanOrEqualsPredicate; import org.gbif.api.model.occurrence.predicate.GreaterThanPredicate; import org.gbif.api.model.occurrence.predicate.InPredicate; import org.gbif.api.model.occurrence.predicate.IsNotNullPredicate; import org.gbif.api.model.occurrence.predicate.LessThanOrEqualsPredicate; import org.gbif.api.model.occurrence.predicate.LessThanPredicate; import org.gbif.api.model.occurrence.predicate.LikePredicate; import org.gbif.api.model.occurrence.predicate.NotPredicate; import org.gbif.api.model.occurrence.predicate.Predicate; import org.gbif.api.model.occurrence.predicate.WithinPredicate; import org.gbif.api.model.occurrence.search.OccurrenceSearchParameter; import org.gbif.api.util.IsoDateParsingUtils; import org.gbif.api.util.IsoDateParsingUtils.IsoDateFormat; import org.gbif.api.util.SearchTypeValidator; import org.gbif.api.vocabulary.Country; import org.gbif.api.vocabulary.Language; import java.util.Date; import java.util.List; import java.util.UUID; import com.google.common.collect.Lists; import com.google.common.collect.Range; import org.junit.Test; import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; public class HiveQueryVisitorTest { private static final OccurrenceSearchParameter PARAM = OccurrenceSearchParameter.CATALOG_NUMBER; private static final OccurrenceSearchParameter PARAM2 = OccurrenceSearchParameter.INSTITUTION_CODE; private final HiveQueryVisitor visitor = new HiveQueryVisitor(); @Test public void testComplexQuery() throws QueryBuildingException { Predicate aves = new EqualsPredicate(OccurrenceSearchParameter.TAXON_KEY, "212"); Predicate passer = new LikePredicate(OccurrenceSearchParameter.SCIENTIFIC_NAME, "Passer%"); Predicate UK = new EqualsPredicate(OccurrenceSearchParameter.COUNTRY, "GB"); Predicate before1989 = new LessThanOrEqualsPredicate(OccurrenceSearchParameter.YEAR, "1989"); Predicate georeferencedPredicate = new EqualsPredicate(OccurrenceSearchParameter.HAS_COORDINATE, "true"); ConjunctionPredicate p = new ConjunctionPredicate(Lists.newArrayList(aves, UK, passer, before1989, georeferencedPredicate)); String where = visitor.getHiveQuery(p); assertEquals( "(((taxonkey = 212 OR kingdomkey = 212 OR phylumkey = 212 OR classkey = 212 OR orderkey = 212 OR familykey = 212 OR genuskey = 212 OR subgenuskey = 212 OR specieskey = 212)) AND (countrycode = \'GB\') AND (scientificname LIKE \'Passer%\') AND (year <= 1989) AND (hascoordinate = true))", where); } @Test public void testConjunctionPredicate() throws QueryBuildingException { Predicate p1 = new EqualsPredicate(PARAM, "value_1"); Predicate p2 = new EqualsPredicate(PARAM2, "value_2"); ConjunctionPredicate p = new ConjunctionPredicate(Lists.newArrayList(p1, p2)); String query = visitor.getHiveQuery(p); assertThat(query, equalTo("((catalognumber = \'value_1\') AND (institutioncode = \'value_2\'))")); } @Test public void testDisjunctionPredicate() throws QueryBuildingException { Predicate p1 = new EqualsPredicate(PARAM, "value_1"); Predicate p2 = new EqualsPredicate(PARAM2, "value_2"); DisjunctionPredicate p = new DisjunctionPredicate(Lists.newArrayList(p1, p2)); String query = visitor.getHiveQuery(p); assertThat(query, equalTo("((catalognumber = \'value_1\') OR (institutioncode = \'value_2\'))")); } @Test public void testEqualsPredicate() throws QueryBuildingException { Predicate p = new EqualsPredicate(PARAM, "value"); String query = visitor.getHiveQuery(p); assertThat(query, equalTo("catalognumber = \'value\'")); } @Test public void testGreaterThanOrEqualPredicate() throws QueryBuildingException { Predicate p = new GreaterThanOrEqualsPredicate(OccurrenceSearchParameter.ELEVATION, "222"); String query = visitor.getHiveQuery(p); assertThat(query, equalTo("elevation >= 222")); } @Test public void testGreaterThanPredicate() throws QueryBuildingException { Predicate p = new GreaterThanPredicate(OccurrenceSearchParameter.ELEVATION, "1000"); String query = visitor.getHiveQuery(p); assertThat(query, equalTo("elevation > 1000")); } @Test public void testInPredicate() throws QueryBuildingException { Predicate p = new InPredicate(PARAM, Lists.newArrayList("value_1", "value_2", "value_3")); String query = visitor.getHiveQuery(p); assertThat(query, equalTo("((catalognumber = \'value_1\') OR (catalognumber = \'value_2\') OR (catalognumber = \'value_3\'))")); } @Test public void testLessThanOrEqualPredicate() throws QueryBuildingException { Predicate p = new LessThanOrEqualsPredicate(OccurrenceSearchParameter.ELEVATION, "1000"); String query = visitor.getHiveQuery(p); assertThat(query, equalTo("elevation <= 1000")); } @Test public void testLessThanPredicate() throws QueryBuildingException { Predicate p = new LessThanPredicate(OccurrenceSearchParameter.ELEVATION, "1000"); String query = visitor.getHiveQuery(p); assertThat(query, equalTo("elevation < 1000")); } @Test public void testNotPredicate() throws QueryBuildingException { Predicate p = new NotPredicate(new EqualsPredicate(PARAM, "value")); String query = visitor.getHiveQuery(p); assertThat(query, equalTo("NOT catalognumber = \'value\'")); } @Test public void testNotPredicateComplex() throws QueryBuildingException { Predicate p1 = new EqualsPredicate(PARAM, "value_1"); Predicate p2 = new EqualsPredicate(PARAM2, "value_2"); ConjunctionPredicate cp = new ConjunctionPredicate(Lists.newArrayList(p1, p2)); Predicate p = new NotPredicate(cp); String query = visitor.getHiveQuery(p); assertThat(query, equalTo("NOT ((catalognumber = \'value_1\') AND (institutioncode = \'value_2\'))")); } @Test public void testQuotes() throws QueryBuildingException { Predicate p = new EqualsPredicate(PARAM, "my \'pleasure\'"); String query = visitor.getHiveQuery(p); assertThat(query, equalTo("catalognumber = \'my \\\'pleasure\\\'\'")); p = new LessThanOrEqualsPredicate(OccurrenceSearchParameter.ELEVATION, "101"); query = visitor.getHiveQuery(p); assertThat(query, equalTo("elevation <= 101")); p = new GreaterThanPredicate(OccurrenceSearchParameter.YEAR, "1998"); query = visitor.getHiveQuery(p); assertThat(query, equalTo("year > 1998")); } @Test public void testWithinPredicate() throws QueryBuildingException { final String wkt = "POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10))"; Predicate p = new WithinPredicate(wkt); String query = visitor.getHiveQuery(p); assertThat(query, equalTo("contains(\"" + wkt + "\", decimallatitude, decimallongitude)")); } @Test public void testIsNotNullPredicate() throws QueryBuildingException { Predicate p = new IsNotNullPredicate(PARAM); String query = visitor.getHiveQuery(p); assertThat(query, equalTo("catalognumber IS NOT NULL ")); } @Test public void testIsNotNullArrayPredicate() throws QueryBuildingException { Predicate p = new IsNotNullPredicate(OccurrenceSearchParameter.MEDIA_TYPE); String query = visitor.getHiveQuery(p); assertThat(query, equalTo("(mediatype IS NOT NULL AND size(mediatype) > 0)")); } @Test public void testPartialDates() throws QueryBuildingException { testPartialDate("2014-10"); testPartialDate("1936"); } @Test public void testDateRanges() throws QueryBuildingException { testPartialDate("2014-05,2014-10"); testPartialDate("1936,1940"); } /** * Reusable method to test partial dates, i.e., dates with the format: yyyy, yyyy-MM. */ private void testPartialDate(String value) throws QueryBuildingException { Range<Date> range = null; if(SearchTypeValidator.isRange(value)){ range = IsoDateParsingUtils.parseDateRange(value); } else { Date lowerDate = IsoDateParsingUtils.parseDate(value); Date upperDate = null; IsoDateFormat isoDateFormat = IsoDateParsingUtils.getFirstDateFormatMatch(value); if(IsoDateFormat.YEAR == isoDateFormat) { upperDate = IsoDateParsingUtils.toLastDayOfYear(lowerDate); } else if(IsoDateFormat.YEAR_MONTH == isoDateFormat){ upperDate = IsoDateParsingUtils.toLastDayOfMonth(lowerDate); } range = Range.closed(lowerDate,upperDate); } Predicate p = new EqualsPredicate(OccurrenceSearchParameter.LAST_INTERPRETED,value); String query = visitor.getHiveQuery(p); assertThat(query, equalTo(String.format("((lastinterpreted >= %s) AND (lastinterpreted <= %s))", String.valueOf(range.lowerEndpoint().getTime()), String.valueOf(range.upperEndpoint().getTime())))); } @Test public void testAllParamsExist() throws QueryBuildingException { List<Predicate> predicates = Lists.newArrayList(); for (OccurrenceSearchParameter param : OccurrenceSearchParameter.values()) { String value = "7"; if (OccurrenceSearchParameter.GEOMETRY == param) { value = "POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10))"; predicates.add(new WithinPredicate(value)); } else if (UUID.class.isAssignableFrom(param.type())) { value = UUID.randomUUID().toString(); } else if (Boolean.class.isAssignableFrom(param.type())) { value = "true"; } else if (Country.class.isAssignableFrom(param.type())) { value = Country.GERMANY.getIso2LetterCode(); } else if (Language.class.isAssignableFrom(param.type())) { value = Language.GERMAN.getIso2LetterCode(); } else if (Enum.class.isAssignableFrom(param.type())) { Enum<?>[] values = ((Class<Enum>) param.type()).getEnumConstants(); value = values[0].name(); } else if (Date.class.isAssignableFrom(param.type())) { value = "2014-01-23"; } if (OccurrenceSearchParameter.GEOMETRY != param) { predicates.add(new EqualsPredicate(param, value)); } } ConjunctionPredicate and = new ConjunctionPredicate(predicates); String where = visitor.getHiveQuery(and); } }