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

org.neo4j.cypher.internal.helpers.CastSupport.scala Maven / Gradle / Ivy

/**
 * Copyright (c) 2002-2015 "Neo Technology,"
 * Network Engine for Objects in Lund AB [http://neotechnology.com]
 *
 * This file is part of Neo4j.
 *
 * Neo4j is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package org.neo4j.cypher.internal.helpers

import org.neo4j.cypher.CypherTypeException

object CastSupport {

  // TODO Switch to using ClassTag once we decide to depend on the reflection api

  /**
   * Filter sequence by type
   */
  def sift[A : Manifest](seq: Seq[Any]): Seq[A] = seq.collect(erasureCast)

  /**
   * Casts input to A if possible according to type erasure, discards input otherwise
   */
  def erasureCast[A : Manifest]: PartialFunction[Any, A] = { case value: A => value }

  def castOrFail[A](value: Any)(implicit ev: Manifest[A]): A = value match {
    case v: A => v
    case _    => throw new CypherTypeException(
      s"Expected $value to be a ${ev.runtimeClass.getName}, but it was a ${value.getClass.getName}")
  }

  /*
  This method takes two values and finds the type both values could be represented in.

  The produced value is strictly meant to be used as a type carrier
   */
  def merge(a: Any, b: Any): Any = {
    (a, b) match {
      case (_: String, _: String)   => a
      case (_: Char, _: Char)       => a
      case (_: Boolean, _: Boolean) => a

      case (_: Byte, _: Byte)   => a
      case (_: Byte, _: Short)  => b
      case (_: Byte, _: Int)    => b
      case (_: Byte, _: Long)   => b
      case (_: Byte, _: Float)  => b
      case (_: Byte, _: Double) => b

      case (_: Short, _: Int)    => b
      case (_: Short, _: Long)   => b
      case (_: Short, _: Float)  => b
      case (_: Short, _: Double) => b
      case (_: Short, _: Number) => a

      case (_: Int, _: Long)   => b
      case (_: Int, _: Float)  => b
      case (_: Int, _: Double) => b
      case (_: Int, _: Number) => a

      case (_: Long, _: Float)  => b
      case (_: Long, _: Double) => b
      case (_: Long, _: Number) => a

      case (_: Float, _: Double) => b
      case (_: Float, _: Number) => a

      case (_: Double, _: Number) => a

      case _ => throw new CypherTypeException("Collections containing mixed types can not be stored in properties.")
    }
  }

  /*Instances of this class can be gotten from @CastSupport.getConverter*/
  sealed case class Converter(valueConverter: Any => Any, arrayConverter: Seq[Any] => Array[_])

  /*Returns a converter given a type value*/
  def getConverter(x: Any): Converter = x match {
    case _: String  => Converter(x => x.asInstanceOf[String], x => x.asInstanceOf[Seq[String]].toArray[String])
    case _: Char    => Converter(x => x.asInstanceOf[Char], x => x.asInstanceOf[Seq[Char]].toArray[Char])
    case _: Boolean => Converter(x => x.asInstanceOf[Boolean], x => x.asInstanceOf[Seq[Boolean]].toArray[Boolean])
    case _: Byte    => Converter(x => x.asInstanceOf[Number].byteValue(), x => x.asInstanceOf[Seq[Byte]].toArray[Byte])
    case _: Short   => Converter(x => x.asInstanceOf[Number].shortValue(), x => x.asInstanceOf[Seq[Short]].toArray[Short])
    case _: Int     => Converter(x => x.asInstanceOf[Number].intValue(), x => x.asInstanceOf[Seq[Int]].toArray[Int])
    case _: Long    => Converter(x => x.asInstanceOf[Number].longValue(), x => x.asInstanceOf[Seq[Long]].toArray[Long])
    case _: Float   => Converter(x => x.asInstanceOf[Number].floatValue(), x => x.asInstanceOf[Seq[Float]].toArray[Float])
    case _: Double  => Converter(x => x.asInstanceOf[Number].doubleValue(), x => x.asInstanceOf[Seq[Double]].toArray[Double])
    case _          => throw new CypherTypeException("Property values can only be of primitive types or arrays thereof")
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy