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

uk.gov.nationalarchives.tdr.validation.utils.CSVtoJsonUtils.scala Maven / Gradle / Ivy

package uk.gov.nationalarchives.tdr.validation.utils

import com.fasterxml.jackson.databind.{JsonNode, ObjectMapper}
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import uk.gov.nationalarchives.tdr.validation.schema.JsonSchemaDefinition.BASE_SCHEMA

import java.io.InputStream
import scala.util.Try

class CSVtoJsonUtils {

  private case class ConvertedProperty(propertyName: String, convertValueFunc: String => Any)
  private val nodeSchema = getJsonNodeFromStreamContent(getClass.getResourceAsStream(BASE_SCHEMA.schemaLocation))
  private val json = ujson.read(nodeSchema.toPrettyString)

  private def getJsonNodeFromStreamContent(content: InputStream): JsonNode = {
    val mapper = new ObjectMapper()
    mapper.readTree(content)
  }

  // Extracts type from JSON value
  private def getPropertyType(propertyValue: ujson.Obj): String = {
    propertyValue.obj.get("type") match {
      case Some(ujson.Str(singleType))              => singleType
      case Some(ujson.Arr(types)) if types.nonEmpty => types.head.str
      case _                                        => "unknown"
    }
  }

  private def convertValueFunction(propertyType: String): String => Any = {
    propertyType match {
      case "integer" => (str: String) => Try(str.toInt).getOrElse(str)
      case "array"   => (str: String) => if (str.isEmpty) "" else str.split("\\|")
      case "boolean" =>
        (str: String) =>
          str.toUpperCase match {
            case "YES" => true
            case "NO"  => false
            case _     => str
          }
      case _ => (str: String) => str
    }
  }

  private val propertyValueConverterMap: Map[String, ConvertedProperty] = (for {
    (propertyName, propertyValue) <- json("properties").obj
    propertyTypes = getPropertyType(propertyValue.obj)
    // Use propertyName if alternateKeys is absent
    headerMappings = propertyValue.obj.get("alternateKeys") match {
      case Some(alternateKeys) =>
        for {
          alternateKey <- alternateKeys.arr
          header <- alternateKey.obj.get("tdrFileHeader").toSeq
        } yield header.str -> ConvertedProperty(propertyName, convertValueFunction(propertyType = propertyTypes))
      case None =>
        Seq(propertyName -> ConvertedProperty(propertyName, convertValueFunction(propertyType = propertyTypes)))
    }
    headerMapping <- headerMappings
  } yield headerMapping).toMap

  // Converts a CSV key-value pair to a JSON string with correct types
  def convertToJSONString(input: Map[String, String]): String = {
    val mapper = new ObjectMapper().registerModule(DefaultScalaModule)
    val dataConvertedToSchemaDefinitions: Map[String, Any] = input.map { case (key, value) =>
      propertyValueConverterMap.get(key) match {
        case Some(convertedProperty: ConvertedProperty) =>
          convertedProperty.propertyName -> convertedProperty.convertValueFunc(value)
        case None =>
          key -> value
      }
    }
    val generatedJson = mapper.writeValueAsString(dataConvertedToSchemaDefinitions)
    generatedJson
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy