tidwall / gjson

Get JSON values quickly - JSON parser for Go
MIT License
14.1k stars 846 forks source link

How to query JSON including literal field/values in the output? #249

Closed natenho closed 2 years ago

natenho commented 2 years ago

I'm building a JSON transformation feature using GJSON and the use case is to parse an input and generate a transformed JSON, but also including extra fields (i.e. fields/values not present in the source JSON). Is that possible with GJSON? Example:

Given the following input (from GJSON playground):

{
  "name": {"first": "Tom", "last": "Anderson"}
}

When the input is {name.last,"foo":name.first}, the result is {"last":"Anderson","foo":"Tom"}

But when the input is {name.last,"foo":"bar"}, the result is: {"last":"Anderson"}

I expected that the result would be {"last":"Anderson","foo":"bar"}

Is there any way to achieve that?

tidwall commented 2 years ago

Right now everything is a path. There is no way to embed static json.

That said, I think it would be pretty cool to have this functionality. I think it could be a nice extension to the library.

Perhaps we can include a new character that indicates that the value is static json.

In this case I'm using the '!' to tell gjson the value is static.

{name.last,"foo":!"bar"}            =>   {"last":"Anderson","foo":"bar"}
{name.last,"foo":!{"bar":"thing"}}  =>   {"last":"Anderson","foo":{"bar":"thing"}}

I pushed this feature for testing to the master branch and to the GJSON Playground.

natenho commented 2 years ago

@tidwall Wow, that was fast! Fantastic! In the playground it has worked very well, I'll do a couple of tests in code but I think it surely will fit my use case. Thank you!

natenho commented 2 years ago

@tidwall I wonder if it could be made without the declaration character "!" though...maybe using some sort of fallback: in case of inexistent source path and the token is a valid string/number, assume static content, the feature would be more intuitive for anyone using gjson. What do you think?

Examples:

{name.last,"foo":bar}            =>    {"last":"Anderson"}
{name.last,"foo":999}            =>    {"last":"Anderson","foo":999}
{name.last,"foo":{"bar":name.last}}  =>   {"last":"Anderson","foo":{"bar":"Anderson"}}
{name.last,"foo":{"bar":"thing"}}  =>   {"last":"Anderson","foo":{"bar":"thing"}}
natenho commented 2 years ago

@tidwall I wonder if it could be made without the declaration character "!" though...maybe using some sort of fallback: in case of inexistent source path and the token is a valid string/number, assume static content, the feature would be more intuitive for anyone using gjson. What do you think?

Examples:

{name.last,"foo":bar}            =>    {"last":"Anderson"}
{name.last,"foo":999}            =>    {"last":"Anderson","foo":999}
{name.last,"foo":{"bar":name.last}}  =>   {"last":"Anderson","foo":{"bar":"Anderson"}}
{name.last,"foo":{"bar":"thing"}}  =>   {"last":"Anderson","foo":{"bar":"thing"}}

ok, on second thought it may not be possible due to the ambiguation over optional json fields and booleans :(

tidwall commented 2 years ago

I agree. I wish there was a way to avoid the declaration character.

For strings, because they are wrapped in quotes, we may possibly get away with forgoing the !. Though possible, it's probably rare to come across an object with a key that extra quotes in it, like { "\"name\"": "Anderson" }. But for most other json literals, like true, false, null, and numbers; these all can be represented as object keys.

I feel that to distinguish the literals from gjson paths, something like ! is needed.

Perhaps there's a better way. I'm open to suggestions.

natenho commented 2 years ago

@tidwall the feature worked really well for me. I'm closing this issue since it was shipped in the last minor release. Thank you again for the support! ;)