-
-
Notifications
You must be signed in to change notification settings - Fork 248
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
bigdecimal_as_decimal
doesn't work in compat
mode
#632
Comments
Looks like a bug. I'll get it fixed assuming it does differ from the JSON gem. If not we may need to discuss other options. |
@ohler55 I think I think for now my option option is to go with |
The JSON gem does have a secret option Would it be helpful if I listed the options needed to configure custom mode to be like compat? |
@ohler55 yes that would be very useful for my case! I'm already aware of What about Oj, in default mode it works: decimal = BigDecimal('1') / BigDecimal('3')
hash = { bc: decimal }
oj_dump_default = Oj.dump(hash) # {":bc":0.333333333333333333e0}
Oj.load(oj_dump_default) == hash # true
# test that `:bigdecimal_as_decimal` works
Oj.dump(hash, bigdecimal_as_decimal: false) # {":bc":"0.333333333333333333e0"} In the last test it produces string instead of scientific notation as it should with bigdecimal_as_decimal turned off In compat mode: oj_dump_compat = Oj.dump(hash, mode: :compat, bigdecimal_as_decimal: true) # {"bc":"0.333333333333333333e0"}
Oj.load(oj_dump_compat, mode: :compat, bigdecimal_as_decimal: true) # {"bc"=>"0.333333333333333333e0"}
Oj.load(oj_dump_compat, mode: :compat, bigdecimal_as_decimal: true) == hash # false This doesn't work because |
oops, that was a mistake. It should have been on the bigdecimal_load. I'll fix that but I think the solution for you will be custom mode. |
V3.10.18 corrects the documentation on bigdecimal. A new constant was also added that can be used to set the default options to be custom mode but matching compat mode. It is |
Thanks a lot! I already started testing custom mode in our staging environment, CUSTOM_MIMIC_JSON_OPTIONS hash will help a lot, I tried to find these in ruby code but looks like most of it sits in C code logic. In our system we use JSON to exchange information between different internal APIs but at the same time we use it for JS front-end so we can't use object mode or "additions" from JSON, I have been trying to fight bigdecimals for a long time converting them into floats but our DB calculations usually return bigdecimals so it was pain, now I look forward to move everything to bigdecimal and forget about fighting formats. Thanks once again for quick response! |
Hope it works out well for you. If not let me know. |
I think I figured out working scheme for us: Oj.default_options = Oj::CUSTOM_MIMIC_JSON_OPTIONS.merge(
{ bigdecimal_as_decimal: true, use_to_json: false }
)
|
That could be the case since setting the |
Does the latest set of changes for compat mode solve your issue? |
@ohler55 YES thanks! I've rolled out the above config as drop-in replacement for JSON gem in production and it fixed issues for us with decimals since we depend on them a lot. Also based on our metrics with JSON gem our system was spending ~5500 second of CPU time on just JSON encoding daily, now with OJ it dropped to 800-1000 seconds daily (these figures are not exact json/oj metrics comparison because we also did some other optimizations as well but OJ definitely played big role there) I really think JSON gem is broken based on https://json-schema.org/understanding-json-schema/reference/numeric.html#number spec where it describes "Exponential notation also works". I've found other threads online where people complain about JSON gem that it doesn't support exporting decimals properly and it breaks compatibility with JSON based databases and storages in AWS, our case was similar but it was breaking other systems compatibility. Also it could break JavaScript in cases for example when you need to manipulate JSON parsed number like: So having option to control this is really useful for advanced cases! I wonder why not that many complain about it yet. UPDATE I didn't test |
Let me know when you do test. If it looks good this issue can be closed. Remember compat mode tries to mimic the JSON gem so compat mode may not be what you want. Custom mode may be more to your liking. |
ok I'll test - I don't promise I could test it this week maybe next one, have pretty big backlog right now, but for us it's more critical to be JSON spec compatible than json gem in a long term. |
No rush here. Take your time and let me know if you need anything else. |
@ohler55 hi again, I'm not sure it's related but I came across this issue when figuring what's wrong with Sinatra json encoder which I set like: btw there is Sinatra doc for it http://sinatrarb.com/contrib/json and it probes for two methods # configure my default options
Oj.default_options = Oj::CUSTOM_MIMIC_JSON_OPTIONS.merge(
{ bigdecimal_as_decimal: true, use_to_json: false }
)
Oj.generate
# "null"
Oj.dump
# ArgumentError: wrong number of arguments (0 for 1).
# from (pry):2:in `dump'
var = { c: BigDecimal('1') / BigDecimal('3') }
# {:c=>0.333333333333333333e0}
puts Oj.generate var
# {"c":"0.333333333333333333e0"}
puts Oj.dump var
# {"c":0.333333333333333333e0} I'm pretty sure we should not use I've been confused because JSON do have both methods |
btw similar case with MultiJson, it looks like they mess with Oj default options: Oj.default_options = Oj::CUSTOM_MIMIC_JSON_OPTIONS.merge(
{ bigdecimal_as_decimal: true, use_to_json: false }
)
var = { c: BigDecimal('1') / BigDecimal('3') }
MultiJson.adapter
# MultiJson::Adapters::Oj
puts MultiJson.encode var
# {"c":"0.333333333333333333e0"}
MultiJson.dump_options = Oj.default_options
puts MultiJson.encode var
# {"c":0.333333333333333333e0} Definitely not an issue of Oj, just leaving it here in case if anyone stumbles on it |
The generate method is for compatibility with the JSON which forces the precision that gem uses. Thanks for the notes. |
As I understood from Modes Matrix
compat
mode should support settingbigdecimal_as_decimal
but it looks like not:However I expect that decimal be dumped without quotes, like it does in
custom
mode:I basically want
:compat
mode with decimals dumped as decimalsThe text was updated successfully, but these errors were encountered: