/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2002-2008, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library 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 * Lesser General Public License for more details. */ package org.geotools.jdbc; import java.io.IOException; import java.util.Arrays; import java.util.Set; import org.geotools.data.Query; import org.geotools.data.Query; import org.geotools.factory.CommonFactoryFinder; import org.geotools.feature.visitor.MaxVisitor; import org.geotools.feature.visitor.MinVisitor; import org.geotools.feature.visitor.NearestVisitor; import org.geotools.feature.visitor.SumVisitor; import org.geotools.feature.visitor.UniqueVisitor; import org.geotools.filter.IllegalFilterException; import org.geotools.filter.SortByImpl; import org.geotools.filter.SortOrder; import org.geotools.util.Converters; import org.opengis.feature.Feature; import org.opengis.feature.simple.SimpleFeature; import org.opengis.filter.Filter; import org.opengis.filter.FilterFactory; import org.opengis.filter.expression.Expression; import org.opengis.filter.expression.PropertyName; import org.opengis.filter.sort.SortBy; /** * * * @source $URL$ */ public abstract class JDBCAggregateFunctionOnlineTest extends JDBCTestSupport { boolean visited = false; @Override protected void setUpInternal() throws Exception { super.setUpInternal(); visited = false; } class MySumVisitor extends SumVisitor { public MySumVisitor(Expression expr) throws IllegalFilterException { super(expr); } public void visit(Feature feature) { super.visit(feature); visited = true; } public void visit(SimpleFeature feature) { super.visit(feature); visited = true; } } public void testSum() throws Exception { FilterFactory ff = dataStore.getFilterFactory(); PropertyName p = ff.property( aname("doubleProperty") ); SumVisitor v = new MySumVisitor(p); dataStore.getFeatureSource(tname("ft1")).accepts(Query.ALL, v, null); assertFalse(visited); assertEquals( 3.3, v.getResult().toDouble(), 0.01 ); } public void testSumWithFilter() throws Exception { FilterFactory ff = dataStore.getFilterFactory(); PropertyName p = ff.property( aname("doubleProperty") ); SumVisitor v = new MySumVisitor(p); Filter f = ff.less( ff.property( aname("doubleProperty") ), ff.literal(2) ); Query q = new Query( tname("ft1"), f); dataStore.getFeatureSource( tname("ft1")).accepts( q, v, null); assertFalse(visited); assertEquals( 1.1, v.getResult().toDouble(), 0.01 ); } public void testSumWithLimitOffset() throws Exception { if (!dataStore.getSQLDialect().isLimitOffsetSupported()) { return; } FilterFactory ff = dataStore.getFilterFactory(); PropertyName p = ff.property( aname("doubleProperty") ); SumVisitor v = new MySumVisitor(p); Query q = new Query( tname("ft1")); q.setStartIndex(0); q.setMaxFeatures(2); dataStore.getFeatureSource( tname("ft1")).accepts( q, v, null); assertFalse(visited); assertEquals( 1.1, v.getResult().toDouble(), 0.01 ); } class MyMaxVisitor extends MaxVisitor { public MyMaxVisitor(Expression expr) throws IllegalFilterException { super(expr); } public void visit(Feature feature) { super.visit(feature); visited = true; } public void visit(SimpleFeature feature) { super.visit(feature); visited = true; } } public void testMax() throws Exception { FilterFactory ff = dataStore.getFilterFactory(); PropertyName p = ff.property( aname("doubleProperty") ); MaxVisitor v = new MyMaxVisitor(p); dataStore.getFeatureSource(tname("ft1")).accepts(Query.ALL, v, null); assertFalse(visited); assertEquals( 2.2, v.getResult().toDouble(), 0.01 ); } public void testMaxWithFilter() throws Exception { FilterFactory ff = dataStore.getFilterFactory(); PropertyName p = ff.property( aname("doubleProperty") ); MaxVisitor v = new MyMaxVisitor(p); Filter f = ff.less( ff.property( aname("doubleProperty") ), ff.literal(2) ); Query q = new Query( tname("ft1"), f); dataStore.getFeatureSource( tname("ft1")).accepts( q, v, null); assertFalse(visited); assertEquals( 1.1, v.getResult().toDouble(), 0.01 ); } public void testMaxWithLimitOffset() throws Exception { if (!dataStore.getSQLDialect().isLimitOffsetSupported()) { return; } FilterFactory ff = dataStore.getFilterFactory(); PropertyName p = ff.property( aname("doubleProperty") ); MaxVisitor v = new MyMaxVisitor(p); Query q = new Query( tname("ft1")); q.setStartIndex(0); q.setMaxFeatures(2); dataStore.getFeatureSource( tname("ft1")).accepts( q, v, null); assertFalse(visited); assertEquals( 1.1, v.getResult().toDouble(), 0.01 ); } class MyMinVisitor extends MinVisitor { public MyMinVisitor(Expression expr) throws IllegalFilterException { super(expr); } public void visit(Feature feature) { super.visit(feature); visited = true; } public void visit(SimpleFeature feature) { super.visit(feature); visited = true; } } public void testMin() throws Exception { FilterFactory ff = dataStore.getFilterFactory(); PropertyName p = ff.property( aname("doubleProperty") ); MinVisitor v = new MyMinVisitor(p); dataStore.getFeatureSource(tname("ft1")).accepts(Query.ALL, v, null); assertFalse(visited); assertEquals( 0.0, v.getResult().toDouble(), 0.01 ); } public void testMinWithFilter() throws Exception { FilterFactory ff = dataStore.getFilterFactory(); PropertyName p = ff.property( aname("doubleProperty") ); MinVisitor v = new MyMinVisitor(p); Filter f = ff.greater( ff.property( aname("doubleProperty") ), ff.literal(1) ); Query q = new Query( tname("ft1"), f); dataStore.getFeatureSource( tname("ft1")).accepts( q, v, null); assertFalse(visited); assertEquals( 1.1, v.getResult().toDouble(), 0.01 ); } public void testMinWithLimitOffset() throws Exception { if (!dataStore.getSQLDialect().isLimitOffsetSupported()) { return; } FilterFactory ff = dataStore.getFilterFactory(); PropertyName p = ff.property( aname("doubleProperty") ); MinVisitor v = new MyMinVisitor(p); Query q = new Query( tname("ft1")); q.setStartIndex(0); q.setMaxFeatures(2); dataStore.getFeatureSource( tname("ft1")).accepts( q, v, null); assertFalse(visited); assertEquals( 0.0, v.getResult().toDouble(), 0.01 ); } class MyUniqueVisitor extends UniqueVisitor { public MyUniqueVisitor(Expression expr) throws IllegalFilterException { super(expr); } public void visit(Feature feature) { super.visit(feature); visited = true; } public void visit(SimpleFeature feature) { super.visit(feature); visited = true; } } public void testUnique() throws Exception { FilterFactory ff = dataStore.getFilterFactory(); PropertyName p = ff.property( aname("stringProperty") ); UniqueVisitor v = new MyUniqueVisitor(p); dataStore.getFeatureSource(tname("ft1")).accepts(Query.ALL, v, null); assertFalse(visited); Set result = v.getResult().toSet(); assertEquals(3, result.size()); assertTrue(result.contains("zero")); assertTrue(result.contains("one")); assertTrue(result.contains("two")); } public void testUniqueWithFilter() throws Exception { FilterFactory ff = dataStore.getFilterFactory(); PropertyName p = ff.property( aname("stringProperty") ); UniqueVisitor v = new MyUniqueVisitor(p); Filter f = ff.greater( ff.property( aname("doubleProperty") ), ff.literal(1) ); Query q = new Query( tname("ft1"), f); dataStore.getFeatureSource(tname("ft1")).accepts(q, v, null); assertFalse(visited); Set result = v.getResult().toSet(); assertEquals(2, result.size()); assertTrue(result.contains("one")); assertTrue(result.contains("two")); } public void testUniqueWithLimitOffset() throws Exception { if (!dataStore.getSQLDialect().isLimitOffsetSupported() || !dataStore.getSQLDialect().isAggregatedSortSupported("distinct")) { return; } FilterFactory ff = dataStore.getFilterFactory(); PropertyName p = ff.property( aname("stringProperty") ); UniqueVisitor v = new MyUniqueVisitor(p); Query q = new Query( tname("ft1")); q.setStartIndex(0); q.setMaxFeatures(2); dataStore.getFeatureSource(tname("ft1")).accepts(q, v, null); assertFalse(visited); Set result = v.getResult().toSet(); assertEquals(2, result.size()); } public void testUniqueWithLimitOnVisitor() throws Exception { if (!dataStore.getSQLDialect().isLimitOffsetSupported() || !dataStore.getSQLDialect().isAggregatedSortSupported("distinct")) { return; } FilterFactory ff = dataStore.getFilterFactory(); PropertyName p = ff.property( aname("stringProperty") ); UniqueVisitor v = new MyUniqueVisitor(p); v.setPreserveOrder(true); v.setStartIndex(0); v.setMaxFeatures(2); Query q = new Query( tname("ft1")); q.setSortBy(new SortBy[] { new SortByImpl(p, SortOrder.ASCENDING)}); dataStore.getFeatureSource(tname("ft1")).accepts(q, v, null); assertFalse(visited); Set result = v.getResult().toSet(); assertEquals(2, result.size()); assertEquals("one", result.iterator().next()); } public void testStoreChecksVisitorLimits() throws Exception { if (!dataStore.getSQLDialect().isLimitOffsetSupported() || !dataStore.getSQLDialect().isAggregatedSortSupported("distinct")) { return; } FilterFactory ff = dataStore.getFilterFactory(); PropertyName p = ff.property( aname("stringProperty") ); UniqueVisitor v = new MyUniqueVisitor(p) { @Override public boolean hasLimits() { // forced to return true, to check that the JDBCDataStore // asks the visitor if it has limits, and if answered true // it ignores query limits return true; } }; v.setPreserveOrder(true); Query q = new Query( tname("ft1")); q.setMaxFeatures(1); q.setSortBy(new SortBy[] { new SortByImpl(p, SortOrder.ASCENDING)}); dataStore.getFeatureSource(tname("ft1")).accepts(q, v, null); assertFalse(visited); Set result = v.getResult().toSet(); assertEquals(3, result.size()); assertEquals("one", result.iterator().next()); } public void testUniqueWithLimitOffsetOnVisitor() throws Exception { if (!dataStore.getSQLDialect().isLimitOffsetSupported() || !dataStore.getSQLDialect().isAggregatedSortSupported("distinct")) { return; } FilterFactory ff = dataStore.getFilterFactory(); PropertyName p = ff.property( aname("stringProperty") ); UniqueVisitor v = new MyUniqueVisitor(p); v.setPreserveOrder(true); v.setStartIndex(1); v.setMaxFeatures(2); Query q = new Query( tname("ft1")); q.setSortBy(new SortBy[] { new SortByImpl(p, SortOrder.ASCENDING)}); dataStore.getFeatureSource(tname("ft1")).accepts(q, v, null); assertFalse(visited); Set result = v.getResult().toSet(); assertEquals(2, result.size()); assertEquals("two", result.iterator().next()); } class MyNearestVisitor extends NearestVisitor { public MyNearestVisitor(Expression expr, Object valueToMatch) { super(expr, valueToMatch); } public void visit(Feature feature) { super.visit(feature); visited = true; } public void visit(SimpleFeature feature) { super.visit(feature); visited = true; } } public void testNearest() throws IOException { // test strings testNearest("ft1", "stringProperty", "two", "two"); // exact match testNearest("ft1", "stringProperty", "aaa", "one"); // below testNearest("ft1", "stringProperty", "rrr", "one", "two"); // mid testNearest("ft1", "stringProperty", "zzz", "zero"); // above // test integer testNearest("ft1", "intProperty", 1, 1); // exact match testNearest("ft1", "intProperty", -10, 0); // below testNearest("ft1", "intProperty", 10, 2); // above // test double testNearest("ft1", "doubleProperty", 1.1, 1.1); // exact match testNearest("ft1", "doubleProperty", -10d, 0d); // below testNearest("ft1", "doubleProperty", 1.3, 1.1); // mid testNearest("ft1", "doubleProperty", 1.9, 2.2); // mid testNearest("ft1", "doubleProperty", 10d, 2.2); // above } private void testNearest(String typeName, String attributeName, Object target, Object... validResults) throws IOException { FilterFactory ff = CommonFactoryFinder.getFilterFactory(); PropertyName expr = ff.property(aname(attributeName)); MyNearestVisitor v = new MyNearestVisitor(expr, target); dataStore.getFeatureSource(tname(typeName)).accepts(Query.ALL, v, null); assertFalse(visited); Object nearestMatch = v.getNearestMatch(); if(validResults.length == 0) { assertNull(nearestMatch); } else { boolean found = false; for (Object object : validResults) { if (object.equals(Converters.convert(nearestMatch, object.getClass()))) { found = true; break; } } assertTrue("Could not match nearest " + nearestMatch + " among valid values " + Arrays.asList(validResults), found); } } }