From 077dd06cc14b23ae3129c13ee840202bf0ee5c7f Mon Sep 17 00:00:00 2001 From: Stewart Stewart Date: Fri, 16 Dec 2016 20:49:22 -0500 Subject: add execute for ListT/OptionT and improve inference --- src/main/scala/xyz/driver/core/database.scala | 62 ++++++++++++++++----------- 1 file changed, 38 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/main/scala/xyz/driver/core/database.scala b/src/main/scala/xyz/driver/core/database.scala index a82e345..255e741 100644 --- a/src/main/scala/xyz/driver/core/database.scala +++ b/src/main/scala/xyz/driver/core/database.scala @@ -1,13 +1,13 @@ package xyz.driver.core +import scala.concurrent.{ExecutionContext, Future} + +import scalaz.{Monad, ListT, OptionT} import slick.backend.DatabaseConfig import slick.dbio.{DBIOAction, NoStream} import slick.driver.JdbcProfile import xyz.driver.core.time.Time -import scala.concurrent.{ExecutionContext, Future} -import scalaz.Monad - object database { trait Database { @@ -80,46 +80,60 @@ object database { trait Dal { - type T[_] - implicit val monadT: Monad[T] + protected type T[D] + protected implicit val monadT: Monad[T] - def execute[D](operations: T[D]): Future[D] - def noAction[V](v: V): T[V] - def customAction[R](action: => Future[R]): T[R] + protected def execute[D](operations: T[D]): Future[D] + protected def execute[D](readOperations: OptionT[T, D]): OptionT[Future, D] + protected def execute[D](readOperations: ListT[T, D]): ListT[Future, D] + + protected def noAction[V](v: V): T[V] + protected def customAction[R](action: => Future[R]): T[R] } class FutureDal(executionContext: ExecutionContext) extends Dal { + import scalaz.std.scalaFuture._ implicit val exec = executionContext - override type T[_] = Future[_] - implicit val monadT: Monad[T] = new Monad[T] { - override def point[A](a: => A): T[A] = Future(a) - override def bind[A, B](fa: T[A])(f: A => T[B]): T[B] = fa.flatMap(a => f(a.asInstanceOf[A])) - } + override type T[D] = Future[D] + implicit val monadT = implicitly[Monad[Future]] - def execute[D](operations: T[D]): Future[D] = operations.asInstanceOf[Future[D]] - def noAction[V](v: V): T[V] = Future.successful(v) - def customAction[R](action: => Future[R]): T[R] = action + def execute[D](operations: T[D]): Future[D] = operations + def execute[D](operations: OptionT[T, D]): OptionT[Future, D] = OptionT(operations.run) + def execute[D](operations: ListT[T, D]): ListT[Future, D] = ListT(operations.run) + def noAction[V](v: V): T[V] = Future.successful(v) + def customAction[R](action: => Future[R]): T[R] = action } class SlickDal(database: Database, executionContext: ExecutionContext) extends Dal { import database.profile.api._ - implicit val exec = executionContext + override type T[D] = slick.dbio.DBIO[D] - override type T[_] = slick.dbio.DBIO[_] - val monadT: Monad[T] = new Monad[T] { + implicit protected class QueryOps[+E, U](query: Query[E, U, Seq]) { + def resultT: ListT[T, U] = ListT[T, U](query.result.map(_.toList)) + } + + override implicit val monadT: Monad[T] = new Monad[T] { override def point[A](a: => A): T[A] = DBIO.successful(a) - override def bind[A, B](fa: T[A])(f: A => T[B]): T[B] = fa.flatMap(a => f(a.asInstanceOf[A])) + override def bind[A, B](fa: T[A])(f: A => T[B]): T[B] = fa.flatMap(f) + } + + override def execute[D](readOperations: T[D]): Future[D] = { + database.database.run(readOperations.transactionally) + } + + override def execute[D](readOperations: OptionT[T, D]): OptionT[Future, D] = { + OptionT(database.database.run(readOperations.run.transactionally)) } - def execute[D](readOperations: T[D]): Future[D] = { - database.database.run(readOperations.asInstanceOf[slick.dbio.DBIO[D]].transactionally) + override def execute[D](readOperations: ListT[T, D]): ListT[Future, D] = { + ListT(database.database.run(readOperations.run.transactionally)) } - def noAction[V](v: V): slick.dbio.DBIO[V] = DBIO.successful(v) - def customAction[R](action: => Future[R]): T[R] = DBIO.from(action) + override def noAction[V](v: V): T[V] = DBIO.successful(v) + override def customAction[R](action: => Future[R]): T[R] = DBIO.from(action) } } -- cgit v1.2.3 From f20f755f689978e1fb7f0b454a871feb4d142101 Mon Sep 17 00:00:00 2001 From: Stewart Stewart Date: Fri, 16 Dec 2016 21:00:40 -0500 Subject: move database from object to package --- src/main/scala/xyz/driver/core/database.scala | 139 --------------------- .../scala/xyz/driver/core/database/database.scala | 133 ++++++++++++++++++++ .../scala/xyz/driver/core/database/package.scala | 8 ++ 3 files changed, 141 insertions(+), 139 deletions(-) delete mode 100644 src/main/scala/xyz/driver/core/database.scala create mode 100644 src/main/scala/xyz/driver/core/database/database.scala create mode 100644 src/main/scala/xyz/driver/core/database/package.scala (limited to 'src') diff --git a/src/main/scala/xyz/driver/core/database.scala b/src/main/scala/xyz/driver/core/database.scala deleted file mode 100644 index 255e741..0000000 --- a/src/main/scala/xyz/driver/core/database.scala +++ /dev/null @@ -1,139 +0,0 @@ -package xyz.driver.core - -import scala.concurrent.{ExecutionContext, Future} - -import scalaz.{Monad, ListT, OptionT} -import slick.backend.DatabaseConfig -import slick.dbio.{DBIOAction, NoStream} -import slick.driver.JdbcProfile -import xyz.driver.core.time.Time - -object database { - - trait Database { - val profile: JdbcProfile - val database: JdbcProfile#Backend#Database - } - - object Database { - - def fromConfig(databaseName: String): Database = { - val dbConfig: DatabaseConfig[JdbcProfile] = DatabaseConfig.forConfig(databaseName) - - new Database { - val profile: JdbcProfile = dbConfig.driver - val database: JdbcProfile#Backend#Database = dbConfig.db - } - } - } - - type Schema = { - def create: DBIOAction[Unit, NoStream, slick.dbio.Effect.Schema] - def drop: DBIOAction[Unit, NoStream, slick.dbio.Effect.Schema] - } - - trait ColumnTypes { - val profile: JdbcProfile - import profile.api._ - - implicit def `xyz.driver.core.Id.columnType`[T]: BaseColumnType[Id[T]] - - implicit def `xyz.driver.core.Name.columnType`[T]: BaseColumnType[Name[T]] = - MappedColumnType.base[Name[T], String](_.value, Name[T](_)) - - implicit def `xyz.driver.core.time.Time.columnType`: BaseColumnType[Time] = - MappedColumnType.base[Time, Long](_.millis, Time(_)) - } - - object ColumnTypes { - trait UUID extends ColumnTypes { - import profile.api._ - - override implicit def `xyz.driver.core.Id.columnType`[T] = - MappedColumnType - .base[Id[T], java.util.UUID](id => java.util.UUID.fromString(id.value), uuid => Id[T](uuid.toString)) - } - trait SerialId extends ColumnTypes { - import profile.api._ - - override implicit def `xyz.driver.core.Id.columnType`[T] = - MappedColumnType.base[Id[T], Long](_.value.toLong, serialId => Id[T](serialId.toString)) - } - trait NaturalId extends ColumnTypes { - import profile.api._ - - override implicit def `xyz.driver.core.Id.columnType`[T] = - MappedColumnType.base[Id[T], String](_.value, Id[T](_)) - } - } - - trait DatabaseObject extends ColumnTypes { - - def createTables(): Future[Unit] - def disconnect(): Unit - } - - abstract class DatabaseObjectAdapter extends DatabaseObject { - def createTables(): Future[Unit] = Future.successful(()) - def disconnect(): Unit = {} - } - - trait Dal { - - protected type T[D] - protected implicit val monadT: Monad[T] - - protected def execute[D](operations: T[D]): Future[D] - protected def execute[D](readOperations: OptionT[T, D]): OptionT[Future, D] - protected def execute[D](readOperations: ListT[T, D]): ListT[Future, D] - - protected def noAction[V](v: V): T[V] - protected def customAction[R](action: => Future[R]): T[R] - } - - class FutureDal(executionContext: ExecutionContext) extends Dal { - import scalaz.std.scalaFuture._ - - implicit val exec = executionContext - - override type T[D] = Future[D] - implicit val monadT = implicitly[Monad[Future]] - - def execute[D](operations: T[D]): Future[D] = operations - def execute[D](operations: OptionT[T, D]): OptionT[Future, D] = OptionT(operations.run) - def execute[D](operations: ListT[T, D]): ListT[Future, D] = ListT(operations.run) - def noAction[V](v: V): T[V] = Future.successful(v) - def customAction[R](action: => Future[R]): T[R] = action - } - - class SlickDal(database: Database, executionContext: ExecutionContext) extends Dal { - - import database.profile.api._ - implicit val exec = executionContext - override type T[D] = slick.dbio.DBIO[D] - - implicit protected class QueryOps[+E, U](query: Query[E, U, Seq]) { - def resultT: ListT[T, U] = ListT[T, U](query.result.map(_.toList)) - } - - override implicit val monadT: Monad[T] = new Monad[T] { - override def point[A](a: => A): T[A] = DBIO.successful(a) - override def bind[A, B](fa: T[A])(f: A => T[B]): T[B] = fa.flatMap(f) - } - - override def execute[D](readOperations: T[D]): Future[D] = { - database.database.run(readOperations.transactionally) - } - - override def execute[D](readOperations: OptionT[T, D]): OptionT[Future, D] = { - OptionT(database.database.run(readOperations.run.transactionally)) - } - - override def execute[D](readOperations: ListT[T, D]): ListT[Future, D] = { - ListT(database.database.run(readOperations.run.transactionally)) - } - - override def noAction[V](v: V): T[V] = DBIO.successful(v) - override def customAction[R](action: => Future[R]): T[R] = DBIO.from(action) - } -} diff --git a/src/main/scala/xyz/driver/core/database/database.scala b/src/main/scala/xyz/driver/core/database/database.scala new file mode 100644 index 0000000..55b0708 --- /dev/null +++ b/src/main/scala/xyz/driver/core/database/database.scala @@ -0,0 +1,133 @@ +package xyz.driver.core + +import scala.concurrent.{ExecutionContext, Future} + +import scalaz.{Monad, ListT, OptionT} +import slick.backend.DatabaseConfig +import slick.driver.JdbcProfile +import xyz.driver.core.time.Time + +package database { + + trait Database { + val profile: JdbcProfile + val database: JdbcProfile#Backend#Database + } + + object Database { + + def fromConfig(databaseName: String): Database = { + val dbConfig: DatabaseConfig[JdbcProfile] = DatabaseConfig.forConfig(databaseName) + + new Database { + val profile: JdbcProfile = dbConfig.driver + val database: JdbcProfile#Backend#Database = dbConfig.db + } + } + } + + trait ColumnTypes { + val profile: JdbcProfile + import profile.api._ + + implicit def `xyz.driver.core.Id.columnType`[T]: BaseColumnType[Id[T]] + + implicit def `xyz.driver.core.Name.columnType`[T]: BaseColumnType[Name[T]] = + MappedColumnType.base[Name[T], String](_.value, Name[T](_)) + + implicit def `xyz.driver.core.time.Time.columnType`: BaseColumnType[Time] = + MappedColumnType.base[Time, Long](_.millis, Time(_)) + } + + object ColumnTypes { + trait UUID extends ColumnTypes { + import profile.api._ + + override implicit def `xyz.driver.core.Id.columnType`[T] = + MappedColumnType + .base[Id[T], java.util.UUID](id => java.util.UUID.fromString(id.value), uuid => Id[T](uuid.toString)) + } + trait SerialId extends ColumnTypes { + import profile.api._ + + override implicit def `xyz.driver.core.Id.columnType`[T] = + MappedColumnType.base[Id[T], Long](_.value.toLong, serialId => Id[T](serialId.toString)) + } + trait NaturalId extends ColumnTypes { + import profile.api._ + + override implicit def `xyz.driver.core.Id.columnType`[T] = + MappedColumnType.base[Id[T], String](_.value, Id[T](_)) + } + } + + trait DatabaseObject extends ColumnTypes { + + def createTables(): Future[Unit] + def disconnect(): Unit + } + + abstract class DatabaseObjectAdapter extends DatabaseObject { + def createTables(): Future[Unit] = Future.successful(()) + def disconnect(): Unit = {} + } + + trait Dal { + + protected type T[D] + protected implicit val monadT: Monad[T] + + protected def execute[D](operations: T[D]): Future[D] + protected def execute[D](readOperations: OptionT[T, D]): OptionT[Future, D] + protected def execute[D](readOperations: ListT[T, D]): ListT[Future, D] + + protected def noAction[V](v: V): T[V] + protected def customAction[R](action: => Future[R]): T[R] + } + + class FutureDal(executionContext: ExecutionContext) extends Dal { + import scalaz.std.scalaFuture._ + + implicit val exec = executionContext + + override type T[D] = Future[D] + implicit val monadT = implicitly[Monad[Future]] + + def execute[D](operations: T[D]): Future[D] = operations + def execute[D](operations: OptionT[T, D]): OptionT[Future, D] = OptionT(operations.run) + def execute[D](operations: ListT[T, D]): ListT[Future, D] = ListT(operations.run) + def noAction[V](v: V): T[V] = Future.successful(v) + def customAction[R](action: => Future[R]): T[R] = action + } + + class SlickDal(database: Database, executionContext: ExecutionContext) extends Dal { + + import database.profile.api._ + implicit val exec = executionContext + override type T[D] = slick.dbio.DBIO[D] + + implicit protected class QueryOps[+E, U](query: Query[E, U, Seq]) { + def resultT: ListT[T, U] = ListT[T, U](query.result.map(_.toList)) + } + + override implicit val monadT: Monad[T] = new Monad[T] { + override def point[A](a: => A): T[A] = DBIO.successful(a) + override def bind[A, B](fa: T[A])(f: A => T[B]): T[B] = fa.flatMap(f) + } + + override def execute[D](readOperations: T[D]): Future[D] = { + database.database.run(readOperations.transactionally) + } + + override def execute[D](readOperations: OptionT[T, D]): OptionT[Future, D] = { + OptionT(database.database.run(readOperations.run.transactionally)) + } + + override def execute[D](readOperations: ListT[T, D]): ListT[Future, D] = { + ListT(database.database.run(readOperations.run.transactionally)) + } + + override def noAction[V](v: V): T[V] = DBIO.successful(v) + override def customAction[R](action: => Future[R]): T[R] = DBIO.from(action) + } +} diff --git a/src/main/scala/xyz/driver/core/database/package.scala b/src/main/scala/xyz/driver/core/database/package.scala new file mode 100644 index 0000000..a664cff --- /dev/null +++ b/src/main/scala/xyz/driver/core/database/package.scala @@ -0,0 +1,8 @@ +import slick.dbio.{DBIOAction, NoStream} + +package object database { + type Schema = { + def create: DBIOAction[Unit, NoStream, slick.dbio.Effect.Schema] + def drop: DBIOAction[Unit, NoStream, slick.dbio.Effect.Schema] + } +} -- cgit v1.2.3 From 9bf738070a6588cd731adef5173f586fa52611c8 Mon Sep 17 00:00:00 2001 From: Stewart Stewart Date: Fri, 16 Dec 2016 21:04:50 -0500 Subject: Extract Dal traits into new file --- src/main/scala/xyz/driver/core/database/Dal.scala | 59 ++++++++++++++++++++ .../scala/xyz/driver/core/database/database.scala | 63 +--------------------- 2 files changed, 60 insertions(+), 62 deletions(-) create mode 100644 src/main/scala/xyz/driver/core/database/Dal.scala (limited to 'src') diff --git a/src/main/scala/xyz/driver/core/database/Dal.scala b/src/main/scala/xyz/driver/core/database/Dal.scala new file mode 100644 index 0000000..b476c0d --- /dev/null +++ b/src/main/scala/xyz/driver/core/database/Dal.scala @@ -0,0 +1,59 @@ +package xyz.driver.core.database + +import scala.concurrent.{ExecutionContext, Future} + +import scalaz.{ListT, Monad, OptionT} +import scalaz.std.scalaFuture._ + +trait Dal { + protected type T[D] + protected implicit val monadT: Monad[T] + + protected def execute[D](operations: T[D]): Future[D] + protected def execute[D](readOperations: OptionT[T, D]): OptionT[Future, D] + protected def execute[D](readOperations: ListT[T, D]): ListT[Future, D] + protected def noAction[V](v: V): T[V] + protected def customAction[R](action: => Future[R]): T[R] +} + +class FutureDal(executionContext: ExecutionContext) extends Dal { + implicit val exec = executionContext + override type T[D] = Future[D] + implicit val monadT = implicitly[Monad[Future]] + + def execute[D](operations: T[D]): Future[D] = operations + def execute[D](operations: OptionT[T, D]): OptionT[Future, D] = OptionT(operations.run) + def execute[D](operations: ListT[T, D]): ListT[Future, D] = ListT(operations.run) + def noAction[V](v: V): T[V] = Future.successful(v) + def customAction[R](action: => Future[R]): T[R] = action +} + +class SlickDal(database: Database, executionContext: ExecutionContext) extends Dal { + import database.profile.api._ + implicit val exec = executionContext + override type T[D] = slick.dbio.DBIO[D] + + implicit protected class QueryOps[+E, U](query: Query[E, U, Seq]) { + def resultT: ListT[T, U] = ListT[T, U](query.result.map(_.toList)) + } + + override implicit val monadT: Monad[T] = new Monad[T] { + override def point[A](a: => A): T[A] = DBIO.successful(a) + override def bind[A, B](fa: T[A])(f: A => T[B]): T[B] = fa.flatMap(f) + } + + override def execute[D](readOperations: T[D]): Future[D] = { + database.database.run(readOperations.transactionally) + } + + override def execute[D](readOperations: OptionT[T, D]): OptionT[Future, D] = { + OptionT(database.database.run(readOperations.run.transactionally)) + } + + override def execute[D](readOperations: ListT[T, D]): ListT[Future, D] = { + ListT(database.database.run(readOperations.run.transactionally)) + } + + override def noAction[V](v: V): T[V] = DBIO.successful(v) + override def customAction[R](action: => Future[R]): T[R] = DBIO.from(action) +} diff --git a/src/main/scala/xyz/driver/core/database/database.scala b/src/main/scala/xyz/driver/core/database/database.scala index 55b0708..54518c5 100644 --- a/src/main/scala/xyz/driver/core/database/database.scala +++ b/src/main/scala/xyz/driver/core/database/database.scala @@ -1,8 +1,7 @@ package xyz.driver.core -import scala.concurrent.{ExecutionContext, Future} +import scala.concurrent.Future -import scalaz.{Monad, ListT, OptionT} import slick.backend.DatabaseConfig import slick.driver.JdbcProfile import xyz.driver.core.time.Time @@ -62,7 +61,6 @@ package database { } trait DatabaseObject extends ColumnTypes { - def createTables(): Future[Unit] def disconnect(): Unit } @@ -71,63 +69,4 @@ package database { def createTables(): Future[Unit] = Future.successful(()) def disconnect(): Unit = {} } - - trait Dal { - - protected type T[D] - protected implicit val monadT: Monad[T] - - protected def execute[D](operations: T[D]): Future[D] - protected def execute[D](readOperations: OptionT[T, D]): OptionT[Future, D] - protected def execute[D](readOperations: ListT[T, D]): ListT[Future, D] - - protected def noAction[V](v: V): T[V] - protected def customAction[R](action: => Future[R]): T[R] - } - - class FutureDal(executionContext: ExecutionContext) extends Dal { - import scalaz.std.scalaFuture._ - - implicit val exec = executionContext - - override type T[D] = Future[D] - implicit val monadT = implicitly[Monad[Future]] - - def execute[D](operations: T[D]): Future[D] = operations - def execute[D](operations: OptionT[T, D]): OptionT[Future, D] = OptionT(operations.run) - def execute[D](operations: ListT[T, D]): ListT[Future, D] = ListT(operations.run) - def noAction[V](v: V): T[V] = Future.successful(v) - def customAction[R](action: => Future[R]): T[R] = action - } - - class SlickDal(database: Database, executionContext: ExecutionContext) extends Dal { - - import database.profile.api._ - implicit val exec = executionContext - override type T[D] = slick.dbio.DBIO[D] - - implicit protected class QueryOps[+E, U](query: Query[E, U, Seq]) { - def resultT: ListT[T, U] = ListT[T, U](query.result.map(_.toList)) - } - - override implicit val monadT: Monad[T] = new Monad[T] { - override def point[A](a: => A): T[A] = DBIO.successful(a) - override def bind[A, B](fa: T[A])(f: A => T[B]): T[B] = fa.flatMap(f) - } - - override def execute[D](readOperations: T[D]): Future[D] = { - database.database.run(readOperations.transactionally) - } - - override def execute[D](readOperations: OptionT[T, D]): OptionT[Future, D] = { - OptionT(database.database.run(readOperations.run.transactionally)) - } - - override def execute[D](readOperations: ListT[T, D]): ListT[Future, D] = { - ListT(database.database.run(readOperations.run.transactionally)) - } - - override def noAction[V](v: V): T[V] = DBIO.successful(v) - override def customAction[R](action: => Future[R]): T[R] = DBIO.from(action) - } } -- cgit v1.2.3 From 54857e80c605200f14e62c596bb943ecc296fdd0 Mon Sep 17 00:00:00 2001 From: Stewart Stewart Date: Sat, 17 Dec 2016 00:00:12 -0500 Subject: add date providing simple Date case class --- src/main/scala/xyz/driver/core/date.scala | 37 +++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/main/scala/xyz/driver/core/date.scala (limited to 'src') diff --git a/src/main/scala/xyz/driver/core/date.scala b/src/main/scala/xyz/driver/core/date.scala new file mode 100644 index 0000000..3d38aff --- /dev/null +++ b/src/main/scala/xyz/driver/core/date.scala @@ -0,0 +1,37 @@ +package xyz.driver.core + +import java.util.Calendar + +import scalaz.{@@, Tag} + +object date { + + type Month = Int @@ Month.type + private[date] def tagMonth(value: Int): Month = Tag.of[Month.type](value) + + object Month { + val JANUARY = tagMonth(Calendar.JANUARY) + val FEBRUARY = tagMonth(Calendar.FEBRUARY) + val MARCH = tagMonth(Calendar.MARCH) + val APRIL = tagMonth(Calendar.APRIL) + val MAY = tagMonth(Calendar.MAY) + val JUNE = tagMonth(Calendar.JUNE) + val JULY = tagMonth(Calendar.JULY) + val AUGUST = tagMonth(Calendar.AUGUST) + val SEPTEMBER = tagMonth(Calendar.SEPTEMBER) + val OCTOBER = tagMonth(Calendar.OCTOBER) + val DECEMBER = tagMonth(Calendar.DECEMBER) + } + + final case class Date(year: Int, month: Month, day: Int) { + def iso8601: String = f"$year%04d-${Tag.unwrap(month) + 1}%02d-$day%02d" + } + + object Date { + def fromJavaDate(date: java.util.Date) = { + val cal = Calendar.getInstance() + cal.setTime(date) + Date(cal.get(Calendar.YEAR), tagMonth(cal.get(Calendar.MONTH)), cal.get(Calendar.DAY_OF_MONTH)) + } + } +} -- cgit v1.2.3 From 1cab0ee11c8bcee14103dbd0fb5e350241b9d260 Mon Sep 17 00:00:00 2001 From: Stewart Stewart Date: Sat, 17 Dec 2016 00:49:52 -0500 Subject: add database-date integration --- src/main/scala/xyz/driver/core/database.scala | 4 ++++ src/main/scala/xyz/driver/core/date.scala | 8 ++++++++ 2 files changed, 12 insertions(+) (limited to 'src') diff --git a/src/main/scala/xyz/driver/core/database.scala b/src/main/scala/xyz/driver/core/database.scala index a82e345..ee87784 100644 --- a/src/main/scala/xyz/driver/core/database.scala +++ b/src/main/scala/xyz/driver/core/database.scala @@ -4,6 +4,7 @@ import slick.backend.DatabaseConfig import slick.dbio.{DBIOAction, NoStream} import slick.driver.JdbcProfile import xyz.driver.core.time.Time +import xyz.driver.core.date.Date import scala.concurrent.{ExecutionContext, Future} import scalaz.Monad @@ -43,6 +44,9 @@ object database { implicit def `xyz.driver.core.time.Time.columnType`: BaseColumnType[Time] = MappedColumnType.base[Time, Long](_.millis, Time(_)) + + implicit def `xyz.driver.core.time.Date.columnType`: BaseColumnType[Date] = + MappedColumnType.base[Date, java.sql.Date](_.toJavaSqlDate, Date.fromJavaDate(_)) } object ColumnTypes { diff --git a/src/main/scala/xyz/driver/core/date.scala b/src/main/scala/xyz/driver/core/date.scala index 3d38aff..05d139d 100644 --- a/src/main/scala/xyz/driver/core/date.scala +++ b/src/main/scala/xyz/driver/core/date.scala @@ -25,6 +25,14 @@ object date { final case class Date(year: Int, month: Month, day: Int) { def iso8601: String = f"$year%04d-${Tag.unwrap(month) + 1}%02d-$day%02d" + def toJavaSqlDate = new java.sql.Date(toJavaDate.getTime) + def toJavaDate: java.util.Date = { + val cal = Calendar.getInstance() + cal.set(Calendar.YEAR, year - 1900) + cal.set(Calendar.MONTH, Tag.unwrap(month)) + cal.set(Calendar.DAY_OF_MONTH, day) + cal.getTime + } } object Date { -- cgit v1.2.3 From 244ab76cc235fd2ae827f038bde8f049c0d9af50 Mon Sep 17 00:00:00 2001 From: Stewart Stewart Date: Sat, 17 Dec 2016 01:38:23 -0500 Subject: add Date generator --- src/main/scala/xyz/driver/core/generators.scala | 3 +++ src/main/scala/xyz/driver/core/time.scala | 2 ++ 2 files changed, 5 insertions(+) (limited to 'src') diff --git a/src/main/scala/xyz/driver/core/generators.scala b/src/main/scala/xyz/driver/core/generators.scala index c61cb94..0db18a1 100644 --- a/src/main/scala/xyz/driver/core/generators.scala +++ b/src/main/scala/xyz/driver/core/generators.scala @@ -4,6 +4,7 @@ import java.math.MathContext import xyz.driver.core.revision.Revision import xyz.driver.core.time.{Time, TimeRange} +import xyz.driver.core.date.Date import scala.reflect.ClassTag import scala.util.Random @@ -55,6 +56,8 @@ object generators { Time(scala.math.max(oneTime.millis, anotherTime.millis))) } + def nextDate(): Date = nextTime.toDate + def nextBigDecimal(multiplier: Double = 1000000.00, precision: Int = 2): BigDecimal = BigDecimal(multiplier * nextDouble, new MathContext(precision)) diff --git a/src/main/scala/xyz/driver/core/time.scala b/src/main/scala/xyz/driver/core/time.scala index 625d6a2..9d3f655 100644 --- a/src/main/scala/xyz/driver/core/time.scala +++ b/src/main/scala/xyz/driver/core/time.scala @@ -26,6 +26,8 @@ object time { def isAfter(anotherTime: Time): Boolean = millis > anotherTime.millis def advanceBy(duration: Duration): Time = Time(millis + duration.toMillis) + + def toDate: date.Date = date.Date.fromJavaDate(new java.util.Date(millis)) } final case class TimeRange(start: Time, end: Time) { -- cgit v1.2.3 From bb7e18fe7998556086863acc0957056079363d4a Mon Sep 17 00:00:00 2001 From: Stewart Stewart Date: Sat, 17 Dec 2016 01:39:12 -0500 Subject: use core.tagging for months --- src/main/scala/xyz/driver/core/core.scala | 5 +++++ src/main/scala/xyz/driver/core/date.scala | 8 +++----- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/main/scala/xyz/driver/core/core.scala b/src/main/scala/xyz/driver/core/core.scala index 8ae9122..2b61689 100644 --- a/src/main/scala/xyz/driver/core/core.scala +++ b/src/main/scala/xyz/driver/core/core.scala @@ -20,6 +20,11 @@ package object core { resource.close() } } + + object tagging { + private[core] trait Tagged[+V, +Tag] + } + type @@[+V, +Tag] = V with tagging.Tagged[V, Tag] } package core { diff --git a/src/main/scala/xyz/driver/core/date.scala b/src/main/scala/xyz/driver/core/date.scala index 05d139d..b423585 100644 --- a/src/main/scala/xyz/driver/core/date.scala +++ b/src/main/scala/xyz/driver/core/date.scala @@ -2,12 +2,10 @@ package xyz.driver.core import java.util.Calendar -import scalaz.{@@, Tag} - object date { type Month = Int @@ Month.type - private[date] def tagMonth(value: Int): Month = Tag.of[Month.type](value) + private[date] def tagMonth(value: Int): Month = value.asInstanceOf[Month] object Month { val JANUARY = tagMonth(Calendar.JANUARY) @@ -24,12 +22,12 @@ object date { } final case class Date(year: Int, month: Month, day: Int) { - def iso8601: String = f"$year%04d-${Tag.unwrap(month) + 1}%02d-$day%02d" + def iso8601: String = f"$year%04d-${month + 1}%02d-$day%02d" def toJavaSqlDate = new java.sql.Date(toJavaDate.getTime) def toJavaDate: java.util.Date = { val cal = Calendar.getInstance() cal.set(Calendar.YEAR, year - 1900) - cal.set(Calendar.MONTH, Tag.unwrap(month)) + cal.set(Calendar.MONTH, month) cal.set(Calendar.DAY_OF_MONTH, day) cal.getTime } -- cgit v1.2.3 From 53d04d4255489bd5802dc91d9dbebddd206d630b Mon Sep 17 00:00:00 2001 From: Stewart Stewart Date: Sat, 17 Dec 2016 02:11:18 -0500 Subject: add json format for date (ISO) --- src/main/scala/xyz/driver/core/date.scala | 7 ++++++- src/main/scala/xyz/driver/core/json.scala | 17 +++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/main/scala/xyz/driver/core/date.scala b/src/main/scala/xyz/driver/core/date.scala index b423585..0cf8986 100644 --- a/src/main/scala/xyz/driver/core/date.scala +++ b/src/main/scala/xyz/driver/core/date.scala @@ -23,7 +23,7 @@ object date { final case class Date(year: Int, month: Month, day: Int) { def iso8601: String = f"$year%04d-${month + 1}%02d-$day%02d" - def toJavaSqlDate = new java.sql.Date(toJavaDate.getTime) + def toJavaSqlDate = new java.sql.Date(toJavaDate.getTime) def toJavaDate: java.util.Date = { val cal = Calendar.getInstance() cal.set(Calendar.YEAR, year - 1900) @@ -34,6 +34,11 @@ object date { } object Date { + def parseIso(iso: String): Option[Date] = { + util.Try(iso.split("-").map(_.toInt)).toOption collect { + case Array(year, month, day) => Date(year, tagMonth(month), day) + } + } def fromJavaDate(date: java.util.Date) = { val cal = Calendar.getInstance() cal.setTime(date) diff --git a/src/main/scala/xyz/driver/core/json.scala b/src/main/scala/xyz/driver/core/json.scala index 277543b..ecd7cce 100644 --- a/src/main/scala/xyz/driver/core/json.scala +++ b/src/main/scala/xyz/driver/core/json.scala @@ -7,6 +7,7 @@ import akka.http.scaladsl.unmarshalling.Unmarshaller import spray.json.{DeserializationException, JsNumber, _} import xyz.driver.core.revision.Revision import xyz.driver.core.time.Time +import xyz.driver.core.date.Date import scala.reflect.runtime.universe._ @@ -66,6 +67,22 @@ object json { } } + implicit val dateFormat = new RootJsonFormat[Date] { + def write(date: Date) = JsObject("calendarDate" -> JsString(date.iso8601)) + + def read(value: JsValue): Date = value match { + case JsObject(fields) => + fields + .get("calendarDate") + .flatMap { + case JsString(iso) => Date.parseIso(iso) + case _ => None + } + .getOrElse(throw DeserializationException("Date expects YYYY-MM-DD")) + case _ => throw DeserializationException("Date expects YYYY-MM-DD") + } + } + def RevisionInPath[T]: PathMatcher1[Revision[T]] = PathMatcher("""[\da-fA-F]{8}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{12}""".r) flatMap { string => Some(Revision[T](string)) -- cgit v1.2.3 From 2f6a2d763732285dc1cffb0d3a435a9e9c96cbd2 Mon Sep 17 00:00:00 2001 From: Stewart Stewart Date: Mon, 19 Dec 2016 16:25:10 -0500 Subject: serialize date to json as object with three fields --- src/main/scala/xyz/driver/core/date.scala | 8 +------- src/main/scala/xyz/driver/core/json.scala | 20 ++++++-------------- 2 files changed, 7 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/main/scala/xyz/driver/core/date.scala b/src/main/scala/xyz/driver/core/date.scala index 0cf8986..b954749 100644 --- a/src/main/scala/xyz/driver/core/date.scala +++ b/src/main/scala/xyz/driver/core/date.scala @@ -5,7 +5,7 @@ import java.util.Calendar object date { type Month = Int @@ Month.type - private[date] def tagMonth(value: Int): Month = value.asInstanceOf[Month] + private[core] def tagMonth(value: Int): Month = value.asInstanceOf[Month] object Month { val JANUARY = tagMonth(Calendar.JANUARY) @@ -22,7 +22,6 @@ object date { } final case class Date(year: Int, month: Month, day: Int) { - def iso8601: String = f"$year%04d-${month + 1}%02d-$day%02d" def toJavaSqlDate = new java.sql.Date(toJavaDate.getTime) def toJavaDate: java.util.Date = { val cal = Calendar.getInstance() @@ -34,11 +33,6 @@ object date { } object Date { - def parseIso(iso: String): Option[Date] = { - util.Try(iso.split("-").map(_.toInt)).toOption collect { - case Array(year, month, day) => Date(year, tagMonth(month), day) - } - } def fromJavaDate(date: java.util.Date) = { val cal = Calendar.getInstance() cal.setTime(date) diff --git a/src/main/scala/xyz/driver/core/json.scala b/src/main/scala/xyz/driver/core/json.scala index ecd7cce..fee7341 100644 --- a/src/main/scala/xyz/driver/core/json.scala +++ b/src/main/scala/xyz/driver/core/json.scala @@ -7,7 +7,7 @@ import akka.http.scaladsl.unmarshalling.Unmarshaller import spray.json.{DeserializationException, JsNumber, _} import xyz.driver.core.revision.Revision import xyz.driver.core.time.Time -import xyz.driver.core.date.Date +import xyz.driver.core.date.Month import scala.reflect.runtime.universe._ @@ -67,19 +67,11 @@ object json { } } - implicit val dateFormat = new RootJsonFormat[Date] { - def write(date: Date) = JsObject("calendarDate" -> JsString(date.iso8601)) - - def read(value: JsValue): Date = value match { - case JsObject(fields) => - fields - .get("calendarDate") - .flatMap { - case JsString(iso) => Date.parseIso(iso) - case _ => None - } - .getOrElse(throw DeserializationException("Date expects YYYY-MM-DD")) - case _ => throw DeserializationException("Date expects YYYY-MM-DD") + implicit val dateFormat = new RootJsonFormat[Month] { + def write(month: Month) = JsNumber(month) + def read(value: JsValue): Month = value match { + case JsNumber(month) if 0 <= month && month <= 11 => date.tagMonth(month.toInt) + case _ => throw DeserializationException("Month is a 0-based number") } } -- cgit v1.2.3 From 514c334dcd3a8b98f41610709b9cafd761899778 Mon Sep 17 00:00:00 2001 From: Stewart Stewart Date: Mon, 19 Dec 2016 18:09:52 -0500 Subject: move java date helpers out of date.Date --- .../scala/xyz/driver/core/database/database.scala | 2 +- .../scala/xyz/driver/core/database/package.scala | 17 ++++++++++++++ src/main/scala/xyz/driver/core/date.scala | 26 +++++++++------------- src/main/scala/xyz/driver/core/time.scala | 2 +- 4 files changed, 29 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/main/scala/xyz/driver/core/database/database.scala b/src/main/scala/xyz/driver/core/database/database.scala index 3db9c9e..a8aec63 100644 --- a/src/main/scala/xyz/driver/core/database/database.scala +++ b/src/main/scala/xyz/driver/core/database/database.scala @@ -39,7 +39,7 @@ package database { MappedColumnType.base[Time, Long](_.millis, Time(_)) implicit def `xyz.driver.core.time.Date.columnType`: BaseColumnType[Date] = - MappedColumnType.base[Date, java.sql.Date](_.toJavaSqlDate, Date.fromJavaDate(_)) + MappedColumnType.base[Date, java.sql.Date](dateToSqlDate(_), sqlDateToDate(_)) } object ColumnTypes { diff --git a/src/main/scala/xyz/driver/core/database/package.scala b/src/main/scala/xyz/driver/core/database/package.scala index a664cff..295e556 100644 --- a/src/main/scala/xyz/driver/core/database/package.scala +++ b/src/main/scala/xyz/driver/core/database/package.scala @@ -1,8 +1,25 @@ +package xyz.driver.core + +import java.sql.{Date => SqlDate} +import java.util.Calendar + +import date.{Date, javaDateToDate} import slick.dbio.{DBIOAction, NoStream} + package object database { type Schema = { def create: DBIOAction[Unit, NoStream, slick.dbio.Effect.Schema] def drop: DBIOAction[Unit, NoStream, slick.dbio.Effect.Schema] } + + private[database] def sqlDateToDate(date: SqlDate): Date = javaDateToDate(date) + + private[database] def dateToSqlDate(date: Date): SqlDate = { + val cal = Calendar.getInstance() + cal.set(Calendar.YEAR, date.year - 1900) + cal.set(Calendar.MONTH, date.month) + cal.set(Calendar.DAY_OF_MONTH, date.day) + new SqlDate(cal.getTime.getTime) + } } diff --git a/src/main/scala/xyz/driver/core/date.scala b/src/main/scala/xyz/driver/core/date.scala index b954749..476cd13 100644 --- a/src/main/scala/xyz/driver/core/date.scala +++ b/src/main/scala/xyz/driver/core/date.scala @@ -21,22 +21,16 @@ object date { val DECEMBER = tagMonth(Calendar.DECEMBER) } - final case class Date(year: Int, month: Month, day: Int) { - def toJavaSqlDate = new java.sql.Date(toJavaDate.getTime) - def toJavaDate: java.util.Date = { - val cal = Calendar.getInstance() - cal.set(Calendar.YEAR, year - 1900) - cal.set(Calendar.MONTH, month) - cal.set(Calendar.DAY_OF_MONTH, day) - cal.getTime - } - } + final case class Date(year: Int, month: Month, day: Int) - object Date { - def fromJavaDate(date: java.util.Date) = { - val cal = Calendar.getInstance() - cal.setTime(date) - Date(cal.get(Calendar.YEAR), tagMonth(cal.get(Calendar.MONTH)), cal.get(Calendar.DAY_OF_MONTH)) - } + private[core] def javaDateToDate(javaDate: java.util.Date): Date = { + val cal = Calendar.getInstance() + cal.setTime(javaDate) + Date( + cal.get(Calendar.YEAR), + date.tagMonth(cal.get(Calendar.MONTH)), + cal.get(Calendar.DAY_OF_MONTH)) } + + } diff --git a/src/main/scala/xyz/driver/core/time.scala b/src/main/scala/xyz/driver/core/time.scala index 9d3f655..6d76939 100644 --- a/src/main/scala/xyz/driver/core/time.scala +++ b/src/main/scala/xyz/driver/core/time.scala @@ -27,7 +27,7 @@ object time { def advanceBy(duration: Duration): Time = Time(millis + duration.toMillis) - def toDate: date.Date = date.Date.fromJavaDate(new java.util.Date(millis)) + def toDate: date.Date = date.javaDateToDate(new java.util.Date(millis)) } final case class TimeRange(start: Time, end: Time) { -- cgit v1.2.3 From d63fd7ef92b67dec5ea72f26d73d56cec676bd82 Mon Sep 17 00:00:00 2001 From: Stewart Stewart Date: Mon, 19 Dec 2016 18:43:07 -0500 Subject: scalafmt --- src/main/scala/xyz/driver/core/database/package.scala | 1 - src/main/scala/xyz/driver/core/date.scala | 6 +----- src/main/scala/xyz/driver/core/json.scala | 2 +- 3 files changed, 2 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/main/scala/xyz/driver/core/database/package.scala b/src/main/scala/xyz/driver/core/database/package.scala index 295e556..2041b85 100644 --- a/src/main/scala/xyz/driver/core/database/package.scala +++ b/src/main/scala/xyz/driver/core/database/package.scala @@ -6,7 +6,6 @@ import java.util.Calendar import date.{Date, javaDateToDate} import slick.dbio.{DBIOAction, NoStream} - package object database { type Schema = { def create: DBIOAction[Unit, NoStream, slick.dbio.Effect.Schema] diff --git a/src/main/scala/xyz/driver/core/date.scala b/src/main/scala/xyz/driver/core/date.scala index 476cd13..437729f 100644 --- a/src/main/scala/xyz/driver/core/date.scala +++ b/src/main/scala/xyz/driver/core/date.scala @@ -26,11 +26,7 @@ object date { private[core] def javaDateToDate(javaDate: java.util.Date): Date = { val cal = Calendar.getInstance() cal.setTime(javaDate) - Date( - cal.get(Calendar.YEAR), - date.tagMonth(cal.get(Calendar.MONTH)), - cal.get(Calendar.DAY_OF_MONTH)) + Date(cal.get(Calendar.YEAR), date.tagMonth(cal.get(Calendar.MONTH)), cal.get(Calendar.DAY_OF_MONTH)) } - } diff --git a/src/main/scala/xyz/driver/core/json.scala b/src/main/scala/xyz/driver/core/json.scala index fee7341..c51e855 100644 --- a/src/main/scala/xyz/driver/core/json.scala +++ b/src/main/scala/xyz/driver/core/json.scala @@ -71,7 +71,7 @@ object json { def write(month: Month) = JsNumber(month) def read(value: JsValue): Month = value match { case JsNumber(month) if 0 <= month && month <= 11 => date.tagMonth(month.toInt) - case _ => throw DeserializationException("Month is a 0-based number") + case _ => throw DeserializationException("Month is a 0-based number") } } -- cgit v1.2.3 From 548338adc1691ea667f7941bfc65f8a6d6ce2c0e Mon Sep 17 00:00:00 2001 From: Stewart Stewart Date: Mon, 19 Dec 2016 19:07:31 -0500 Subject: add timezone to time => date conversion --- src/main/scala/xyz/driver/core/database/package.scala | 1 + src/main/scala/xyz/driver/core/generators.scala | 2 +- src/main/scala/xyz/driver/core/time.scala | 6 +++++- 3 files changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/main/scala/xyz/driver/core/database/package.scala b/src/main/scala/xyz/driver/core/database/package.scala index 2041b85..7d9aecb 100644 --- a/src/main/scala/xyz/driver/core/database/package.scala +++ b/src/main/scala/xyz/driver/core/database/package.scala @@ -7,6 +7,7 @@ import date.{Date, javaDateToDate} import slick.dbio.{DBIOAction, NoStream} package object database { + type Schema = { def create: DBIOAction[Unit, NoStream, slick.dbio.Effect.Schema] def drop: DBIOAction[Unit, NoStream, slick.dbio.Effect.Schema] diff --git a/src/main/scala/xyz/driver/core/generators.scala b/src/main/scala/xyz/driver/core/generators.scala index 0db18a1..d532ae3 100644 --- a/src/main/scala/xyz/driver/core/generators.scala +++ b/src/main/scala/xyz/driver/core/generators.scala @@ -56,7 +56,7 @@ object generators { Time(scala.math.max(oneTime.millis, anotherTime.millis))) } - def nextDate(): Date = nextTime.toDate + def nextDate(): Date = nextTime.toDate(java.util.TimeZone.getTimeZone("UTC")) def nextBigDecimal(multiplier: Double = 1000000.00, precision: Int = 2): BigDecimal = BigDecimal(multiplier * nextDouble, new MathContext(precision)) diff --git a/src/main/scala/xyz/driver/core/time.scala b/src/main/scala/xyz/driver/core/time.scala index 6d76939..cdeb3a6 100644 --- a/src/main/scala/xyz/driver/core/time.scala +++ b/src/main/scala/xyz/driver/core/time.scala @@ -27,7 +27,11 @@ object time { def advanceBy(duration: Duration): Time = Time(millis + duration.toMillis) - def toDate: date.Date = date.javaDateToDate(new java.util.Date(millis)) + def toDate(timezone: TimeZone): date.Date = { + val cal = java.util.Calendar.getInstance(timezone) + cal.setTimeInMillis(millis) + date.javaDateToDate(cal.getTime()) + } } final case class TimeRange(start: Time, end: Time) { -- cgit v1.2.3 From a32427bca195ef4eb1cc0f326d27b990402e6c63 Mon Sep 17 00:00:00 2001 From: Stewart Stewart Date: Mon, 19 Dec 2016 20:37:40 -0500 Subject: update sbt-settings (for scalaz 2.7.8 with `mapT`) --- project/plugins.sbt | 2 +- src/main/scala/xyz/driver/core/database/Dal.scala | 20 ++++---------------- 2 files changed, 5 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/project/plugins.sbt b/project/plugins.sbt index 981c484..a4722e8 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,4 +1,4 @@ resolvers += "releases" at "https://drivergrp.jfrog.io/drivergrp/releases" credentials += Credentials("Artifactory Realm", "drivergrp.jfrog.io", "sbt-publisher", "ANC-d8X-Whm-USS") -addSbtPlugin("xyz.driver" % "sbt-settings" % "0.5.47") +addSbtPlugin("xyz.driver" % "sbt-settings" % "0.5.48") diff --git a/src/main/scala/xyz/driver/core/database/Dal.scala b/src/main/scala/xyz/driver/core/database/Dal.scala index b476c0d..e920392 100644 --- a/src/main/scala/xyz/driver/core/database/Dal.scala +++ b/src/main/scala/xyz/driver/core/database/Dal.scala @@ -2,7 +2,7 @@ package xyz.driver.core.database import scala.concurrent.{ExecutionContext, Future} -import scalaz.{ListT, Monad, OptionT} +import scalaz.{ListT, Monad} import scalaz.std.scalaFuture._ trait Dal { @@ -10,8 +10,6 @@ trait Dal { protected implicit val monadT: Monad[T] protected def execute[D](operations: T[D]): Future[D] - protected def execute[D](readOperations: OptionT[T, D]): OptionT[Future, D] - protected def execute[D](readOperations: ListT[T, D]): ListT[Future, D] protected def noAction[V](v: V): T[V] protected def customAction[R](action: => Future[R]): T[R] } @@ -21,11 +19,9 @@ class FutureDal(executionContext: ExecutionContext) extends Dal { override type T[D] = Future[D] implicit val monadT = implicitly[Monad[Future]] - def execute[D](operations: T[D]): Future[D] = operations - def execute[D](operations: OptionT[T, D]): OptionT[Future, D] = OptionT(operations.run) - def execute[D](operations: ListT[T, D]): ListT[Future, D] = ListT(operations.run) - def noAction[V](v: V): T[V] = Future.successful(v) - def customAction[R](action: => Future[R]): T[R] = action + def execute[D](operations: T[D]): Future[D] = operations + def noAction[V](v: V): T[V] = Future.successful(v) + def customAction[R](action: => Future[R]): T[R] = action } class SlickDal(database: Database, executionContext: ExecutionContext) extends Dal { @@ -46,14 +42,6 @@ class SlickDal(database: Database, executionContext: ExecutionContext) extends D database.database.run(readOperations.transactionally) } - override def execute[D](readOperations: OptionT[T, D]): OptionT[Future, D] = { - OptionT(database.database.run(readOperations.run.transactionally)) - } - - override def execute[D](readOperations: ListT[T, D]): ListT[Future, D] = { - ListT(database.database.run(readOperations.run.transactionally)) - } - override def noAction[V](v: V): T[V] = DBIO.successful(v) override def customAction[R](action: => Future[R]): T[R] = DBIO.from(action) } -- cgit v1.2.3 From f6b6847c226a0a18a250ead6557f8df75309f079 Mon Sep 17 00:00:00 2001 From: Stewart Stewart Date: Mon, 19 Dec 2016 20:57:32 -0500 Subject: remove overloaded Dal#execute (can use mapT instead) --- src/main/scala/xyz/driver/core/database/Dal.scala | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/main/scala/xyz/driver/core/database/Dal.scala b/src/main/scala/xyz/driver/core/database/Dal.scala index e920392..b476c0d 100644 --- a/src/main/scala/xyz/driver/core/database/Dal.scala +++ b/src/main/scala/xyz/driver/core/database/Dal.scala @@ -2,7 +2,7 @@ package xyz.driver.core.database import scala.concurrent.{ExecutionContext, Future} -import scalaz.{ListT, Monad} +import scalaz.{ListT, Monad, OptionT} import scalaz.std.scalaFuture._ trait Dal { @@ -10,6 +10,8 @@ trait Dal { protected implicit val monadT: Monad[T] protected def execute[D](operations: T[D]): Future[D] + protected def execute[D](readOperations: OptionT[T, D]): OptionT[Future, D] + protected def execute[D](readOperations: ListT[T, D]): ListT[Future, D] protected def noAction[V](v: V): T[V] protected def customAction[R](action: => Future[R]): T[R] } @@ -19,9 +21,11 @@ class FutureDal(executionContext: ExecutionContext) extends Dal { override type T[D] = Future[D] implicit val monadT = implicitly[Monad[Future]] - def execute[D](operations: T[D]): Future[D] = operations - def noAction[V](v: V): T[V] = Future.successful(v) - def customAction[R](action: => Future[R]): T[R] = action + def execute[D](operations: T[D]): Future[D] = operations + def execute[D](operations: OptionT[T, D]): OptionT[Future, D] = OptionT(operations.run) + def execute[D](operations: ListT[T, D]): ListT[Future, D] = ListT(operations.run) + def noAction[V](v: V): T[V] = Future.successful(v) + def customAction[R](action: => Future[R]): T[R] = action } class SlickDal(database: Database, executionContext: ExecutionContext) extends Dal { @@ -42,6 +46,14 @@ class SlickDal(database: Database, executionContext: ExecutionContext) extends D database.database.run(readOperations.transactionally) } + override def execute[D](readOperations: OptionT[T, D]): OptionT[Future, D] = { + OptionT(database.database.run(readOperations.run.transactionally)) + } + + override def execute[D](readOperations: ListT[T, D]): ListT[Future, D] = { + ListT(database.database.run(readOperations.run.transactionally)) + } + override def noAction[V](v: V): T[V] = DBIO.successful(v) override def customAction[R](action: => Future[R]): T[R] = DBIO.from(action) } -- cgit v1.2.3 From 0ce42d864b4d79902bb661743682c913faae0df0 Mon Sep 17 00:00:00 2001 From: Stewart Stewart Date: Mon, 19 Dec 2016 21:28:21 -0500 Subject: fix name of month json formatter --- src/main/scala/xyz/driver/core/json.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/main/scala/xyz/driver/core/json.scala b/src/main/scala/xyz/driver/core/json.scala index c51e855..a3894db 100644 --- a/src/main/scala/xyz/driver/core/json.scala +++ b/src/main/scala/xyz/driver/core/json.scala @@ -67,7 +67,7 @@ object json { } } - implicit val dateFormat = new RootJsonFormat[Month] { + implicit val monthFormat = new RootJsonFormat[Month] { def write(month: Month) = JsNumber(month) def read(value: JsValue): Month = value match { case JsNumber(month) if 0 <= month && month <= 11 => date.tagMonth(month.toInt) -- cgit v1.2.3 From d514c186b505257fbfd631d5a4b707150aa78b7e Mon Sep 17 00:00:00 2001 From: Stewart Stewart Date: Mon, 19 Dec 2016 21:40:02 -0500 Subject: add json formatter for date --- src/main/scala/xyz/driver/core/json.scala | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/main/scala/xyz/driver/core/json.scala b/src/main/scala/xyz/driver/core/json.scala index a3894db..4007e78 100644 --- a/src/main/scala/xyz/driver/core/json.scala +++ b/src/main/scala/xyz/driver/core/json.scala @@ -7,12 +7,14 @@ import akka.http.scaladsl.unmarshalling.Unmarshaller import spray.json.{DeserializationException, JsNumber, _} import xyz.driver.core.revision.Revision import xyz.driver.core.time.Time -import xyz.driver.core.date.Month +import xyz.driver.core.date.{Date, Month} import scala.reflect.runtime.universe._ object json { + import DefaultJsonProtocol._ + def IdInPath[T]: PathMatcher1[Id[T]] = new PathMatcher1[Id[T]] { def apply(path: Path) = path match { case Path.Segment(segment, tail) => Matched(tail, Tuple1(Id[T](segment))) @@ -75,6 +77,8 @@ object json { } } + implicit val dateFormat = jsonFormat3(Date) + def RevisionInPath[T]: PathMatcher1[Revision[T]] = PathMatcher("""[\da-fA-F]{8}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{4}-[\da-fA-F]{12}""".r) flatMap { string => Some(Revision[T](string)) -- cgit v1.2.3 From e0a4590247199fb4f9ad49ea6520f104b2622c51 Mon Sep 17 00:00:00 2001 From: Stewart Stewart Date: Mon, 19 Dec 2016 21:45:51 -0500 Subject: remove overloaded Dal#execute (can use mapT instead) --- src/main/scala/xyz/driver/core/database/Dal.scala | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/main/scala/xyz/driver/core/database/Dal.scala b/src/main/scala/xyz/driver/core/database/Dal.scala index b476c0d..e920392 100644 --- a/src/main/scala/xyz/driver/core/database/Dal.scala +++ b/src/main/scala/xyz/driver/core/database/Dal.scala @@ -2,7 +2,7 @@ package xyz.driver.core.database import scala.concurrent.{ExecutionContext, Future} -import scalaz.{ListT, Monad, OptionT} +import scalaz.{ListT, Monad} import scalaz.std.scalaFuture._ trait Dal { @@ -10,8 +10,6 @@ trait Dal { protected implicit val monadT: Monad[T] protected def execute[D](operations: T[D]): Future[D] - protected def execute[D](readOperations: OptionT[T, D]): OptionT[Future, D] - protected def execute[D](readOperations: ListT[T, D]): ListT[Future, D] protected def noAction[V](v: V): T[V] protected def customAction[R](action: => Future[R]): T[R] } @@ -21,11 +19,9 @@ class FutureDal(executionContext: ExecutionContext) extends Dal { override type T[D] = Future[D] implicit val monadT = implicitly[Monad[Future]] - def execute[D](operations: T[D]): Future[D] = operations - def execute[D](operations: OptionT[T, D]): OptionT[Future, D] = OptionT(operations.run) - def execute[D](operations: ListT[T, D]): ListT[Future, D] = ListT(operations.run) - def noAction[V](v: V): T[V] = Future.successful(v) - def customAction[R](action: => Future[R]): T[R] = action + def execute[D](operations: T[D]): Future[D] = operations + def noAction[V](v: V): T[V] = Future.successful(v) + def customAction[R](action: => Future[R]): T[R] = action } class SlickDal(database: Database, executionContext: ExecutionContext) extends Dal { @@ -46,14 +42,6 @@ class SlickDal(database: Database, executionContext: ExecutionContext) extends D database.database.run(readOperations.transactionally) } - override def execute[D](readOperations: OptionT[T, D]): OptionT[Future, D] = { - OptionT(database.database.run(readOperations.run.transactionally)) - } - - override def execute[D](readOperations: ListT[T, D]): ListT[Future, D] = { - ListT(database.database.run(readOperations.run.transactionally)) - } - override def noAction[V](v: V): T[V] = DBIO.successful(v) override def customAction[R](action: => Future[R]): T[R] = DBIO.from(action) } -- cgit v1.2.3 From fd050fa250991c195c4c81e949636402e94c28b2 Mon Sep 17 00:00:00 2001 From: Stewart Stewart Date: Mon, 19 Dec 2016 23:06:04 -0500 Subject: clarify month deserialization error message --- src/main/scala/xyz/driver/core/json.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/main/scala/xyz/driver/core/json.scala b/src/main/scala/xyz/driver/core/json.scala index 4007e78..5833383 100644 --- a/src/main/scala/xyz/driver/core/json.scala +++ b/src/main/scala/xyz/driver/core/json.scala @@ -73,7 +73,7 @@ object json { def write(month: Month) = JsNumber(month) def read(value: JsValue): Month = value match { case JsNumber(month) if 0 <= month && month <= 11 => date.tagMonth(month.toInt) - case _ => throw DeserializationException("Month is a 0-based number") + case _ => throw DeserializationException("Expected a number from 0 to 11") } } -- cgit v1.2.3 From 0672ad697cbf2f66baabd8c2aa0e2de966240f88 Mon Sep 17 00:00:00 2001 From: Stewart Stewart Date: Tue, 20 Dec 2016 00:17:55 -0500 Subject: add tests for Date json format --- src/test/scala/xyz/driver/core/JsonTest.scala | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'src') diff --git a/src/test/scala/xyz/driver/core/JsonTest.scala b/src/test/scala/xyz/driver/core/JsonTest.scala index eb8d5d8..821b162 100644 --- a/src/test/scala/xyz/driver/core/JsonTest.scala +++ b/src/test/scala/xyz/driver/core/JsonTest.scala @@ -42,6 +42,22 @@ class JsonTest extends FlatSpec with Matchers { parsedTime should be(referenceTime) } + "Json format for Date" should "read and write correct JSON" in { + import date._ + + val referenceDate = Date(1941, Month.DECEMBER, 7) + + val writtenJson = json.dateFormat.write(referenceDate) + writtenJson.prettyPrint should be("""|{ + | "year": 1941, + | "month": 11, + | "day": 7 + |}""".stripMargin) + + val parsedDate = json.dateFormat.read(writtenJson) + parsedDate should be(referenceDate) + } + "Json format for Revision" should "read and write correct JSON" in { val referenceRevision = Revision[String]("037e2ec0-8901-44ac-8e53-6d39f6479db4") -- cgit v1.2.3 From f0edf2510e2cf67afdf598824a02ff03e6726f62 Mon Sep 17 00:00:00 2001 From: Stewart Stewart Date: Tue, 20 Dec 2016 01:13:05 -0500 Subject: add tests for time/date conversions --- src/test/scala/xyz/driver/core/CoreTest.scala | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'src') diff --git a/src/test/scala/xyz/driver/core/CoreTest.scala b/src/test/scala/xyz/driver/core/CoreTest.scala index da9fd9a..e210887 100644 --- a/src/test/scala/xyz/driver/core/CoreTest.scala +++ b/src/test/scala/xyz/driver/core/CoreTest.scala @@ -60,6 +60,24 @@ class CoreTest extends FlatSpec with Matchers with MockitoSugar { (y2 === y) should be(true) } + "Time" should "use TimeZone correctly when converting to Date" in { + + import time._ + + val EST = java.util.TimeZone.getTimeZone("EST") + val PST = java.util.TimeZone.getTimeZone("PST") + + val timestamp = { + import java.util.Calendar + val cal = Calendar.getInstance(EST) + cal.set(Calendar.HOUR_OF_DAY, 1) + Time(cal.getTime().getTime()) + } + + textualDate(EST)(timestamp) should not be textualDate(PST)(timestamp) + timestamp.toDate(EST) should not be timestamp.toDate(PST) + } + "Name" should "have equality and ordering working correctly" in { (Name[String]("foo") === Name[String]("foo")) should be(true) -- cgit v1.2.3 From f0a5e41ec45d2420ba7173e156806f81701f9796 Mon Sep 17 00:00:00 2001 From: Stewart Stewart Date: Tue, 20 Dec 2016 01:39:16 -0500 Subject: fix Time#toDate and sqlDateToDate --- src/main/scala/xyz/driver/core/database/package.scala | 10 ++++++++-- src/main/scala/xyz/driver/core/date.scala | 7 ------- src/main/scala/xyz/driver/core/time.scala | 4 ++-- 3 files changed, 10 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/main/scala/xyz/driver/core/database/package.scala b/src/main/scala/xyz/driver/core/database/package.scala index 7d9aecb..c88260b 100644 --- a/src/main/scala/xyz/driver/core/database/package.scala +++ b/src/main/scala/xyz/driver/core/database/package.scala @@ -3,7 +3,7 @@ package xyz.driver.core import java.sql.{Date => SqlDate} import java.util.Calendar -import date.{Date, javaDateToDate} +import date.Date import slick.dbio.{DBIOAction, NoStream} package object database { @@ -13,7 +13,13 @@ package object database { def drop: DBIOAction[Unit, NoStream, slick.dbio.Effect.Schema] } - private[database] def sqlDateToDate(date: SqlDate): Date = javaDateToDate(date) + private[database] def sqlDateToDate(sqlDate: SqlDate): Date = { + // NOTE: SQL date does not have a time component, so this date + // should only be interpreted in the running JVMs timezone. + val cal = Calendar.getInstance() + cal.setTime(sqlDate) + Date(cal.get(Calendar.YEAR), date.tagMonth(cal.get(Calendar.MONTH)), cal.get(Calendar.DAY_OF_MONTH)) + } private[database] def dateToSqlDate(date: Date): SqlDate = { val cal = Calendar.getInstance() diff --git a/src/main/scala/xyz/driver/core/date.scala b/src/main/scala/xyz/driver/core/date.scala index 437729f..ab19074 100644 --- a/src/main/scala/xyz/driver/core/date.scala +++ b/src/main/scala/xyz/driver/core/date.scala @@ -22,11 +22,4 @@ object date { } final case class Date(year: Int, month: Month, day: Int) - - private[core] def javaDateToDate(javaDate: java.util.Date): Date = { - val cal = Calendar.getInstance() - cal.setTime(javaDate) - Date(cal.get(Calendar.YEAR), date.tagMonth(cal.get(Calendar.MONTH)), cal.get(Calendar.DAY_OF_MONTH)) - } - } diff --git a/src/main/scala/xyz/driver/core/time.scala b/src/main/scala/xyz/driver/core/time.scala index 5dc16a0..cbb86ed 100644 --- a/src/main/scala/xyz/driver/core/time.scala +++ b/src/main/scala/xyz/driver/core/time.scala @@ -28,9 +28,9 @@ object time { def advanceBy(duration: Duration): Time = Time(millis + duration.toMillis) def toDate(timezone: TimeZone): date.Date = { - val cal = java.util.Calendar.getInstance(timezone) + val cal = Calendar.getInstance(timezone) cal.setTimeInMillis(millis) - date.javaDateToDate(cal.getTime()) + date.Date(cal.get(Calendar.YEAR), date.tagMonth(cal.get(Calendar.MONTH)), cal.get(Calendar.DAY_OF_MONTH)) } } -- cgit v1.2.3