avro 1.8.2 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Manifest +6 -0
- data/avro.gemspec +21 -21
- data/lib/avro.rb +11 -0
- data/lib/avro/io.rb +44 -64
- data/lib/avro/ipc.rb +8 -8
- data/lib/avro/logical_types.rb +90 -0
- data/lib/avro/protocol.rb +11 -7
- data/lib/avro/schema.rb +89 -63
- data/lib/avro/schema_compatibility.rb +170 -0
- data/lib/avro/schema_validator.rb +242 -0
- data/test/random_data.rb +21 -2
- data/test/test_datafile.rb +3 -3
- data/test/test_io.rb +73 -6
- data/test/test_logical_types.rb +128 -0
- data/test/test_protocol.rb +36 -3
- data/test/test_schema.rb +323 -27
- data/test/test_schema_compatibility.rb +475 -0
- data/test/test_schema_validator.rb +554 -0
- data/test/tool.rb +0 -1
- metadata +20 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1e128a7db859ace5ff9b558f8c43a5a7f1c79ee5
|
|
4
|
+
data.tar.gz: dedca07a2a2f32894edded0b785d0c7954b65246
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5393149d588e12974d8036cd76b63b96b2698cc02fec3608fea7d88ecec936e5c5b81444252b0e1d42932f08299ff89b81828a7e7f877e7c67faf4713b07d979
|
|
7
|
+
data.tar.gz: b0f8c39b2fdabe08e5769e05baf1036969753be9e93ecabd1c6230df9f839167b43cc1bbea523439a430ed624d5243c7926b44867961422785010412f132dd91
|
data/Manifest
CHANGED
|
@@ -9,9 +9,12 @@ lib/avro.rb
|
|
|
9
9
|
lib/avro/data_file.rb
|
|
10
10
|
lib/avro/io.rb
|
|
11
11
|
lib/avro/ipc.rb
|
|
12
|
+
lib/avro/logical_types.rb
|
|
12
13
|
lib/avro/protocol.rb
|
|
13
14
|
lib/avro/schema.rb
|
|
15
|
+
lib/avro/schema_compatibility.rb
|
|
14
16
|
lib/avro/schema_normalization.rb
|
|
17
|
+
lib/avro/schema_validator.rb
|
|
15
18
|
test/case_finder.rb
|
|
16
19
|
test/random_data.rb
|
|
17
20
|
test/sample_ipc_client.rb
|
|
@@ -22,8 +25,11 @@ test/test_datafile.rb
|
|
|
22
25
|
test/test_fingerprints.rb
|
|
23
26
|
test/test_help.rb
|
|
24
27
|
test/test_io.rb
|
|
28
|
+
test/test_logical_types.rb
|
|
25
29
|
test/test_protocol.rb
|
|
26
30
|
test/test_schema.rb
|
|
31
|
+
test/test_schema_compatibility.rb
|
|
27
32
|
test/test_schema_normalization.rb
|
|
33
|
+
test/test_schema_validator.rb
|
|
28
34
|
test/test_socket_transport.rb
|
|
29
35
|
test/tool.rb
|
data/avro.gemspec
CHANGED
|
@@ -1,35 +1,35 @@
|
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
|
2
|
-
# stub: avro 1.
|
|
2
|
+
# stub: avro 1.9.0 ruby lib
|
|
3
3
|
|
|
4
4
|
Gem::Specification.new do |s|
|
|
5
|
-
s.name = "avro"
|
|
6
|
-
s.version = "1.
|
|
5
|
+
s.name = "avro".freeze
|
|
6
|
+
s.version = "1.9.0"
|
|
7
7
|
|
|
8
|
-
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
|
9
|
-
s.require_paths = ["lib"]
|
|
10
|
-
s.authors = ["Apache Software Foundation"]
|
|
11
|
-
s.date = "
|
|
12
|
-
s.description = "Avro is a data serialization and RPC format"
|
|
13
|
-
s.email = "dev@avro.apache.org"
|
|
14
|
-
s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "lib/avro.rb", "lib/avro/data_file.rb", "lib/avro/io.rb", "lib/avro/ipc.rb", "lib/avro/protocol.rb", "lib/avro/schema.rb", "lib/avro/schema_normalization.rb"]
|
|
15
|
-
s.files = ["CHANGELOG", "LICENSE", "Manifest", "NOTICE", "Rakefile", "avro.gemspec", "interop/test_interop.rb", "lib/avro.rb", "lib/avro/data_file.rb", "lib/avro/io.rb", "lib/avro/ipc.rb", "lib/avro/protocol.rb", "lib/avro/schema.rb", "lib/avro/schema_normalization.rb", "test/case_finder.rb", "test/random_data.rb", "test/sample_ipc_client.rb", "test/sample_ipc_http_client.rb", "test/sample_ipc_http_server.rb", "test/sample_ipc_server.rb", "test/test_datafile.rb", "test/test_fingerprints.rb", "test/test_help.rb", "test/test_io.rb", "test/test_protocol.rb", "test/test_schema.rb", "test/test_schema_normalization.rb", "test/test_socket_transport.rb", "test/tool.rb"]
|
|
16
|
-
s.homepage = "http://avro.apache.org/"
|
|
17
|
-
s.licenses = ["Apache License 2.0 (Apache-2.0)"]
|
|
18
|
-
s.rdoc_options = ["--line-numbers", "--title", "Avro"]
|
|
19
|
-
s.rubyforge_project = "avro"
|
|
20
|
-
s.rubygems_version = "2.2.
|
|
21
|
-
s.summary = "Apache Avro for Ruby"
|
|
22
|
-
s.test_files = ["test/
|
|
8
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2".freeze) if s.respond_to? :required_rubygems_version=
|
|
9
|
+
s.require_paths = ["lib".freeze]
|
|
10
|
+
s.authors = ["Apache Software Foundation".freeze]
|
|
11
|
+
s.date = "2019-05-21"
|
|
12
|
+
s.description = "Avro is a data serialization and RPC format".freeze
|
|
13
|
+
s.email = "dev@avro.apache.org".freeze
|
|
14
|
+
s.extra_rdoc_files = ["CHANGELOG".freeze, "LICENSE".freeze, "lib/avro.rb".freeze, "lib/avro/data_file.rb".freeze, "lib/avro/io.rb".freeze, "lib/avro/ipc.rb".freeze, "lib/avro/logical_types.rb".freeze, "lib/avro/protocol.rb".freeze, "lib/avro/schema.rb".freeze, "lib/avro/schema_compatibility.rb".freeze, "lib/avro/schema_normalization.rb".freeze, "lib/avro/schema_validator.rb".freeze]
|
|
15
|
+
s.files = ["CHANGELOG".freeze, "LICENSE".freeze, "Manifest".freeze, "NOTICE".freeze, "Rakefile".freeze, "avro.gemspec".freeze, "interop/test_interop.rb".freeze, "lib/avro.rb".freeze, "lib/avro/data_file.rb".freeze, "lib/avro/io.rb".freeze, "lib/avro/ipc.rb".freeze, "lib/avro/logical_types.rb".freeze, "lib/avro/protocol.rb".freeze, "lib/avro/schema.rb".freeze, "lib/avro/schema_compatibility.rb".freeze, "lib/avro/schema_normalization.rb".freeze, "lib/avro/schema_validator.rb".freeze, "test/case_finder.rb".freeze, "test/random_data.rb".freeze, "test/sample_ipc_client.rb".freeze, "test/sample_ipc_http_client.rb".freeze, "test/sample_ipc_http_server.rb".freeze, "test/sample_ipc_server.rb".freeze, "test/test_datafile.rb".freeze, "test/test_fingerprints.rb".freeze, "test/test_help.rb".freeze, "test/test_io.rb".freeze, "test/test_logical_types.rb".freeze, "test/test_protocol.rb".freeze, "test/test_schema.rb".freeze, "test/test_schema_compatibility.rb".freeze, "test/test_schema_normalization.rb".freeze, "test/test_schema_validator.rb".freeze, "test/test_socket_transport.rb".freeze, "test/tool.rb".freeze]
|
|
16
|
+
s.homepage = "http://avro.apache.org/".freeze
|
|
17
|
+
s.licenses = ["Apache License 2.0 (Apache-2.0)".freeze]
|
|
18
|
+
s.rdoc_options = ["--line-numbers".freeze, "--title".freeze, "Avro".freeze]
|
|
19
|
+
s.rubyforge_project = "avro".freeze
|
|
20
|
+
s.rubygems_version = "2.5.2.1".freeze
|
|
21
|
+
s.summary = "Apache Avro for Ruby".freeze
|
|
22
|
+
s.test_files = ["test/test_schema_validator.rb".freeze, "test/test_help.rb".freeze, "test/test_schema_normalization.rb".freeze, "test/test_datafile.rb".freeze, "test/test_schema.rb".freeze, "test/test_io.rb".freeze, "test/test_socket_transport.rb".freeze, "test/test_schema_compatibility.rb".freeze, "test/test_logical_types.rb".freeze, "test/test_fingerprints.rb".freeze, "test/test_protocol.rb".freeze]
|
|
23
23
|
|
|
24
24
|
if s.respond_to? :specification_version then
|
|
25
25
|
s.specification_version = 4
|
|
26
26
|
|
|
27
27
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
|
28
|
-
s.add_runtime_dependency(%q<multi_json
|
|
28
|
+
s.add_runtime_dependency(%q<multi_json>.freeze, [">= 0"])
|
|
29
29
|
else
|
|
30
|
-
s.add_dependency(%q<multi_json
|
|
30
|
+
s.add_dependency(%q<multi_json>.freeze, [">= 0"])
|
|
31
31
|
end
|
|
32
32
|
else
|
|
33
|
-
s.add_dependency(%q<multi_json
|
|
33
|
+
s.add_dependency(%q<multi_json>.freeze, [">= 0"])
|
|
34
34
|
end
|
|
35
35
|
end
|
data/lib/avro.rb
CHANGED
|
@@ -32,6 +32,15 @@ module Avro
|
|
|
32
32
|
super(msg)
|
|
33
33
|
end
|
|
34
34
|
end
|
|
35
|
+
|
|
36
|
+
class << self
|
|
37
|
+
attr_writer :disable_field_default_validation
|
|
38
|
+
|
|
39
|
+
def disable_field_default_validation
|
|
40
|
+
@disable_field_default_validation ||=
|
|
41
|
+
ENV.fetch('AVRO_DISABLE_FIELD_DEFAULT_VALIDATION', '') != ''
|
|
42
|
+
end
|
|
43
|
+
end
|
|
35
44
|
end
|
|
36
45
|
|
|
37
46
|
require 'avro/schema'
|
|
@@ -40,3 +49,5 @@ require 'avro/data_file'
|
|
|
40
49
|
require 'avro/protocol'
|
|
41
50
|
require 'avro/ipc'
|
|
42
51
|
require 'avro/schema_normalization'
|
|
52
|
+
require 'avro/schema_validator'
|
|
53
|
+
require 'avro/schema_compatibility'
|
data/lib/avro/io.rb
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
# to you under the Apache License, Version 2.0 (the
|
|
6
6
|
# "License"); you may not use this file except in compliance
|
|
7
7
|
# with the License. You may obtain a copy of the License at
|
|
8
|
-
#
|
|
8
|
+
#
|
|
9
9
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
-
#
|
|
10
|
+
#
|
|
11
11
|
# Unless required by applicable law or agreed to in writing, software
|
|
12
12
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
13
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
@@ -43,9 +43,9 @@ module Avro
|
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
def byte!
|
|
46
|
-
@reader.
|
|
46
|
+
@reader.readbyte
|
|
47
47
|
end
|
|
48
|
-
|
|
48
|
+
|
|
49
49
|
def read_null
|
|
50
50
|
# null is written as zero byte's
|
|
51
51
|
nil
|
|
@@ -76,7 +76,7 @@ module Avro
|
|
|
76
76
|
# The float is converted into a 32-bit integer using a method
|
|
77
77
|
# equivalent to Java's floatToIntBits and then encoded in
|
|
78
78
|
# little-endian format.
|
|
79
|
-
|
|
79
|
+
read_and_unpack(4, 'e'.freeze)
|
|
80
80
|
end
|
|
81
81
|
|
|
82
82
|
def read_double
|
|
@@ -84,7 +84,7 @@ module Avro
|
|
|
84
84
|
# The double is converted into a 64-bit integer using a method
|
|
85
85
|
# equivalent to Java's doubleToLongBits and then encoded in
|
|
86
86
|
# little-endian format.
|
|
87
|
-
|
|
87
|
+
read_and_unpack(8, 'E'.freeze)
|
|
88
88
|
end
|
|
89
89
|
|
|
90
90
|
def read_bytes
|
|
@@ -97,7 +97,7 @@ module Avro
|
|
|
97
97
|
# A string is encoded as a long followed by that many bytes of
|
|
98
98
|
# UTF-8 encoded character data.
|
|
99
99
|
read_bytes.tap do |string|
|
|
100
|
-
string.force_encoding(
|
|
100
|
+
string.force_encoding('UTF-8'.freeze) if string.respond_to? :force_encoding
|
|
101
101
|
end
|
|
102
102
|
end
|
|
103
103
|
|
|
@@ -144,6 +144,23 @@ module Avro
|
|
|
144
144
|
def skip(n)
|
|
145
145
|
reader.seek(reader.tell() + n)
|
|
146
146
|
end
|
|
147
|
+
|
|
148
|
+
private
|
|
149
|
+
|
|
150
|
+
# Optimize unpacking strings when `unpack1` is available (ruby >= 2.4)
|
|
151
|
+
if String.instance_methods.include?(:unpack1)
|
|
152
|
+
|
|
153
|
+
def read_and_unpack(byte_count, format)
|
|
154
|
+
@reader.read(byte_count).unpack1(format)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
else
|
|
158
|
+
|
|
159
|
+
def read_and_unpack(byte_count, format)
|
|
160
|
+
@reader.read(byte_count).unpack(format)[0]
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
end
|
|
147
164
|
end
|
|
148
165
|
|
|
149
166
|
# Write leaf values
|
|
@@ -159,7 +176,7 @@ module Avro
|
|
|
159
176
|
nil
|
|
160
177
|
end
|
|
161
178
|
|
|
162
|
-
# a boolean is written as a single byte
|
|
179
|
+
# a boolean is written as a single byte
|
|
163
180
|
# whose value is either 0 (false) or 1 (true).
|
|
164
181
|
def write_boolean(datum)
|
|
165
182
|
on_disk = datum ? 1.chr : 0.chr
|
|
@@ -175,7 +192,6 @@ module Avro
|
|
|
175
192
|
# int and long values are written using variable-length,
|
|
176
193
|
# zig-zag coding.
|
|
177
194
|
def write_long(n)
|
|
178
|
-
foo = n
|
|
179
195
|
n = (n << 1) ^ (n >> 63)
|
|
180
196
|
while (n & ~0x7F) != 0
|
|
181
197
|
@writer.write(((n & 0x7f) | 0x80).chr)
|
|
@@ -189,7 +205,7 @@ module Avro
|
|
|
189
205
|
# equivalent to Java's floatToIntBits and then encoded in
|
|
190
206
|
# little-endian format.
|
|
191
207
|
def write_float(datum)
|
|
192
|
-
@writer.write([datum].pack('e'))
|
|
208
|
+
@writer.write([datum].pack('e'.freeze))
|
|
193
209
|
end
|
|
194
210
|
|
|
195
211
|
# A double is written as 8 bytes.
|
|
@@ -197,7 +213,7 @@ module Avro
|
|
|
197
213
|
# equivalent to Java's doubleToLongBits and then encoded in
|
|
198
214
|
# little-endian format.
|
|
199
215
|
def write_double(datum)
|
|
200
|
-
@writer.write([datum].pack('E'))
|
|
216
|
+
@writer.write([datum].pack('E'.freeze))
|
|
201
217
|
end
|
|
202
218
|
|
|
203
219
|
# Bytes are encoded as a long followed by that many bytes of data.
|
|
@@ -209,7 +225,7 @@ module Avro
|
|
|
209
225
|
# A string is encoded as a long followed by that many bytes of
|
|
210
226
|
# UTF-8 encoded character data
|
|
211
227
|
def write_string(datum)
|
|
212
|
-
datum = datum.encode('utf-8') if datum.respond_to? :encode
|
|
228
|
+
datum = datum.encode('utf-8'.freeze) if datum.respond_to? :encode
|
|
213
229
|
write_bytes(datum)
|
|
214
230
|
end
|
|
215
231
|
|
|
@@ -221,46 +237,7 @@ module Avro
|
|
|
221
237
|
|
|
222
238
|
class DatumReader
|
|
223
239
|
def self.match_schemas(writers_schema, readers_schema)
|
|
224
|
-
|
|
225
|
-
r_type = readers_schema.type_sym
|
|
226
|
-
|
|
227
|
-
# This conditional is begging for some OO love.
|
|
228
|
-
if w_type == :union || r_type == :union
|
|
229
|
-
return true
|
|
230
|
-
end
|
|
231
|
-
|
|
232
|
-
if w_type == r_type
|
|
233
|
-
return true if Schema::PRIMITIVE_TYPES_SYM.include?(r_type)
|
|
234
|
-
|
|
235
|
-
case r_type
|
|
236
|
-
when :record
|
|
237
|
-
return writers_schema.fullname == readers_schema.fullname
|
|
238
|
-
when :error
|
|
239
|
-
return writers_schema.fullname == readers_schema.fullname
|
|
240
|
-
when :request
|
|
241
|
-
return true
|
|
242
|
-
when :fixed
|
|
243
|
-
return writers_schema.fullname == readers_schema.fullname &&
|
|
244
|
-
writers_schema.size == readers_schema.size
|
|
245
|
-
when :enum
|
|
246
|
-
return writers_schema.fullname == readers_schema.fullname
|
|
247
|
-
when :map
|
|
248
|
-
return writers_schema.values.type == readers_schema.values.type
|
|
249
|
-
when :array
|
|
250
|
-
return writers_schema.items.type == readers_schema.items.type
|
|
251
|
-
end
|
|
252
|
-
end
|
|
253
|
-
|
|
254
|
-
# Handle schema promotion
|
|
255
|
-
if w_type == :int && [:long, :float, :double].include?(r_type)
|
|
256
|
-
return true
|
|
257
|
-
elsif w_type == :long && [:float, :double].include?(r_type)
|
|
258
|
-
return true
|
|
259
|
-
elsif w_type == :float && r_type == :double
|
|
260
|
-
return true
|
|
261
|
-
end
|
|
262
|
-
|
|
263
|
-
return false
|
|
240
|
+
Avro::SchemaCompatibility.match_schemas(writers_schema, readers_schema)
|
|
264
241
|
end
|
|
265
242
|
|
|
266
243
|
attr_accessor :writers_schema, :readers_schema
|
|
@@ -293,7 +270,7 @@ module Avro
|
|
|
293
270
|
|
|
294
271
|
# function dispatch for reading data based on type of writer's
|
|
295
272
|
# schema
|
|
296
|
-
case writers_schema.type_sym
|
|
273
|
+
datum = case writers_schema.type_sym
|
|
297
274
|
when :null; decoder.read_null
|
|
298
275
|
when :boolean; decoder.read_boolean
|
|
299
276
|
when :string; decoder.read_string
|
|
@@ -311,6 +288,8 @@ module Avro
|
|
|
311
288
|
else
|
|
312
289
|
raise AvroError, "Cannot read unknown schema type: #{writers_schema.type}"
|
|
313
290
|
end
|
|
291
|
+
|
|
292
|
+
readers_schema.type_adapter.decode(datum)
|
|
314
293
|
end
|
|
315
294
|
|
|
316
295
|
def read_fixed(writers_schema, readers_schema, decoder)
|
|
@@ -336,7 +315,7 @@ module Avro
|
|
|
336
315
|
while block_count != 0
|
|
337
316
|
if block_count < 0
|
|
338
317
|
block_count = -block_count
|
|
339
|
-
|
|
318
|
+
_block_size = decoder.read_long
|
|
340
319
|
end
|
|
341
320
|
block_count.times do
|
|
342
321
|
read_items << read_data(writers_schema.items,
|
|
@@ -355,7 +334,7 @@ module Avro
|
|
|
355
334
|
while block_count != 0
|
|
356
335
|
if block_count < 0
|
|
357
336
|
block_count = -block_count
|
|
358
|
-
|
|
337
|
+
_block_size = decoder.read_long
|
|
359
338
|
end
|
|
360
339
|
block_count.times do
|
|
361
340
|
key = decoder.read_string
|
|
@@ -393,11 +372,11 @@ module Avro
|
|
|
393
372
|
writers_fields_hash = writers_schema.fields_hash
|
|
394
373
|
readers_fields_hash.each do |field_name, field|
|
|
395
374
|
unless writers_fields_hash.has_key? field_name
|
|
396
|
-
if
|
|
375
|
+
if field.default?
|
|
397
376
|
field_val = read_default_value(field.type, field.default)
|
|
398
377
|
read_record[field.name] = field_val
|
|
399
378
|
else
|
|
400
|
-
#
|
|
379
|
+
raise AvroError, "Missing data for #{field.type} with no default"
|
|
401
380
|
end
|
|
402
381
|
end
|
|
403
382
|
end
|
|
@@ -407,10 +386,6 @@ module Avro
|
|
|
407
386
|
end
|
|
408
387
|
|
|
409
388
|
def read_default_value(field_schema, default_value)
|
|
410
|
-
if default_value == :no_default
|
|
411
|
-
raise AvroError, "Missing data for #{field_schema} with no default"
|
|
412
|
-
end
|
|
413
|
-
|
|
414
389
|
# Basically a JSON Decoder?
|
|
415
390
|
case field_schema.type_sym
|
|
416
391
|
when :null
|
|
@@ -524,7 +499,7 @@ module Avro
|
|
|
524
499
|
if block_count < 0
|
|
525
500
|
decoder.skip(decoder.read_long)
|
|
526
501
|
else
|
|
527
|
-
block_count.times
|
|
502
|
+
block_count.times(&blk)
|
|
528
503
|
end
|
|
529
504
|
block_count = decoder.read_long
|
|
530
505
|
end
|
|
@@ -542,8 +517,10 @@ module Avro
|
|
|
542
517
|
write_data(writers_schema, datum, encoder)
|
|
543
518
|
end
|
|
544
519
|
|
|
545
|
-
def write_data(writers_schema,
|
|
546
|
-
|
|
520
|
+
def write_data(writers_schema, logical_datum, encoder)
|
|
521
|
+
datum = writers_schema.type_adapter.encode(logical_datum)
|
|
522
|
+
|
|
523
|
+
unless Schema.validate(writers_schema, datum, { recursive: false, encoded: true })
|
|
547
524
|
raise AvroTypeError.new(writers_schema, datum)
|
|
548
525
|
end
|
|
549
526
|
|
|
@@ -578,6 +555,7 @@ module Avro
|
|
|
578
555
|
end
|
|
579
556
|
|
|
580
557
|
def write_array(writers_schema, datum, encoder)
|
|
558
|
+
raise AvroTypeError.new(writers_schema, datum) unless datum.is_a?(Array)
|
|
581
559
|
if datum.size > 0
|
|
582
560
|
encoder.write_long(datum.size)
|
|
583
561
|
datum.each do |item|
|
|
@@ -588,6 +566,7 @@ module Avro
|
|
|
588
566
|
end
|
|
589
567
|
|
|
590
568
|
def write_map(writers_schema, datum, encoder)
|
|
569
|
+
raise AvroTypeError.new(writers_schema, datum) unless datum.is_a?(Hash)
|
|
591
570
|
if datum.size > 0
|
|
592
571
|
encoder.write_long(datum.size)
|
|
593
572
|
datum.each do |k,v|
|
|
@@ -610,6 +589,7 @@ module Avro
|
|
|
610
589
|
end
|
|
611
590
|
|
|
612
591
|
def write_record(writers_schema, datum, encoder)
|
|
592
|
+
raise AvroTypeError.new(writers_schema, datum) unless datum.is_a?(Hash)
|
|
613
593
|
writers_schema.fields.each do |field|
|
|
614
594
|
write_data(field.type, datum[field.name], encoder)
|
|
615
595
|
end
|
data/lib/avro/ipc.rb
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
# to you under the Apache License, Version 2.0 (the
|
|
6
6
|
# "License"); you may not use this file except in compliance
|
|
7
7
|
# with the License. You may obtain a copy of the License at
|
|
8
|
-
#
|
|
8
|
+
#
|
|
9
9
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
-
#
|
|
10
|
+
#
|
|
11
11
|
# Unless required by applicable law or agreed to in writing, software
|
|
12
12
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
13
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
@@ -74,10 +74,10 @@ module Avro::IPC
|
|
|
74
74
|
|
|
75
75
|
class ConnectionClosedException < Avro::AvroError; end
|
|
76
76
|
|
|
77
|
+
# Base class for the client side of a protocol interaction.
|
|
77
78
|
class Requestor
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
attr_accessor :remote_protocol, :remote_hash, :send_protocol
|
|
79
|
+
attr_reader :local_protocol, :transport, :remote_protocol, :remote_hash
|
|
80
|
+
attr_accessor :send_protocol
|
|
81
81
|
|
|
82
82
|
def initialize(local_protocol, transport)
|
|
83
83
|
@local_protocol = local_protocol
|
|
@@ -193,9 +193,9 @@ module Avro::IPC
|
|
|
193
193
|
# * a one-byte error flag boolean, followed by either:
|
|
194
194
|
# * if the error flag is false,
|
|
195
195
|
# the message response, serialized per the message's response schema.
|
|
196
|
-
# * if the error flag is true,
|
|
196
|
+
# * if the error flag is true,
|
|
197
197
|
# the error, serialized per the message's error union schema.
|
|
198
|
-
|
|
198
|
+
_response_metadata = META_READER.read(decoder)
|
|
199
199
|
|
|
200
200
|
# remote response schema
|
|
201
201
|
remote_message_schema = remote_protocol.messages[message_name]
|
|
@@ -257,7 +257,7 @@ module Avro::IPC
|
|
|
257
257
|
end
|
|
258
258
|
|
|
259
259
|
# read request using remote protocol
|
|
260
|
-
|
|
260
|
+
_request_metadata = META_READER.read(buffer_decoder)
|
|
261
261
|
remote_message_name = buffer_decoder.read_string
|
|
262
262
|
|
|
263
263
|
# get remote and local request schemas so we can do
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
|
3
|
+
# or more contributor license agreements. See the NOTICE file
|
|
4
|
+
# distributed with this work for additional information
|
|
5
|
+
# regarding copyright ownership. The ASF licenses this file
|
|
6
|
+
# to you under the Apache License, Version 2.0 (the
|
|
7
|
+
# "License"); you may not use this file except in compliance
|
|
8
|
+
# with the License. You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
|
|
18
|
+
require 'date'
|
|
19
|
+
|
|
20
|
+
module Avro
|
|
21
|
+
module LogicalTypes
|
|
22
|
+
module IntDate
|
|
23
|
+
EPOCH_START = Date.new(1970, 1, 1)
|
|
24
|
+
|
|
25
|
+
def self.encode(date)
|
|
26
|
+
return date.to_i if date.is_a?(Numeric)
|
|
27
|
+
|
|
28
|
+
(date - EPOCH_START).to_i
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.decode(int)
|
|
32
|
+
EPOCH_START + int
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
module TimestampMillis
|
|
37
|
+
def self.encode(value)
|
|
38
|
+
return value.to_i if value.is_a?(Numeric)
|
|
39
|
+
|
|
40
|
+
time = value.to_time
|
|
41
|
+
time.to_i * 1000 + time.usec / 1000
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def self.decode(int)
|
|
45
|
+
s, ms = int / 1000, int % 1000
|
|
46
|
+
Time.at(s, ms * 1000).utc
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
module TimestampMicros
|
|
51
|
+
def self.encode(value)
|
|
52
|
+
return value.to_i if value.is_a?(Numeric)
|
|
53
|
+
|
|
54
|
+
time = value.to_time
|
|
55
|
+
time.to_i * 1000_000 + time.usec
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def self.decode(int)
|
|
59
|
+
s, us = int / 1000_000, int % 1000_000
|
|
60
|
+
Time.at(s, us).utc
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
module Identity
|
|
65
|
+
def self.encode(datum)
|
|
66
|
+
datum
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def self.decode(datum)
|
|
70
|
+
datum
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
TYPES = {
|
|
75
|
+
"int" => {
|
|
76
|
+
"date" => IntDate
|
|
77
|
+
},
|
|
78
|
+
"long" => {
|
|
79
|
+
"timestamp-millis" => TimestampMillis,
|
|
80
|
+
"timestamp-micros" => TimestampMicros
|
|
81
|
+
},
|
|
82
|
+
}.freeze
|
|
83
|
+
|
|
84
|
+
def self.type_adapter(type, logical_type)
|
|
85
|
+
return unless logical_type
|
|
86
|
+
|
|
87
|
+
TYPES.fetch(type, {}.freeze).fetch(logical_type, Identity)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|