Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/tminglei/slick-pg
Browse files Browse the repository at this point in the history
  • Loading branch information
tminglei committed Feb 5, 2016
2 parents 41d8656 + 545c5fa commit ab10076
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 19 deletions.
49 changes: 31 additions & 18 deletions src/main/scala/com/github/tminglei/slickpg/PgRangeSupport.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,31 @@ case object `(_,_]` extends EdgeType
case object `(_,_)` extends EdgeType
case object `[_,_]` extends EdgeType

case class Range[T](start: T, end: T, edge: EdgeType = `[_,_)`) {
import PgRangeSupportUtils._

case class Range[T](start: Option[T], end: Option[T], edge: EdgeType) {

def as[A](convert: (T => A)): Range[A] = {
new Range[A](convert(start), convert(end), edge)
new Range[A](start.map(convert), end.map(convert), edge)
}

override def toString = edge match {
case `[_,_)` => s"[$start,$end)"
case `(_,_]` => s"($start,$end]"
case `(_,_)` => s"($start,$end)"
case `[_,_]` => s"[$start,$end]"
case `[_,_)` => s"[${oToString(start)},${oToString(end)})"
case `(_,_]` => s"(${oToString(start)},${oToString(end)}]"
case `(_,_)` => s"(${oToString(start)},${oToString(end)})"
case `[_,_]` => s"[${oToString(start)},${oToString(end)}]"
}
}

object Range {
def apply[T](start: T, end: T, edge: EdgeType = `[_,_)`): Range[T] = Range(Some(start), Some(end), edge)
}

/**
* simple range support; if all you want is just getting from / saving to db, and using pg range operations/methods, it should be enough
*/
trait PgRangeSupport extends range.PgRangeExtensions with utils.PgCommonJdbcTypes { driver: PostgresDriver =>
import driver.api._
import PgRangeSupportUtils._

private def toTimestamp(str: String) = Timestamp.valueOf(str)
private def toSQLDate(str: String) = Date.valueOf(str)
Expand Down Expand Up @@ -123,30 +128,38 @@ object PgRangeSupportUtils {
val `(_,_)Range` = """\("?([^,"]*)"?,[ ]*"?([^,"]*)"?\)""".r // matches: (_,_)
val `[_,_]Range` = """\["?([^,"]*)"?,[ ]*"?([^,"]*)"?\]""".r // matches: [_,_]

def mkRangeFn[T](convert: (String => T)): (String => Range[T]) =
def mkRangeFn[T](convert: (String => T)): (String => Range[T]) = {
def conv[T](str: String, convert: (String => T)): Option[T] =
Option(str).filterNot(_.isEmpty).map(convert)

(str: String) => str match {
case `[_,_)Range`(start, end) => Range(convert(start), convert(end), `[_,_)`)
case `(_,_]Range`(start, end) => Range(convert(start), convert(end), `(_,_]`)
case `(_,_)Range`(start, end) => Range(convert(start), convert(end), `(_,_)`)
case `[_,_]Range`(start, end) => Range(convert(start), convert(end), `[_,_]`)
case `[_,_)Range`(start, end) => Range(conv(start, convert), conv(end, convert), `[_,_)`)
case `(_,_]Range`(start, end) => Range(conv(start, convert), conv(end, convert), `(_,_]`)
case `(_,_)Range`(start, end) => Range(conv(start, convert), conv(end, convert), `(_,_)`)
case `[_,_]Range`(start, end) => Range(conv(start, convert), conv(end, convert), `[_,_]`)
}
}

def toStringFn[T](toString: (T => String)): (Range[T] => String) =
(r: Range[T]) => r.edge match {
case `[_,_)` => s"[${toString(r.start)},${toString(r.end)})"
case `(_,_]` => s"(${toString(r.start)},${toString(r.end)}]"
case `(_,_)` => s"(${toString(r.start)},${toString(r.end)})"
case `[_,_]` => s"[${toString(r.start)},${toString(r.end)}]"
case `[_,_)` => s"[${oToString(r.start, toString)},${oToString(r.end, toString)})"
case `(_,_]` => s"(${oToString(r.start, toString)},${oToString(r.end, toString)}]"
case `(_,_)` => s"(${oToString(r.start, toString)},${oToString(r.end, toString)})"
case `[_,_]` => s"[${oToString(r.start, toString)},${oToString(r.end, toString)}]"
}

///
def mkWithLength[T](start: T, length: Double, edge: EdgeType = `[_,_)`) = {
val upper = (start.asInstanceOf[Double] + length).asInstanceOf[T]
new Range[T](start, upper, edge)
new Range[T](Some(start), Some(upper), edge)
}

def mkWithInterval[T <: java.util.Date](start: T, interval: Interval, edge: EdgeType = `[_,_)`) = {
val end = (start +: interval).asInstanceOf[T]
new Range[T](start, end, edge)
new Range[T](Some(start), Some(end), edge)
}

////// helper methods
private[slickpg] def oToString[T](o: Option[T], toString: (T => String) = (r: T) => r.toString) =
o.map(toString).getOrElse("")
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class PgRangeSupportSuite extends FunSuite {
Some(Range(ts("2010-01-01 14:30:00"), ts("2010-01-03 15:30:00"))))
val testRec2 = RangeBean(35L, Range(31, 59), Range(11.5f, 33.3f),
Some(Range(ts("2011-01-01 14:30:00"), ts("2011-11-01 15:30:00"))))
val testRec3 = RangeBean(41L, Range(1, 5), Range(7.5f, 15.3f), None)
val testRec3 = RangeBean(41L, Range(1, 5), Range(Some(7.5f), None, `[_,_)`), None)

test("Range Lifted support") {
Await.result(db.run(
Expand All @@ -48,6 +48,9 @@ class PgRangeSupportSuite extends FunSuite {
RangeTests forceInsertAll List(testRec1, testRec2, testRec3)
).andThen(
DBIO.seq(
RangeTests.sortBy(_.id).to[List].result.map(
r => assert(List(testRec1, testRec2, testRec3) === r)
),
// @>
RangeTests.filter(_.tsRange @>^ ts("2011-10-01 15:30:00")).sortBy(_.id).to[List].result.map(
r => assert(List(testRec2) === r)
Expand Down

0 comments on commit ab10076

Please sign in to comment.