Search code examples
scalacirce

Parse Array with circe


i have a json such as :

[
    [
        "Service ID",
        "VARCHAR",
        1,
        12
    ],
    [
        "Operation",
        "VARCHAR",
        2,
        12
    ],
    [
        "Start Date",
        "VARCHAR",
        3,
        12
    ],
    [
        "End Date",
        "VARCHAR",
        4,
        12
    ],
    [
        "Agent Position",
        "VARCHAR",
        5,
        12
    ],
    [
        "Customer ID",
        "VARCHAR",
        6,
        12
    ],
    [
        "Product",
        "VARCHAR",
        7,
        12
    ],
    [
        "Service Type",
        "VARCHAR",
        8,
        12
    ],
    [
        "Agent",
        "VARCHAR",
        9,
        12
    ]
]

where i would like to massage/map as a case class like

{
"schema": [
    {
        "COLUMN_NAME":"Service ID",
        "DATA_TYPE":"VARCHAR",
        "ORDINAL_POSITION":1,
        "JDBC_DATA_TYPE12":12
    },
    {
        "COLUMN_NAME":"Operation",
        "DATA_TYPE":"VARCHAR",
        "ORDINAL_POSITION":2,
        "JDBC_DATA_TYPE12":12
    },
    {
        "COLUMN_NAME":"Start Date",
        "DATA_TYPE":"VARCHAR",
        "ORDINAL_POSITION":3,
        "JDBC_DATA_TYPE12":12
    },
    {
        "COLUMN_NAME":"End Date",
        "DATA_TYPE":"VARCHAR",
        "ORDINAL_POSITION":4,
        "JDBC_DATA_TYPE12":12
    },
    {
        "COLUMN_NAME":"Agent Position",
        "DATA_TYPE":"VARCHAR",
        "ORDINAL_POSITION":5,
        "JDBC_DATA_TYPE12":12
    },
    {
        "COLUMN_NAME":"Customer ID",
        "DATA_TYPE":"VARCHAR",
        "ORDINAL_POSITION":6,
        "JDBC_DATA_TYPE12":12
    },
    {
        "COLUMN_NAME":"Product",
        "DATA_TYPE":"VARCHAR",
        "ORDINAL_POSITION":7,
        "JDBC_DATA_TYPE12":12
    },
    {
        "COLUMN_NAME":"Service Type",
        "DATA_TYPE":"VARCHAR",
        "ORDINAL_POSITION":8,
        "JDBC_DATA_TYPE12":12
    },
    {
        "COLUMN_NAME":"Agent",
        "DATA_TYPE":"VARCHAR",
        "ORDINAL_POSITION":9,
        "JDBC_DATA_TYPE12":12
    }
    ]
}

i have tried to follow : Decoding structured JSON arrays with circe in Scala as an advice but some methods no longer exists such as deleteGoRight, etc..

i have attempted to try something like :

implicit val decoder: Decoder[Schema] = { (hCursor: HCursor) =>
    for {
      colName <- hCursor.as[String]
      colNameC = hCursor.delete
      dtype <- colNameC.right.as[String]
      dtypeC = colNameC.delete
      pos <- dtypeC.right.as[Double]
      posC = dtypeC.delete
      jtype <- posC.right.as[Double]
    } yield Schema(colName, dtype, pos, jtype) }

  parser.decode[List[Schema]]("""["Service Type","VARCHAR",8,12]""") match {
    case Right(applicants) => println(applicants)
    case Left(ex) => println(s"Oops something is wrong with decoding value ${ex}")
  }

but it fails to decode, and the errors are hard to interpret.


Solution

  • You can use downN method on HCursor to access particular element from a list.

    import io.circe.parser.decode
    import io.circe.{Decoder, HCursor, _}
    
    object Main extends App {
    
      val payload =
        """[
          |    [
          |        "Service ID",
          |        "VARCHAR",
          |        1,
          |        12
          |    ],
          |    [
          |        "Operation",
          |        "VARCHAR",
          |        2,
          |        12
          |    ]
          |]""".stripMargin
    
    
      val schemas: Either[Error, List[Schema]] = decode[List[Schema]](payload)
      println(schemas)
    }
    
    case class Schema(name: String, dataType: String, position: Int, jdbcType: Int)
    
    object Schema {
    
      implicit val schemaDecoder: Decoder[Schema] = (c: HCursor) => for {
        name <- c.downN(0).as[String]
        dataType <- c.downN(1).as[String]
        position <- c.downN(2).as[Int]
        jdbcType <- c.downN(3).as[Int]
      } yield Schema(name, dataType, position, jdbcType)
    }