Conversation
Encode floating-point values in Spanner JSON using a Ruby port of Nlohmann's Grisu2 algorithm. This produces the decimal representations expected by Spanner's precision checks while keeping the formatting scoped to Spanner JSON values. Cover JSON attributes and arrays, query parameters, and SDK mutations, with exact-output fixtures and serialization isolation tests. Co-authored-by: Codex <codex@openai.com>
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
There was a problem hiding this comment.
Code Review
This pull request introduces a pure Ruby port of the Grisu2 algorithm from nlohmann/json 3.11.3 to format finite floats before encoding JSON documents, ensuring decimal precision is preserved during round-trips with Google Spanner. It integrates this formatter into a custom ActiveRecord JSON type and prepends it to the Google Cloud Spanner client conversion logic. The feedback highlights a critical compatibility issue in FloatFormatter where appending an integer directly to a string using << will raise a TypeError in Ruby 3.2 and later, and suggests using .chr to convert the character codes first.
|
|
||
| while length.positive? | ||
| digit, integral = integral.divmod power_of_ten | ||
| digits << (48 + digit) |
There was a problem hiding this comment.
In Ruby 3.2 and later, passing an integer to String#<< raises a TypeError (e.g., no implicit conversion of Integer into String). Since the gemspec specifies required_ruby_version = ">= 3.2", this will cause a runtime crash when formatting floats. Converting the character code to a string using .chr resolves this issue.
digits << (48 + digit).chr| fraction *= 10 | ||
| digit = fraction >> shift | ||
| fraction &= one - 1 | ||
| digits << (48 + digit) |
There was a problem hiding this comment.
In Ruby 3.2 and later, passing an integer to String#<< raises a TypeError (e.g., no implicit conversion of Integer into String). Since the gemspec specifies required_ruby_version = ">= 3.2", this will cause a runtime crash when formatting floats. Converting the character code to a string using .chr resolves this issue.
digits << (48 + digit).chr
This is a pretty awkward one, but spanner requires floats in JSON values are serialized the exact way spanner would internally serialize them (using nlohmann/json). This PR implements ports the implementation of the Grisu2 algorithm from that library to ruby, and adds a custom JSON spanner type to make sure any JSON serialized by activerecord for spanner uses that serialization.
Without this change certain float values will cause queries to fail (1.240425 is an example).