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

com.github.mauricio.async.db.postgresql.column.PostgreSQLColumnEncoderRegistry.scala Maven / Gradle / Ivy

/*
 * Copyright 2013 Maurício Linhares
 *
 * Maurício Linhares licenses this file to you 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 com.github.mauricio.async.db.postgresql.column

import java.nio.ByteBuffer

import com.github.mauricio.async.db.column._
import io.netty.buffer.ByteBuf
import org.joda.time._

import scala.collection.JavaConversions._

object PostgreSQLColumnEncoderRegistry {
  val Instance = new PostgreSQLColumnEncoderRegistry()
}

class PostgreSQLColumnEncoderRegistry extends ColumnEncoderRegistry {

  private val classesSequence_ : List[(Class[_], (ColumnEncoder, Int))] = List(
    classOf[Int] -> (IntegerEncoderDecoder -> ColumnTypes.Numeric),
    classOf[java.lang.Integer] -> (IntegerEncoderDecoder -> ColumnTypes.Numeric),

    classOf[java.lang.Short] -> (ShortEncoderDecoder -> ColumnTypes.Numeric),
    classOf[Short] -> (ShortEncoderDecoder -> ColumnTypes.Numeric),

    classOf[Long] -> (LongEncoderDecoder -> ColumnTypes.Numeric),
    classOf[java.lang.Long] -> (LongEncoderDecoder -> ColumnTypes.Numeric),

    classOf[String] -> (StringEncoderDecoder -> ColumnTypes.Varchar),
    classOf[java.lang.String] -> (StringEncoderDecoder -> ColumnTypes.Varchar),

    classOf[Float] -> (FloatEncoderDecoder -> ColumnTypes.Numeric),
    classOf[java.lang.Float] -> (FloatEncoderDecoder -> ColumnTypes.Numeric),

    classOf[Double] -> (DoubleEncoderDecoder -> ColumnTypes.Numeric),
    classOf[java.lang.Double] -> (DoubleEncoderDecoder -> ColumnTypes.Numeric),

    classOf[BigDecimal] -> (BigDecimalEncoderDecoder -> ColumnTypes.Numeric),
    classOf[java.math.BigDecimal] -> (BigDecimalEncoderDecoder -> ColumnTypes.Numeric),

    classOf[java.util.UUID] -> (UUIDEncoderDecoder -> ColumnTypes.UUID),

    classOf[LocalDate] -> ( DateEncoderDecoder -> ColumnTypes.Date ),
    classOf[LocalDateTime] -> (TimestampEncoderDecoder.Instance -> ColumnTypes.Timestamp),
    classOf[DateTime] -> (TimestampWithTimezoneEncoderDecoder -> ColumnTypes.TimestampWithTimezone),
    classOf[ReadableDateTime] -> (TimestampWithTimezoneEncoderDecoder -> ColumnTypes.TimestampWithTimezone),
    classOf[ReadableInstant] -> (DateEncoderDecoder -> ColumnTypes.Date),

    classOf[ReadablePeriod] -> (PostgreSQLIntervalEncoderDecoder -> ColumnTypes.Interval),
    classOf[ReadableDuration] -> (PostgreSQLIntervalEncoderDecoder -> ColumnTypes.Interval),

    classOf[java.util.Date] -> (TimestampWithTimezoneEncoderDecoder -> ColumnTypes.TimestampWithTimezone),
    classOf[java.sql.Date] -> ( DateEncoderDecoder -> ColumnTypes.Date ),
    classOf[java.sql.Time] -> ( SQLTimeEncoder -> ColumnTypes.Time ),
    classOf[java.sql.Timestamp] -> (TimestampWithTimezoneEncoderDecoder -> ColumnTypes.TimestampWithTimezone),
    classOf[java.util.Calendar] -> (TimestampWithTimezoneEncoderDecoder -> ColumnTypes.TimestampWithTimezone),
    classOf[java.util.GregorianCalendar] -> (TimestampWithTimezoneEncoderDecoder -> ColumnTypes.TimestampWithTimezone),
    classOf[Array[Byte]] -> ( ByteArrayEncoderDecoder -> ColumnTypes.ByteA ),
    classOf[ByteBuffer] -> ( ByteArrayEncoderDecoder -> ColumnTypes.ByteA ),
    classOf[ByteBuf] -> ( ByteArrayEncoderDecoder -> ColumnTypes.ByteA )
  )

  private final val classesSequence = (classOf[LocalTime] -> (TimeEncoderDecoder.Instance -> ColumnTypes.Time)) ::
    (classOf[ReadablePartial] -> (TimeEncoderDecoder.Instance -> ColumnTypes.Time)) ::
    classesSequence_

  private final val classes = classesSequence.toMap

  override def encode(value: Any): String = {

    if (value == null) {
      return null
    }

    value match {
      case Some(v) => encode(v)
      case None => null
      case _ => encodeValue(value)
    }

  }

  /**
   * Used to encode a value that is not null and not an Option.
   */
  private def encodeValue(value: Any): String = {

    val encoder = this.classes.get(value.getClass)

    if (encoder.isDefined) {
      encoder.get._1.encode(value)
    } else {

      val view: Option[Traversable[Any]] = value match {
        case i: java.lang.Iterable[_] => Some(i.toIterable)
        case i: Traversable[_] => Some(i)
        case i: Array[_] => Some(i.toIterable)
        case _ => None
      }

      view match {
        case Some(collection) => encodeArray(collection)
        case None => {
          this.classesSequence.find(entry => entry._1.isAssignableFrom(value.getClass)) match {
            case Some(parent) => parent._2._1.encode(value)
            case None => value.toString
          }
        }
      }

    }

  }

  private def encodeArray(collection: Traversable[_]): String = {
    val builder = new StringBuilder()

    builder.append('{')

    val result = collection.map {
      item =>

        if (item == null || item == None) {
          "NULL"
        } else {
          if (this.shouldQuote(item)) {
            "\"" + this.encode(item).replaceAllLiterally("\\", """\\""").replaceAllLiterally("\"", """\"""") + "\""
          } else {
            this.encode(item)
          }
        }

    }.mkString(",")

    builder.append(result)
    builder.append('}')

    builder.toString()
  }

  private def shouldQuote(value: Any): Boolean = {
    value match {
      case n: java.lang.Number => false
      case n: Int => false
      case n: Short => false
      case n: Long => false
      case n: Float => false
      case n: Double => false
      case n: java.lang.Iterable[_] => false
      case n: Traversable[_] => false
      case n: Array[_] => false
      case Some(v) => shouldQuote(v)
      case _ => true
    }
  }

  override def kindOf(value: Any): Int = {
    if ( value == null || value == None ) {
      0
    } else {
      value match {
        case Some(v) => kindOf(v)
        case v : String => ColumnTypes.Untyped
        case _ => {
          this.classes.get(value.getClass) match {
            case Some( entry ) => entry._2
            case None => ColumnTypes.Untyped
          }
        }
      }
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy