diff --git a/phantom-dsl/src/main/scala/com/websudos/phantom/builder/primitives/Primitive.scala b/phantom-dsl/src/main/scala/com/websudos/phantom/builder/primitives/Primitive.scala index 2a4dee7dd..82119c7ef 100644 --- a/phantom-dsl/src/main/scala/com/websudos/phantom/builder/primitives/Primitive.scala +++ b/phantom-dsl/src/main/scala/com/websudos/phantom/builder/primitives/Primitive.scala @@ -49,6 +49,8 @@ private[phantom] object DateSerializer { def asCql(date: LocalDate): String = date.getMillisSinceEpoch.toString + def asCql(date: org.joda.time.LocalDate): String = date.toString + def asCql(date: DateTime): String = date.getMillis.toString } @@ -270,6 +272,30 @@ trait DefaultPrimitives { override def clz: Class[LocalDate] = classOf[LocalDate] } + implicit object JodaLocalDateIsPrimitive extends Primitive[org.joda.time.LocalDate] { + + override type PrimitiveType = com.datastax.driver.core.LocalDate + + val cassandraType = CQLSyntax.Types.Date + + def fromRow(row: Row, name: String): Option[org.joda.time.LocalDate] = + if (row.isNull(name)) None else Try(new DateTime(row.getDate(name).getMillisSinceEpoch).toLocalDate).toOption + + override def asCql(value: org.joda.time.LocalDate): String = { + CQLQuery.empty.singleQuote(DateSerializer.asCql(value)) + } + + override def fromRow(column: String, row: Row): Try[org.joda.time.LocalDate] = nullCheck(column, row) { + r => new DateTime(r.getDate(column).getMillisSinceEpoch).toLocalDate + } + + override def fromString(value: String): org.joda.time.LocalDate = { + new DateTime(value, DateTimeZone.UTC).toLocalDate + } + + override def clz: Class[com.datastax.driver.core.LocalDate] = classOf[com.datastax.driver.core.LocalDate] + } + implicit object DateTimeIsPrimitive extends Primitive[DateTime] { override type PrimitiveType = java.util.Date diff --git a/phantom-dsl/src/main/scala/com/websudos/phantom/codec/JodaLocalDateCodec.scala b/phantom-dsl/src/main/scala/com/websudos/phantom/codec/JodaLocalDateCodec.scala new file mode 100644 index 000000000..2d3bdebde --- /dev/null +++ b/phantom-dsl/src/main/scala/com/websudos/phantom/codec/JodaLocalDateCodec.scala @@ -0,0 +1,40 @@ +/* + * Copyright 2013-2015 Websudos, Limited. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Explicit consent must be obtained from the copyright owner, Websudos Limited before any redistribution is made. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package com.websudos.phantom.codec + +import com.datastax.driver.core._ +import com.datastax.driver.extras.codecs.MappingCodec + +class JodaLocalDateCodec extends MappingCodec(TypeCodec.date(), classOf[org.joda.time.LocalDate]) { + + override def serialize(value: org.joda.time.LocalDate): LocalDate = LocalDate.fromYearMonthDay(value.getYear, value.getMonthOfYear, value.getDayOfMonth) + + override def deserialize(value: LocalDate): org.joda.time.LocalDate = new org.joda.time.LocalDate(value.getYear, value.getMonth, value.getDay) +} \ No newline at end of file diff --git a/phantom-dsl/src/main/scala/com/websudos/phantom/column/PrimitiveColumn.scala b/phantom-dsl/src/main/scala/com/websudos/phantom/column/PrimitiveColumn.scala index 0bf237fd8..8b7eec894 100644 --- a/phantom-dsl/src/main/scala/com/websudos/phantom/column/PrimitiveColumn.scala +++ b/phantom-dsl/src/main/scala/com/websudos/phantom/column/PrimitiveColumn.scala @@ -36,7 +36,7 @@ import com.websudos.phantom.CassandraTable import com.websudos.phantom.builder.primitives.Primitive import com.websudos.phantom.builder.query.CQLQuery import com.websudos.phantom.builder.syntax.CQLSyntax -import org.joda.time.DateTime +import org.joda.time.{LocalDate, DateTime} import scala.annotation.implicitNotFound import scala.util.Try @@ -82,6 +82,16 @@ class DateTimeColumn[Owner <: CassandraTable[Owner, Record], Record](table: Cass extends PrimitiveColumn[Owner, Record, DateTime](table) { } +/** + * A LocalDate Column. + * @param table The Cassandra Table to which the column belongs to. + * @tparam Owner The Owner of the Record. + * @tparam Record The Record type. + */ +class LocalDateColumn[Owner <: CassandraTable[Owner, Record], Record](table: CassandraTable[Owner, Record]) + extends PrimitiveColumn[Owner, Record, LocalDate](table) { +} + /* class Tuple2Column[Owner <: CassandraTable[Owner, Record], Record, K1 : Primitive, K2 : Primitive](table: Owner) extends Column[Owner, Record, (K1, K2)](table) { diff --git a/phantom-dsl/src/test/scala/com/websudos/phantom/builder/query/prepared/PreparedInsertQueryTest.scala b/phantom-dsl/src/test/scala/com/websudos/phantom/builder/query/prepared/PreparedInsertQueryTest.scala index 36e98f57b..63edb6372 100644 --- a/phantom-dsl/src/test/scala/com/websudos/phantom/builder/query/prepared/PreparedInsertQueryTest.scala +++ b/phantom-dsl/src/test/scala/com/websudos/phantom/builder/query/prepared/PreparedInsertQueryTest.scala @@ -30,9 +30,10 @@ package com.websudos.phantom.builder.query.prepared import com.websudos.phantom.PhantomSuite -import com.websudos.phantom.tables.{PrimitiveCassandra22, Primitive, TestDatabase, Recipe} -import com.websudos.util.testing._ +import com.websudos.phantom.codec.JodaLocalDateCodec import com.websudos.phantom.dsl._ +import com.websudos.phantom.tables.{Primitive, PrimitiveCassandra22, Recipe, TestDatabase} +import com.websudos.util.testing._ class PreparedInsertQueryTest extends PhantomSuite { @@ -40,7 +41,7 @@ class PreparedInsertQueryTest extends PhantomSuite { super.beforeAll() TestDatabase.recipes.insertSchema() TestDatabase.primitives.insertSchema() - if(session.v4orNewer) { + if (session.v4orNewer) { TestDatabase.primitivesCassandra22.insertSchema() } } @@ -126,25 +127,32 @@ class PreparedInsertQueryTest extends PhantomSuite { } } - if(session.v4orNewer) { + if (session.v4orNewer) { it should "serialize a cassandra 2.2 primitives insert query" in { + session.getCluster.getConfiguration.getCodecRegistry.register(new JodaLocalDateCodec) val sample = gen[PrimitiveCassandra22] val query = TestDatabase.primitivesCassandra22.insert .p_value(_.pkey, ?) .p_value(_.short, ?) .p_value(_.byte, ?) + .p_value(_.date, ?) .prepare() val exec = query.bind( sample.pkey, sample.short, - sample.byte + sample.byte, + sample.localDate ).future() + val selectQuery = TestDatabase.primitivesCassandra22.select + .p_where(_.pkey eqs ?) + .prepare() + val chain = for { store <- exec - get <- TestDatabase.primitivesCassandra22.select.where(_.pkey eqs sample.pkey).one() + get <- selectQuery.bind(sample.pkey).one() } yield get whenReady(chain) { diff --git a/phantom-dsl/src/test/scala/com/websudos/phantom/tables/PrimitivesCassandra22.scala b/phantom-dsl/src/test/scala/com/websudos/phantom/tables/PrimitivesCassandra22.scala index c82b8a2b3..e79e47f3c 100644 --- a/phantom-dsl/src/test/scala/com/websudos/phantom/tables/PrimitivesCassandra22.scala +++ b/phantom-dsl/src/test/scala/com/websudos/phantom/tables/PrimitivesCassandra22.scala @@ -30,12 +30,15 @@ package com.websudos.phantom.tables import com.websudos.phantom.builder.query.InsertQuery +import com.websudos.phantom.column.LocalDateColumn import com.websudos.phantom.dsl._ +import org.joda.time.LocalDate case class PrimitiveCassandra22( pkey: String, short: Short, - byte: Byte + byte: Byte, + localDate: LocalDate ) sealed class PrimitivesCassandra22 extends CassandraTable[ConcretePrimitivesCassandra22, PrimitiveCassandra22] { @@ -45,11 +48,14 @@ sealed class PrimitivesCassandra22 extends CassandraTable[ConcretePrimitivesCass object byte extends TinyIntColumn(this) + object date extends LocalDateColumn(this) + override def fromRow(r: Row): PrimitiveCassandra22 = { PrimitiveCassandra22( pkey = pkey(r), short = short(r), - byte = byte(r) + byte = byte(r), + localDate = date(r) ) } } @@ -63,5 +69,6 @@ abstract class ConcretePrimitivesCassandra22 extends PrimitivesCassandra22 with .value(_.pkey, row.pkey) .value(_.short, row.short) .value(_.byte, row.byte) + .value(_.date, row.localDate) } } diff --git a/phantom-dsl/src/test/scala/com/websudos/phantom/tables/package.scala b/phantom-dsl/src/test/scala/com/websudos/phantom/tables/package.scala index 9d2c77f94..eab9f3733 100644 --- a/phantom-dsl/src/test/scala/com/websudos/phantom/tables/package.scala +++ b/phantom-dsl/src/test/scala/com/websudos/phantom/tables/package.scala @@ -146,7 +146,8 @@ package object tables { PrimitiveCassandra22( gen[String], gen[Int].toShort, - gen[Int].toByte + gen[Int].toByte, + new DateTime(new DateTime().plus(gen[Int].toLong)).toLocalDate ) } } diff --git a/project/Build.scala b/project/Build.scala index 7330c4b21..b6dc80be2 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -200,6 +200,7 @@ object Build extends Build { "joda-time" % "joda-time" % "2.3", "org.joda" % "joda-convert" % "1.6", "com.datastax.cassandra" % "cassandra-driver-core" % DatastaxDriverVersion, + "com.datastax.cassandra" % "cassandra-driver-extras" % DatastaxDriverVersion, "org.slf4j" % "log4j-over-slf4j" % "1.7.12", "org.scalacheck" %% "scalacheck" % "1.11.5" % "test, provided", "com.websudos" %% "util-lift" % UtilVersion % "test, provided",