diff --git a/README.md b/README.md index 3f43db4e..2a1002f7 100644 --- a/README.md +++ b/README.md @@ -25,4 +25,8 @@ libraryDependencies += "com.outr" %% "lightdb-all" % "0.15.0" For a specific implementation like Lucene: ```scala libraryDependencies += "com.outr" %% "lightdb-lucene" % "0.15.0" -``` \ No newline at end of file +``` + +## Videos +OKC JUG Presentation +https://www.youtube.com/watch?v=E_5fwgbF4rc \ No newline at end of file diff --git a/core/src/main/scala/lightdb/spatial/Geo.scala b/core/src/main/scala/lightdb/spatial/Geo.scala index 0fd16024..1dcd0116 100644 --- a/core/src/main/scala/lightdb/spatial/Geo.scala +++ b/core/src/main/scala/lightdb/spatial/Geo.scala @@ -49,24 +49,24 @@ object Geo { def parse(json: Json): Geo = json("type").asString match { case "Point" => - val v = json("coordinates").asVector - Geo.Point(latitude = v(1).asDouble, longitude = v(0).asDouble) + val v = json("coordinates").asVector.map(_.asDouble) + Geo.Point(latitude = v(1).asDouble, longitude = v(0).asDouble).fixed case "LineString" => Line( json("coordinates").asVector.toList.map { p => val v = p.asVector - Geo.Point(latitude = v(1).asDouble, longitude = v(0).asDouble) + Geo.Point(latitude = v(1).asDouble, longitude = v(0).asDouble).fixed } ) case "Polygon" => Polygon( json("coordinates").asVector.head.asVector.toList.map { p => val v = p.asVector - Geo.Point(latitude = v(1).asDouble, longitude = v(0).asDouble) + Geo.Point(latitude = v(1).asDouble, longitude = v(0).asDouble).fixed } ) case "MultiPolygon" => MultiPolygon( json("coordinates").asVector.toList.map { p => p.asVector.head.asVector.toList.map(_.asVector.toList).map { v => - Geo.Point(latitude = v(1).asDouble, longitude = v(0).asDouble) + Geo.Point(latitude = v(1).asDouble, longitude = v(0).asDouble).fixed } }.map(list => Polygon(list)) ) @@ -98,6 +98,12 @@ object Geo { case class Point(latitude: Double, longitude: Double) extends Geo { override def center: Point = this + + def fixed: Point = if (latitude < -90.0 || latitude > 90.0) { + Point(longitude, latitude) + } else { + this + } } case class MultiPoint(points: List[Point]) extends Geo { lazy val center: Point = Geo.center(points) diff --git a/core/src/test/scala/spec/AbstractSpatialSpec.scala b/core/src/test/scala/spec/AbstractSpatialSpec.scala index 5f8567ab..02881a37 100644 --- a/core/src/test/scala/spec/AbstractSpatialSpec.scala +++ b/core/src/test/scala/spec/AbstractSpatialSpec.scala @@ -1,5 +1,6 @@ package spec +import fabric.io.JsonParser import fabric.rw._ import lightdb.collection.Collection import lightdb.distance._ @@ -111,6 +112,18 @@ abstract class AbstractSpatialSpec extends AnyWordSpec with Matchers { spec => )) } } + "parse and insert from a GeometryCollection" in { + DB.people.transaction { implicit transaction => + val json = JsonParser("""{"crs": {"type": "name", "properties": {"name": "urn:ogc:def:crs:EPSG::4269"}}, "type": "GeometryCollection", "geometries": [{"type": "LineString", "coordinates": [[-103.79558, 32.30492], [-103.793467263, 32.331700182]]}]}""") + val geo = Geo.parseMulti(json) + DB.people.insert(Person( + name = "Baby Dole", + age = 2, + point = yonkers, + geo = geo + )) + } + } "truncate the database" in { DB.truncate() } diff --git a/lucene/src/main/scala/lightdb/lucene/LuceneStore.scala b/lucene/src/main/scala/lightdb/lucene/LuceneStore.scala index 4c118e4b..0c224c22 100644 --- a/lucene/src/main/scala/lightdb/lucene/LuceneStore.scala +++ b/lucene/src/main/scala/lightdb/lucene/LuceneStore.scala @@ -93,9 +93,17 @@ class LuceneStore[Doc <: Document[Doc], Model <: DocumentModel[Doc]](directory: field.className match { case Some("lightdb.spatial.Geo.Point") => val p = json.as[Geo.Point] - add(new LatLonPoint(field.name, p.latitude, p.longitude)) + try { + add(new LatLonPoint(field.name, p.latitude, p.longitude)) + } catch { + case t: Throwable => throw new RuntimeException(s"Failed to add LatLonPoint(${field.name}, ${p.latitude}, ${p.longitude}): ${JsonFormatter.Default(json)}", t) + } case _ => - def indexPoint(p: Geo.Point): Unit = LatLonShape.createIndexableFields(field.name, p.latitude, p.longitude) + def indexPoint(p: Geo.Point): Unit = try { + LatLonShape.createIndexableFields(field.name, p.latitude, p.longitude) + } catch { + case t: Throwable => throw new RuntimeException(s"Failed to add LatLonPoint.createIndexableFields(${field.name}, ${p.latitude}, ${p.longitude}): ${JsonFormatter.Default(json)}", t) + } def indexLine(l: Geo.Line): Unit = { val line = new Line(l.points.map(_.latitude).toArray, l.points.map(_.longitude).toArray) LatLonShape.createIndexableFields(field.name, line)