Skip to content

Commit

Permalink
Move slick project from core
Browse files Browse the repository at this point in the history
  • Loading branch information
moradology committed Apr 18, 2019
1 parent 3a87d1d commit 2347ef7
Show file tree
Hide file tree
Showing 13 changed files with 837 additions and 17 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ project/plugins/target
project/target
target
.ensime
*.bloop
*.metals
\#*#
*~
.#*
Expand Down Expand Up @@ -45,4 +47,3 @@ nohup.out
derby.log
metastore_db/
*.log

3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ scala:
- "2.12.8"
before_install:
- docker pull daunnc/openjdk-gdal:2.4.0
- docker run -d --restart=always -p 9999:5432 -e POSTGRES_DB=slick_tests quay.io/azavea/postgis:0.1.0
services:
- docker
cache:
Expand All @@ -23,4 +24,4 @@ notifications:
- [email protected]
- [email protected]
before_deploy:
- export VERSION_SUFFIX="-${TRAVIS_COMMIT:0:7}"
- export VERSION_SUFFIX="-${TRAVIS_COMMIT:0:7}"
1 change: 1 addition & 0 deletions .travis/build-and-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@

./sbt -J-Xmx2G "++$TRAVIS_SCALA_VERSION" \
"project vlm" test \
"project slick" test \
"project gdal" test || { exit 1; }
10 changes: 10 additions & 0 deletions .travis/slickTestDB.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash

docker pull quay.io/azavea/postgis:0.1.0

docker run \
-it \
--rm \
-p 9999:5432 \
-e POSTGRES_DB=slick_tests \
quay.io/azavea/postgis:0.1.0
15 changes: 14 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ lazy val commonSettings = Seq(

lazy val root = Project("geotrellis-contrib", file(".")).
aggregate(
vlm, gdal, summary
vlm, gdal, summary, slick
).
settings(commonSettings: _*).
settings(publish / skip := true).
Expand Down Expand Up @@ -130,6 +130,19 @@ lazy val gdal = project
""".stripMargin
)

lazy val slick = project
.settings(commonSettings)
.settings(
organization := "com.azavea.geotrellis",
name := "geotrellis-contrib-slick",
libraryDependencies ++= Seq(
geotrellisVector,
slickPG,
scalatest % Test
)
)
.settings(crossScalaVersions := Seq(scalaVersion.value))

lazy val testkit = project
.settings(commonSettings)
.settings(
Expand Down
29 changes: 15 additions & 14 deletions project/Dependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -43,24 +43,25 @@ object Dependencies {
val geotrellisVector = "org.locationtech.geotrellis" %% "geotrellis-vector" % Version.geotrellis
val geotrellisUtil = "org.locationtech.geotrellis" %% "geotrellis-util" % Version.geotrellis
val geotrellisShapefile = "org.locationtech.geotrellis" %% "geotrellis-shapefile" % Version.geotrellis
val slickPG = "com.github.tminglei" %% "slick-pg" % "0.16.3"

val gdal = "org.gdal" % "gdal" % Properties.envOrElse("GDAL_VERSION", "2.4.0")
val gdal = "org.gdal" % "gdal" % Properties.envOrElse("GDAL_VERSION", "2.4.0")

val pureconfig = "com.github.pureconfig" %% "pureconfig" % "0.9.1"
val logging = "com.typesafe.scala-logging" %% "scala-logging" % "3.9.0"
val scalatest = "org.scalatest" %% "scalatest" % "3.0.5"
val scalactic = "org.scalactic" %% "scalactic" % "3.0.5"
val simulacrum = "com.github.mpilquist" %% "simulacrum" % "0.15.0"
val pureconfig = "com.github.pureconfig" %% "pureconfig" % "0.9.1"
val logging = "com.typesafe.scala-logging" %% "scala-logging" % "3.9.0"
val scalatest = "org.scalatest" %% "scalatest" % "3.0.5"
val scalactic = "org.scalactic" %% "scalactic" % "3.0.5"
val simulacrum = "com.github.mpilquist" %% "simulacrum" % "0.15.0"


val catsCore = "org.typelevel" %% "cats-core" % "1.4.0"
val catsEffect = "org.typelevel" %% "cats-effect" % "1.0.0"
val fs2Core = "co.fs2" %% "fs2-core" % "1.0.0"
val fs2Io = "co.fs2" %% "fs2-io" % "1.0.0"
val catsCore = "org.typelevel" %% "cats-core" % "1.4.0"
val catsEffect = "org.typelevel" %% "cats-effect" % "1.0.0"
val fs2Core = "co.fs2" %% "fs2-core" % "1.0.0"
val fs2Io = "co.fs2" %% "fs2-io" % "1.0.0"

val sparkCore = "org.apache.spark" %% "spark-core" % Version.spark
val sparkSQL = "org.apache.spark" %% "spark-sql" % Version.spark
val hadoopClient = "org.apache.hadoop" % "hadoop-client" % Version.hadoop
val sparkCore = "org.apache.spark" %% "spark-core" % Version.spark
val sparkSQL = "org.apache.spark" %% "spark-sql" % Version.spark
val hadoopClient = "org.apache.hadoop" % "hadoop-client" % Version.hadoop

val squants = "org.typelevel" %% "squants" % "1.3.0"
val squants = "org.typelevel" %% "squants" % "1.3.0"
}
126 changes: 126 additions & 0 deletions slick/src/main/scala/geotrellis/slick/PostGisProjectionSupport.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
* Copyright 2016 Azavea
*
* 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 geotrellis.contrib.slick

import geotrellis.vector._
import geotrellis.vector.io.wkt.WKT
import geotrellis.vector.io.wkb.WKB

import slick.ast.FieldSymbol
import slick.driver.{JdbcDriver, PostgresDriver}
import slick.jdbc.{PositionedParameters, PositionedResult, SetParameter}
import com.github.tminglei.slickpg.geom.PgPostGISExtensions

import java.sql._
import scala.reflect.ClassTag

/**
* This class provides column types and extension methods to work with Geometry columns
* associated with an SRID in PostGIS.
*
* Sample Usage:
* <code>
* val PostGIS = new PostGisProjectionSupport(PostgresDriver)
* import PostGIS._
*
* class City(tag: Tag) extends Table[(Int,String,Projected[Point])](tag, "cities") {
* def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
* def name = column[String]("name")
* def geom = column[Projected[Point]]("geom")
* def * = (id, name, geom)
* }
* </code>
*
* based on [[package com.github.tminglei.slickpg.PgPostGISSupport]]
*/
trait PostGisProjectionSupport extends PgPostGISExtensions { driver: PostgresDriver =>
import PostGisProjectionSupportUtils._
import driver.api._

type GEOMETRY = Projected[Geometry]
type POINT = Projected[Point]
type LINESTRING = Projected[Line]
type POLYGON = Projected[Polygon]
type GEOMETRYCOLLECTION = Projected[GeometryCollection]

trait PostGISProjectionAssistants extends BasePostGISAssistants[GEOMETRY, POINT, LINESTRING, POLYGON, GEOMETRYCOLLECTION]
trait PostGISProjectionImplicits {
implicit val geometryTypeMapper = new ProjectedGeometryJdbcType[GEOMETRY]
implicit val pointTypeMapper = new ProjectedGeometryJdbcType[POINT]
implicit val lineTypeMapper = new ProjectedGeometryJdbcType[LINESTRING]
implicit val polygonTypeMapper = new ProjectedGeometryJdbcType[POLYGON]
implicit val geometryCollectionTypeMapper = new ProjectedGeometryJdbcType[GEOMETRYCOLLECTION]
implicit val multiPointTypeMapper = new ProjectedGeometryJdbcType[Projected[MultiPoint]]
implicit val multiPolygonTypeMapper = new ProjectedGeometryJdbcType[Projected[MultiPolygon]]
implicit val multiLineTypeMapper = new ProjectedGeometryJdbcType[Projected[MultiLine]]

implicit def geometryColumnExtensionMethods[G1 <: GEOMETRY](c: Rep[G1]) =
new GeometryColumnExtensionMethods[GEOMETRY, POINT, LINESTRING, POLYGON, GEOMETRYCOLLECTION, G1, G1](c)

implicit def geometryOptionColumnExtensionMethods[G1 <: GEOMETRY](c: Rep[Option[G1]]) =
new GeometryColumnExtensionMethods[GEOMETRY, POINT, LINESTRING, POLYGON, GEOMETRYCOLLECTION, G1, Option[G1]](c)
}

class ProjectedGeometryJdbcType[T <: Projected[Geometry] :ClassTag] extends DriverJdbcType[T] {

override def sqlTypeName(sym: Option[FieldSymbol]): String = "geometry"

override def hasLiteralForm: Boolean = false

override def valueToSQLLiteral(v: T) = toLiteral(v)

def zero: T = null.asInstanceOf[T]

def sqlType: Int = java.sql.Types.OTHER

def setValue(v: T, p: PreparedStatement, idx: Int) = p.setBytes(idx, WKB.write(v.geom, v.srid))

def updateValue(v: T, r: ResultSet, idx: Int) = r.updateBytes(idx, WKB.write(v.geom, v.srid))

def getValue(r: ResultSet, idx: Int): T = {
val s = r.getString(idx)
(if(r.wasNull) None else Some(s))
.map(fromLiteral[T](_))
.getOrElse(zero)
}
}
}

object PostGisProjectionSupportUtils {
lazy val WITH_SRID = """^SRID=([\d]+);(.*)""".r

def toLiteral(pg: Projected[Geometry]): String = s"SRID=${pg.srid};${WKT.write(pg.geom)}"

def fromLiteral[T <: Projected[_]](value: String): T =
value match {
case WITH_SRID(srid, wkt) =>
val geom = readWktOrWkb(wkt)
Projected(geom, srid.toInt).asInstanceOf[T]
case _ =>
val geom = readWktOrWkb(value)
Projected(geom, geom.jtsGeom.getSRID).asInstanceOf[T]
}

def readWktOrWkb(s: String): Geometry = {
if (s.startsWith("\\x"))
WKB.read(s.drop(2))
else if (s.startsWith("00") || s.startsWith("01"))
WKB.read(s)
else
WKT.read(s)
}
}
116 changes: 116 additions & 0 deletions slick/src/main/scala/geotrellis/slick/PostGisSupport.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
* Copyright 2016 Azavea
*
* 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 geotrellis.contrib.slick

import geotrellis.vector._
import geotrellis.vector.io.wkt.WKT
import geotrellis.vector.io.wkb.WKB

import slick.ast.FieldSymbol
import slick.driver.{JdbcDriver, PostgresDriver}
import slick.jdbc.{PositionedParameters, PositionedResult, SetParameter}
import com.github.tminglei.slickpg.geom.PgPostGISExtensions

import scala.reflect.ClassTag
import java.sql.{PreparedStatement, ResultSet}

/**
* This class provides column types and extension methods to work with Geometry columns in PostGIS.
*
* Sample Usage:
* <code>
* val PostGIS = new PostGisSupport(PostgresDriver)
* import PostGIS._
*
* class City(tag: Tag) extends Table[(Int,String,Point)](tag, "cities") {
* def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
* def name = column[String]("name")
* def geom = column[Point]("geom")
* def * = (id, name, geom)
* }
* </code>
*
* based on [[package com.github.tminglei.slickpg.PgPostGISSupport]]
*/
trait PostGisSupport extends PgPostGISExtensions { driver: PostgresDriver =>
import PostGisSupportUtils._
import driver.api._

type GEOMETRY = Geometry
type POINT = Point
type LINESTRING = Line
type POLYGON = Polygon
type GEOMETRYCOLLECTION = GeometryCollection

trait PostGISAssistants extends BasePostGISAssistants[GEOMETRY, POINT, LINESTRING, POLYGON, GEOMETRYCOLLECTION]
trait PostGISImplicits {
implicit val geometryTypeMapper = new GeometryJdbcType[GEOMETRY]
implicit val pointTypeMapper = new GeometryJdbcType[POINT]
implicit val lineTypeMapper = new GeometryJdbcType[LINESTRING]
implicit val polygonTypeMapper = new GeometryJdbcType[POLYGON]
implicit val geometryCollectionTypeMapper = new GeometryJdbcType[GEOMETRYCOLLECTION]
implicit val multiPointTypeMapper = new GeometryJdbcType[MultiPoint]
implicit val multiPolygonTypeMapper = new GeometryJdbcType[MultiPolygon]
implicit val multiLineTypeMapper = new GeometryJdbcType[MultiLine]

implicit def geometryColumnExtensionMethods[G1 <: Geometry](c: Rep[G1]) =
new GeometryColumnExtensionMethods[GEOMETRY, POINT, LINESTRING, POLYGON, GEOMETRYCOLLECTION, G1, G1](c)

implicit def geometryOptionColumnExtensionMethods[G1 <: Geometry](c: Rep[Option[G1]]) =
new GeometryColumnExtensionMethods[GEOMETRY, POINT, LINESTRING, POLYGON, GEOMETRYCOLLECTION, G1, Option[G1]](c)
}

class GeometryJdbcType[T <: Geometry](implicit override val classTag: ClassTag[T]) extends DriverJdbcType[T]{

override def sqlTypeName(sym: Option[FieldSymbol]): String = "geometry"

override def hasLiteralForm: Boolean = false

override def valueToSQLLiteral(v: T) = toLiteral(v)

def zero: T = null.asInstanceOf[T]

def sqlType: Int = java.sql.Types.OTHER

def setValue(v: T, p: PreparedStatement, idx: Int) = p.setBytes(idx, WKB.write(v))

def updateValue(v: T, r: ResultSet, idx: Int) = r.updateBytes(idx, WKB.write(v))

def getValue(r: ResultSet, idx: Int): T = {
val s = r.getString(idx)
(if(r.wasNull) None else Some(s))
.map(fromLiteral[T](_))
.getOrElse(zero)
}
}
}

object PostGisSupportUtils {
import PostGisProjectionSupportUtils._

def toLiteral(geom: Geometry): String = WKT.write(geom)

def fromLiteral[T <: Geometry](value: String): T = {
val wkt =
value match {
case WITH_SRID(srid, wkt) => wkt
case _ => value
}

readWktOrWkb(wkt).asInstanceOf[T]
}
}
21 changes: 21 additions & 0 deletions slick/src/test/resources/reference.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright 2016 Azavea
#
# 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.

db {
user = "postgres"
password = "postgres"
database = "slick_tests"
host = "localhost:9999"
}

Loading

0 comments on commit 2347ef7

Please sign in to comment.