/* Copyright 2013 The jeo project. All rights reserved.
*
* 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 io.jeo.geopkg;
import static io.jeo.Tests.unzip;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.nio.file.Path;
import java.util.List;
import io.jeo.geom.Bounds;
import io.jeo.vector.FeatureWriteCursor;
import io.jeo.vector.ListFeature;
import org.apache.commons.io.FileUtils;
import io.jeo.data.Cursor;
import io.jeo.vector.VectorQuery;
import io.jeo.vector.VectorDataset;
import io.jeo.vector.Feature;
import io.jeo.vector.Schema;
import io.jeo.vector.SchemaBuilder;
import io.jeo.geom.Geom;
import io.jeo.geopkg.Entry.DataType;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Point;
import java.io.IOException;
import io.jeo.data.Transaction;
import io.jeo.data.Transactional;
public class GeoPkgFeatureTest extends GeoPkgTestSupport {
GeoPkgWorkspace geopkg;
@Before
public void setUp() throws Exception {
Path dir = unzip(getClass().getResourceAsStream("usa.gpkg.zip"), newTmpDir());
geopkg = GeoPackage.open(dir.resolve("usa.gpkg"));
}
@After
public void tearDown() throws Exception {
geopkg.close();
FileUtils.deleteQuietly(geopkg.file().getParentFile());
}
@Test
public void testFeatureEntry() throws Exception {
List<FeatureEntry> entries = geopkg.features();
assertEquals(1, entries.size());
FeatureEntry entry = entries.get(0);
assertEquals("states", entry.getTableName());
}
@Test
public void testCreateSchema() throws Exception {
FeatureEntry entry = geopkg.feature("states");
assertNotNull(entry);
Schema schema = geopkg.createSchema(entry);
assertEquals("states", schema.name());
assertNotNull(schema.geometry());
assertEquals(MultiPolygon.class, schema.geometry().type());
assertNotNull(schema.field("STATE_NAME"));
}
@Test
public void testCount() throws Exception {
FeatureEntry entry = geopkg.feature("states");
assertEquals(49, geopkg.count(entry, new VectorQuery()));
}
@Test
public void testRead() throws Exception {
FeatureEntry entry = geopkg.feature("states");
Cursor<Feature> c = geopkg.read(entry, new VectorQuery());
assertNotNull(c);
for (int i = 0; i < 49; i++) {
assertTrue(c.hasNext());
Feature f = c.next();
assertNotNull(f);
assertTrue(f.geometry() instanceof MultiPolygon);
assertNotNull(f.get("STATE_NAME"));
}
assertFalse(c.hasNext());
assertNull(c.next());
c.close();
}
@Test
public void testReadWithFilter() throws Exception {
FeatureEntry entry = geopkg.feature("states");
Cursor<Feature> c = geopkg.read(entry, new VectorQuery().filter("STATE_NAME = 'Texas'"));
assertNotNull(c);
assertTrue(c.hasNext());
assertNotNull(c.next());
assertFalse(c.hasNext());
c.close();
}
@Test
public void testAdd() throws Exception {
FeatureEntry entry = geopkg.feature("states");
Schema schema = geopkg.schema(entry);
FeatureWriteCursor cursor = geopkg.append(entry, new VectorQuery());
assertTrue(cursor.hasNext());
Geometry g = Geom.point(0,0).buffer(1);
Feature f = cursor.next();
f.put(schema.geometry().name(), g);
f.put("STATE_NAME", "JEOLAND");
cursor.write().close();
assertEquals(50, geopkg.count(entry, new VectorQuery()));
Cursor<Feature> c = geopkg.read(entry, new VectorQuery().bounds(g.getEnvelopeInternal()));
assertTrue(c.hasNext());
assertEquals("JEOLAND", c.next().get("STATE_NAME"));
c.close();
}
@Test
public void testUpdate() throws Exception {
VectorDataset states = (VectorDataset) geopkg.get("states");
assertEquals(1, states.count(new VectorQuery().filter("STATE_ABBR = 'TX'")));
assertEquals(0, states.count(new VectorQuery().filter("STATE_ABBR = 'XT'")));
FeatureWriteCursor c = states.update(new VectorQuery().filter("STATE_NAME = 'Texas'"));
assertTrue(c.hasNext());
Feature f = c.next();
f.put("STATE_ABBR", "XT");
c.write().close();
assertEquals(0, states.count(new VectorQuery().filter("STATE_ABBR = 'TX'")));
assertEquals(1, states.count(new VectorQuery().filter("STATE_ABBR = 'XT'")));
}
@Test
public void testDelete() throws Exception {
VectorDataset states = (VectorDataset) geopkg.get("states");
assertEquals(49, states.count(new VectorQuery()));
FeatureWriteCursor c = states.update(new VectorQuery().filter("STATE_ABBR = 'TX'"));
assertTrue(c.hasNext());
c.next();
c.remove().close();
assertEquals(48, states.count(new VectorQuery()));
assertEquals(0, states.count(new VectorQuery().filter("STATE_NAME = 'Texas'")));
}
@Test
public void testCreate() throws Exception {
Schema schema = new SchemaBuilder("widgets").field("geometry", Point.class)
.field("name", String.class).field("cost", Double.class).schema();
FeatureEntry entry = new FeatureEntry();
entry.setSrid(4326);
entry.setBounds(new Bounds(-180, 180, -90, 90));
geopkg.create(entry, schema);
geopkg.insert(entry, new ListFeature(schema, Geom.point(1,2), "anvil", 10.99), null);
Cursor<Feature> c = geopkg.read(entry, new VectorQuery());
try {
assertTrue(c.hasNext());
Feature f = c.next();
assertEquals(((Point)f.geometry()).getX(), 1f, 0.1);
assertEquals(((Point)f.geometry()).getY(), 2f, 0.1);
assertEquals("anvil", f.get("name"));
assertEquals(10.99, ((Number)f.get("cost")).doubleValue(), 0.1);
}
finally {
c.close();
}
//test re-loading the entry
entry = geopkg.feature("widgets");
assertNotNull(entry);
assertEquals(Geom.Type.POINT, entry.getGeometryType());
Backend.Results rs = geopkg.rawQuery("SELECT data_type FROM gpkg_contents WHERE table_name = 'widgets'");
try {
assertTrue(rs.next());
assertEquals(DataType.Feature.value(), rs.getString(0));
} finally {
rs.close();
}
}
private void assertCleanState(VectorDataset states) throws IOException {
assertEquals(1, states.count(new VectorQuery().filter("STATE_ABBR = 'TX'")));
assertEquals(49, states.count(new VectorQuery()));
}
@Test
public void testTransaction() throws Exception {
// ensure a transaction works across mutiple operations
VectorDataset states = (VectorDataset) geopkg.get("states");
assertCleanState(states);
Transaction tx = ((Transactional) states).transaction(null);
// update one
FeatureWriteCursor c = states.update(new VectorQuery().filter("STATE_NAME = 'Texas'").transaction(tx));
assertTrue(c.hasNext());
Feature f = c.next();
f.put("STATE_ABBR", "XT");
c.write().close();
// remove one
c = states.update(new VectorQuery().filter("STATE_ABBR = 'WV'").transaction(tx));
assertTrue(c.hasNext());
c.next();
c.remove().close();
// add one
c = states.append(new VectorQuery().transaction(tx));
assertTrue(c.hasNext());
f = c.next();
f.put("STATE_ABBR", "XX");
c.write().close();
tx.rollback();
assertCleanState(states);
}
}