You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@avro.apache.org by tj...@apache.org on 2023/06/16 16:04:20 UTC
[avro] branch master updated: AVRO-3775: [ruby] fix decoded default value of logical type (#2277)
This is an automated email from the ASF dual-hosted git repository.
tjwp pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/avro.git
The following commit(s) were added to refs/heads/master by this push:
new 3b77d40ee AVRO-3775: [ruby] fix decoded default value of logical type (#2277)
3b77d40ee is described below
commit 3b77d40ee13330646b106f3b66ad7670aa9b71b2
Author: Rich <jy...@users.noreply.github.com>
AuthorDate: Fri Jun 16 12:04:14 2023 -0400
AVRO-3775: [ruby] fix decoded default value of logical type (#2277)
Co-authored-by: Tim Perkins <tj...@users.noreply.github.com>
---
lang/ruby/lib/avro/io.rb | 20 ++++---
lang/ruby/test/test_logical_types.rb | 112 ++++++++++++++++++++++++++++++++++-
2 files changed, 121 insertions(+), 11 deletions(-)
diff --git a/lang/ruby/lib/avro/io.rb b/lang/ruby/lib/avro/io.rb
index e6e3b326d..0d2f31358 100644
--- a/lang/ruby/lib/avro/io.rb
+++ b/lang/ruby/lib/avro/io.rb
@@ -390,31 +390,31 @@ module Avro
def read_default_value(field_schema, default_value)
# Basically a JSON Decoder?
- case field_schema.type_sym
+ datum = case field_schema.type_sym
when :null
- return nil
+ nil
when :int, :long
- return Integer(default_value)
+ Integer(default_value)
when :float, :double
- return Float(default_value)
+ Float(default_value)
when :boolean, :enum, :fixed, :string, :bytes
- return default_value
+ default_value
when :array
read_array = []
default_value.each do |json_val|
item_val = read_default_value(field_schema.items, json_val)
read_array << item_val
end
- return read_array
+ read_array
when :map
read_map = {}
default_value.each do |key, json_val|
map_val = read_default_value(field_schema.values, json_val)
read_map[key] = map_val
end
- return read_map
+ read_map
when :union
- return read_default_value(field_schema.schemas[0], default_value)
+ read_default_value(field_schema.schemas[0], default_value)
when :record, :error
read_record = {}
field_schema.fields.each do |field|
@@ -423,11 +423,13 @@ module Avro
field_val = read_default_value(field.type, json_val)
read_record[field.name] = field_val
end
- return read_record
+ read_record
else
fail_msg = "Unknown type: #{field_schema.type}"
raise AvroError, fail_msg
end
+
+ field_schema.type_adapter.decode(datum)
end
def skip_data(writers_schema, decoder)
diff --git a/lang/ruby/test/test_logical_types.rb b/lang/ruby/test/test_logical_types.rb
index f42b5fe2e..3aeb34983 100644
--- a/lang/ruby/test/test_logical_types.rb
+++ b/lang/ruby/test/test_logical_types.rb
@@ -124,6 +124,113 @@ class TestLogicalTypes < Test::Unit::TestCase
end
end
+ def test_logical_type_default_value
+ sales_schema = Avro::Schema.parse('{
+ "type": "record",
+ "name": "Order",
+ "fields" : [
+ {
+ "name": "sales",
+ "type": [
+ {
+ "type": "bytes",
+ "logicalType": "decimal",
+ "precision": 4,
+ "scale": 2
+ },
+ "null"
+ ],
+ "default": "\u0000"
+ }
+ ]
+ }')
+
+ sales_tax_schema = Avro::Schema.parse('{
+ "type": "record",
+ "name": "Order",
+ "fields" : [
+ {
+ "name": "sales",
+ "type": [
+ {
+ "type": "bytes",
+ "logicalType": "decimal",
+ "precision": 4,
+ "scale": 2
+ },
+ "null"
+ ],
+ "default": "\u0000"
+ },
+ {
+ "name": "tax",
+ "type": [
+ {
+ "type": "bytes",
+ "logicalType": "decimal",
+ "precision": 4,
+ "scale": 2
+ },
+ "null"
+ ],
+ "default": "\u0000"
+ },
+ {
+ "name": "invoice_date",
+ "type": [
+ {
+ "type": "int",
+ "logicalType": "date"
+ },
+ "null"
+ ],
+ "default": 0
+ },
+ {
+ "name": "invoice_time",
+ "type": [
+ {
+ "type": "int",
+ "logicalType": "time-millis"
+ },
+ "null"
+ ],
+ "default": 0
+ },
+ {
+ "name": "created_at",
+ "type": [
+ {
+ "type": "long",
+ "logicalType": "timestamp-millis"
+ },
+ "null"
+ ],
+ "default": 0
+ }
+ ]
+ }')
+
+ sales_record = {"sales" => BigDecimal("12.34")}
+ sales_tax_record = {
+ "sales" => BigDecimal("12.34"),
+ "tax" => BigDecimal("0.000"),
+ "invoice_date" => Time.at(0).to_date,
+ # time-millis is not supported
+ "invoice_time" => 0,
+ "created_at" => Time.at(0).utc,
+ }
+ encoded = encode(sales_record, sales_schema)
+ assert_equal sales_record, decode(encoded, sales_schema)
+ # decode with different schema applies default
+ assert_equal sales_tax_record, decode(encoded, sales_tax_schema, writer_schema: sales_schema)
+
+ # decode with same schema does not apply default, since it is nullable during encode
+ encoded = encode(sales_record, sales_tax_schema)
+ tax_nil_record = {"sales" => BigDecimal("12.34"), "tax" => nil, "invoice_date" => nil, "invoice_time" => nil, "created_at" => nil}
+ assert_equal tax_nil_record, decode(encoded, sales_tax_schema)
+ end
+
def test_bytes_decimal_range_errors
schema = Avro::Schema.parse <<-SCHEMA
{ "type": "bytes", "logicalType": "decimal", "precision": 4, "scale": 2 }
@@ -243,11 +350,12 @@ class TestLogicalTypes < Test::Unit::TestCase
buffer.string
end
- def decode(encoded, schema)
+ def decode(encoded, schema, writer_schema: nil)
+ writer_schema ||= schema
buffer = StringIO.new(encoded)
decoder = Avro::IO::BinaryDecoder.new(buffer)
- datum_reader = Avro::IO::DatumReader.new(schema, schema)
+ datum_reader = Avro::IO::DatumReader.new(writer_schema, schema)
datum_reader.read(decoder)
end