All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.websudos.phantom.builder.primitives.Primitive.scala Maven / Gradle / Ivy

There is a newer version: 1.29.6
Show newest version
/*
 * 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, Outworkers 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.builder.primitives

import java.net.InetAddress
import java.nio.ByteBuffer
import java.util.{Date, UUID}

import com.datastax.driver.core.utils.Bytes
import com.datastax.driver.core.{LocalDate, Row}
import com.websudos.phantom.builder.query.CQLQuery
import com.websudos.phantom.builder.syntax.CQLSyntax
import org.joda.time.{DateTime, DateTimeZone}

import scala.util.control.NoStackTrace
import scala.util.{Failure, Try}


private[phantom] object DateSerializer {

  def asCql(date: Date): String = date.getTime.toString

  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
}

sealed trait ValueTypeDef {
  type ValueType <: AnyRef
}

abstract class Primitive[RR] {

  type PrimitiveType

  protected[this] def nullCheck[T](column: String, row: Row)(fn: Row => T): Try[T] = {
    if (Option(row).isEmpty || row.isNull(column)) {
      Failure(new Exception(s"Column $column is null") with NoStackTrace)
    } else {
      Try(fn(row))
    }
  }

  def asCql(value: RR): String

  def cassandraType: String

  def fromRow(column: String, row: Row): Try[RR]

  def fromString(value: String): RR

  def clz: Class[PrimitiveType]

  def fromPrimitive(obj: PrimitiveType): RR = identity(obj).asInstanceOf[RR]

}

trait DefaultPrimitives {

  implicit object StringPrimitive extends Primitive[String] {

    override type PrimitiveType = java.lang.String

    def asCql(value: String): String = CQLQuery.empty.singleQuote(value)

    override def cassandraType: String = CQLSyntax.Types.Text

    override def fromString(value: String): String = value

    override def fromRow(column: String, row: Row): Try[String] = {
      nullCheck(column, row) {
        r => r.getString(column)
      }
    }

    override def clz: Class[String] = classOf[String]
  }

  implicit object IntPrimitive extends Primitive[Int] {

    override type PrimitiveType = java.lang.Integer

    def asCql(value: Int): String = value.toString

    override def cassandraType: String = CQLSyntax.Types.Int

    override def fromString(value: String): Int = value.toInt

    override def fromRow(column: String, row: Row): Try[Int] = nullCheck(column, row) {
      r => r.getInt(column)
    }

    override def clz: Class[java.lang.Integer] = classOf[java.lang.Integer]
  }

  implicit object SmallIntPrimitive extends Primitive[Short] {

    override type PrimitiveType = java.lang.Short

    def asCql(value: Short): String = value.toString

    override def cassandraType: String = CQLSyntax.Types.SmallInt

    override def fromString(value: String): Short = value.toShort

    override def fromRow(column: String, row: Row): Try[Short] = nullCheck(column, row) {
      r => r.getShort(column)
    }

    override def clz: Class[java.lang.Short] = classOf[java.lang.Short]
  }

  implicit object TinyIntPrimitive extends Primitive[Byte] {

    override type PrimitiveType = java.lang.Byte

    def asCql(value: Byte): String = value.toString

    override def cassandraType: String = CQLSyntax.Types.TinyInt

    override def fromString(value: String): Byte = value.toByte

    override def fromRow(column: String, row: Row): Try[Byte] = nullCheck(column, row) {
      r => r.getByte(column)
    }

    override def clz: Class[java.lang.Byte] = classOf[java.lang.Byte]
  }

  implicit object DoublePrimitive extends Primitive[Double] {

    override type PrimitiveType = java.lang.Double

    def asCql(value: Double): String = value.toString

    override def cassandraType: String = CQLSyntax.Types.Double

    override def fromString(value: String): Double = value.toDouble

    override def fromRow(column: String, row: Row): Try[Double] = nullCheck(column, row) {
      r => r.getDouble(column)
    }

    override def clz: Class[java.lang.Double] = classOf[java.lang.Double]
  }

  implicit object LongPrimitive extends Primitive[Long] {

    override type PrimitiveType = java.lang.Long

    def asCql(value: Long): String = value.toString

    override def cassandraType: String = CQLSyntax.Types.BigInt

    override def fromString(value: String): Long = value.toLong

    override def fromRow(column: String, row: Row): Try[Long] = {
      nullCheck(column, row)(_.getLong(column))
    }

    override def clz: Class[java.lang.Long] = classOf[java.lang.Long]
  }

  implicit object FloatPrimitive extends Primitive[Float] {

    override type PrimitiveType = java.lang.Float

    def asCql(value: Float): String = value.toString

    override def cassandraType: String = CQLSyntax.Types.Float

    override def fromString(value: String): Float = value.toFloat

    override def fromRow(column: String, row: Row): Try[Float] = nullCheck(column, row) {
      r => r.getFloat(column)
    }

    override def clz: Class[java.lang.Float] = classOf[java.lang.Float]
  }

  implicit object UUIDPrimitive extends Primitive[UUID] {

    override type PrimitiveType = java.util.UUID

    def asCql(value: UUID): String = value.toString

    override def cassandraType: String = CQLSyntax.Types.UUID

    override def fromString(value: String): UUID = UUID.fromString(value)

    override def fromRow(column: String, row: Row): Try[UUID] = nullCheck(column, row) {
      r => r.getUUID(column)
    }

    override def clz: Class[UUID] = classOf[UUID]
  }

  implicit object DateIsPrimitive extends Primitive[Date] {

    override type PrimitiveType = java.util.Date

    val cassandraType = CQLSyntax.Types.Timestamp

    def fromRow(row: Row, name: String): Option[Date] =
      if (row.isNull(name)) None else Try(row.getTimestamp(name)).toOption

    override def asCql(value: Date): String = {
      DateSerializer.asCql(value)
    }

    override def fromRow(column: String, row: Row): Try[Date] = nullCheck(column, row) {
      r => r.getTimestamp(column)
    }

    override def fromString(value: String): Date = {
      new DateTime(value, DateTimeZone.UTC).toDate
    }

    override def clz: Class[Date] = classOf[Date]
  }

  implicit object LocalDateIsPrimitive extends Primitive[LocalDate] {

    override type PrimitiveType = com.datastax.driver.core.LocalDate

    val cassandraType = CQLSyntax.Types.Date

    def fromRow(row: Row, name: String): Option[LocalDate] =
      if (row.isNull(name)) None else Try(row.getDate(name)).toOption

    override def asCql(value: LocalDate): String = {
      DateSerializer.asCql(value)
    }

    override def fromRow(column: String, row: Row): Try[LocalDate] = nullCheck(column, row) {
      r => r.getDate(column)
    }

    override def fromString(value: String): LocalDate = {
      LocalDate.fromMillisSinceEpoch(new DateTime(value, DateTimeZone.UTC).getMillis)
    }

    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, DateTimeZone.UTC).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, DateTimeZone.UTC).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

    val cassandraType = CQLSyntax.Types.Timestamp

    override def asCql(value: DateTime): String = {
      DateSerializer.asCql(value)
    }

    override def fromRow(column: String, row: Row): Try[DateTime] = nullCheck(column, row) {
      r => new DateTime(r.getTimestamp(column))
    }

    override def fromString(value: String): DateTime = new DateTime(value)

    override def clz: Class[Date] = classOf[Date]

    override def fromPrimitive(obj: PrimitiveType): DateTime = new DateTime(obj)
  }


  implicit object BooleanIsPrimitive extends Primitive[Boolean] {

    override type PrimitiveType = java.lang.Boolean

    val cassandraType = CQLSyntax.Types.Boolean

    def fromRow(row: Row, name: String): Option[Boolean] =
      if (row.isNull(name)) None else Try(row.getBool(name)).toOption

    override def asCql(value: Boolean): String = value.toString

    override def fromRow(column: String, row: Row): Try[Boolean] = nullCheck(column, row) {
      r => r.getBool(column)
    }

    override def fromString(value: String): Boolean = value match {
      case "true" => true
      case "false" => false
      case _ => throw new Exception(s"Couldn't parse a boolean value from $value")
    }

    override def clz: Class[java.lang.Boolean] = classOf[java.lang.Boolean]
  }

  implicit object BigDecimalPrimitive extends Primitive[BigDecimal] {

    override type PrimitiveType = java.math.BigDecimal

    val cassandraType = CQLSyntax.Types.Decimal

    override def fromRow(column: String, row: Row): Try[BigDecimal] = nullCheck(column, row) {
      r => BigDecimal(r.getDecimal(column))
    }

    override def asCql(value: BigDecimal): String = value.toString()

    override def fromString(value: String): BigDecimal = BigDecimal(value)

    override def clz: Class[java.math.BigDecimal] = classOf[java.math.BigDecimal]
  }

  implicit object InetAddressPrimitive extends Primitive[InetAddress] {

    override type PrimitiveType = java.net.InetAddress

    val cassandraType = CQLSyntax.Types.Inet

    override def fromRow(column: String, row: Row): Try[InetAddress] = nullCheck(column, row) {
      r => r.getInet(column)
    }

    override def asCql(value: InetAddress): String = CQLQuery.empty.singleQuote(value.getHostAddress)

    override def fromString(value: String): InetAddress = InetAddress.getByName(value)

    override def clz: Class[InetAddress] = classOf[InetAddress]
  }

  implicit object BigIntPrimitive extends Primitive[BigInt] {

    override type PrimitiveType = java.math.BigInteger

    val cassandraType = CQLSyntax.Types.Varint

    override def fromRow(column: String, row: Row): Try[BigInt] = nullCheck(column, row) {
      r => r.getVarint(column)
    }

    override def asCql(value: BigInt): String = value.toString()

    override def fromString(value: String): BigInt = BigInt(value)

    override def clz: Class[java.math.BigInteger] = classOf[java.math.BigInteger]
  }

  implicit object BlobIsPrimitive extends Primitive[ByteBuffer] {

    override type PrimitiveType = java.nio.ByteBuffer

    val cassandraType = CQLSyntax.Types.Blob

    override def fromRow(column: String, row: Row): Try[ByteBuffer] = nullCheck(column, row) {
      r => r.getBytes(column)
    }

    override def asCql(value: ByteBuffer): String = Bytes.toHexString(value)

    override def fromString(value: String): ByteBuffer = Bytes.fromHexString(value)

    override def clz: Class[java.nio.ByteBuffer] = classOf[java.nio.ByteBuffer]
  }

}

object Primitive extends DefaultPrimitives {
  def apply[RR: Primitive]: Primitive[RR] = implicitly[Primitive[RR]]


  def apply[T <: Enumeration](enum: T): Primitive[T#Value] = {
    new Primitive[T#Value] {

      override type PrimitiveType = java.lang.String

      override def cassandraType: String = Primitive[String].cassandraType

      override def fromRow(name: String, row: Row): Try[T#Value] = {
        nullCheck(name, row) {
          r => enum.values.find(_.toString == r.getString(name)) match {
            case Some(value) => value
            case _ => throw new Exception(s"Value $name not found in enumeration") with NoStackTrace
          }
        }
      }

      override def asCql(value: T#Value): String = Primitive[String].asCql(value.toString)

      override def fromString(value: String): T#Value = enum.values.find(value == _.toString).getOrElse(None.orNull)

      override def clz: Class[String] = classOf[java.lang.String]
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy