Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Uable to access nested json field #4

Open
grzegorz-taramina opened this issue Jul 31, 2023 · 4 comments
Open

Uable to access nested json field #4

grzegorz-taramina opened this issue Jul 31, 2023 · 4 comments
Assignees
Labels
enhancement New feature or request

Comments

@grzegorz-taramina
Copy link

Hi,
I'm trying to use json logic scala for very common case which is accessing field in nested data object.

I have the following data structure:
{ "booking" : { "ref" : 123 }, "test" : 666 }

And the following rule:
{ "<" : [ { "var" : "booking.ref", "type" : { "codename" : "int" } }, { "var" : "test", "type" : { "codename" : "int" } } ] }

Deserialization fails becasue I don't have "booking.ref" field in my data strucutre but I do have booking \ ref.
Does that mean json-logic-scala can only handle root level data fields?
When I change "booking": { "ref":"..." } to "booking.ref" : 444 it works but it's really not what I need.

@celadari
Copy link
Owner

celadari commented Aug 8, 2023

Hello @grzegorz-taramina ,

Sorry for the late reply (I was afk for the last two weeks).

Current version do not accept accessing in nested data object. This can be added.

Is one of these alternatives what you're looking for:

  • put every field at root level (I think this is not what you're looking for)
  • define a type Booking (`case class Booking(ref){def } {def $less(num: java.lang.Integer): java.lang.Boolean = ref < num}' )

If not what you're looking for, we can see how to add the nested data structure field accessing

@grzegorz-taramina
Copy link
Author

grzegorz-taramina commented Aug 8, 2023

Hey @celadari,
Thanks for the reply.
I've managed to solve this issue overriding deserializeValueLogic function (Deserializer) like that:

`override protected[this] def deserializeValueLogic(jsonLogic: JsObject, jsonLogicData: JsObject): ValueLogic[_] = {
val isTypeDefined = (jsonLogic \ "type").isDefined
val typeValueOpt = Deserializer.unmarshType(jsonLogic \ "type")
val pathData = (jsonLogic \ "var").as[String]
val split = pathData.split("\.")

val lookUpPathData = if (split.isEmpty) {
  jsonLogicData \ pathData
} else {
  split.tail.foldLeft(jsonLogicData \ split.head)((b, a) => {
    b \ a
  })
}
val jsValue = lookUpPathData.getOrElse(JsNull)

if (isTypeDefined && lookUpPathData.isEmpty) {
  throw new InvalidJsonParsingException(s"""Error while parsing ValueLogic of type value: "var" $pathData is undefined""")
}
if (!isTypeDefined && lookUpPathData.isDefined) {
  throw new InvalidJsonParsingException(
    """Error while parsing ValueLogic of type variable: "var" must not be a key on data dictionary.""" +
      s"""\nActual: "$pathData"""")
}

val valueOpt = typeValueOpt.flatMap(typeValue => Option(getUnmarshaller(typeValue).unmarshal(jsValue)))
val variableNameOpt = if (lookUpPathData.isDefined) None else Some(pathData)
val pathDataOpt = if (lookUpPathData.isDefined) Some(pathData) else None

ValueLogic(valueOpt, typeValueOpt, variableNameOpt, pathDataOpt)

}`

Maybe it's worth adding that to the library as usual scenario for using jsonlogic is passing complex objects to jsonlogic engine.

Cheers

@celadari
Copy link
Owner

celadari commented Aug 8, 2023

Clever move, I will check if adding this line doesn't break unit and functional tests.

I'll let you know :)

@celadari celadari self-assigned this Aug 8, 2023
@celadari celadari added the enhancement New feature or request label Aug 8, 2023
@grzegorz-taramina
Copy link
Author

Hey @celadari,
Any update on this enhancement ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants