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

circe.CirceSolver.scala Maven / Gradle / Ivy

/*
 * Copyright 2023 Filippo De Luca
 *
 * Licensed 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.filippodeluca.jsonpath
package circe

import io.circe.Json

import com.filippodeluca.jsonpath.ast.*

object CirceSolver {
  // TODO Shall we use ADT instead?
  class Context(values: Vector[Json], root: Json) extends Ctx[Context, Json](values, root) {
    def one(value: Json, root: Json) = Context.one(value, root)
    def many(values: Vector[Json], root: Json) = new Context(values, root)
    def current = this

    def nullCtx(root: Json) = Context.one(Json.Null, root)
    def stringCtx(value: String, root: Json) = Context.one(Json.fromString(value), root)
    def booleanCtx(value: Boolean, root: Json) = Context.one(Json.fromBoolean(value), root)
    def numberCtx(value: Double, root: Json) =
      Context.one(Json.fromDouble(value).getOrElse(Json.fromBigDecimal(BigDecimal(value))), root)

    def arrayValue(json: Json): Option[Vector[Json]] = json.asArray
    def arrayToValue(arr: Vector[Json]): Json = Json.fromValues(arr)

    def mapValue(json: Json): Option[Map[String, Json]] = json.asObject.map(_.toMap)

    def propertyKey(json: Json): Option[String] = {
      json.asString
        .orElse(json.asNumber.map(_.toDouble.toString))
        .orElse(json.asBoolean.map(_.toString))
    }

    def stringValue(json: Json): Option[String] = json.asString

    def intValue(json: Json): Option[Int] = json.asNumber.flatMap(_.toInt)

    def doubleValue(json: Json): Option[Double] = json.asNumber.map(_.toDouble)

    // According to https://www.sitepoint.com/javascript-truthy-falsy/
    def booleanValue(json: Json): Boolean = {
      val isFalse = json.fold[Boolean](
        true,
        _ == false,
        jsn => jsn.toBigDecimal.exists(_ == BigDecimal(0)) || jsn.toDouble == 0d,
        _.isEmpty,
        _ => false,
        _ => false
      )
      !isFalse
    }
  }

  object Context {
    def one(value: Json, root: Json) = new Context(Vector(value), root)
  }

  def solve(exp: ast.Exp, source: Json): Vector[Json] = {
    val sourceCtx = Context.one(source, source)
    sourceCtx.loop(exp).values
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy