avromatic 0.23.0 → 0.24.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +8 -0
- data/lib/avromatic/io/datum_reader.rb +1 -1
- data/lib/avromatic/io/datum_writer.rb +25 -0
- data/lib/avromatic/io.rb +8 -0
- data/lib/avromatic/messaging.rb +27 -2
- data/lib/avromatic/model/attribute/union.rb +1 -1
- data/lib/avromatic/model/raw_serialization.rb +51 -12
- data/lib/avromatic/version.rb +1 -1
- data/lib/avromatic.rb +3 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c482b56c1e0e8d3f9271d7a7e61e763a9dffdd83
|
4
|
+
data.tar.gz: 0005f4ef6ff0abdc4a484b67873de53fab595244
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3ad6910fa3bda579cc807aec5b2e374d7821f7fb8c47b43de99b58c738b822b4f95d884594ec89a6f083baac97b018621d6ff70e9795caf8c050b96f3c4cc974
|
7
|
+
data.tar.gz: d11cb1499b84dc7b4dfea172f0391eeee61e4f161d35a5e8e44c8181c775693b86902e2b0825e31fe4829058fbef51299a65da1d262c1aacfd689d74cacc9b43
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
# avromatic changelog
|
2
2
|
|
3
|
+
## v0.24.0
|
4
|
+
- Add `Avromatic::IO::DatumWriter` to optimize the encoding of Avro unions
|
5
|
+
from Avromatic models.
|
6
|
+
- Expose the `#key_attributes_for_avro` method on models.
|
7
|
+
|
3
8
|
## v0.23.0
|
4
9
|
- Add mutable option when defining a model.
|
5
10
|
|
data/README.md
CHANGED
@@ -97,6 +97,14 @@ end
|
|
97
97
|
is included in the hash returned by the `DatumReader` but can be omitted by
|
98
98
|
setting this option to `false`.
|
99
99
|
|
100
|
+
#### Encoding
|
101
|
+
* **use_custom_datum_writer**: `Avromatic` includes a modified subclass of
|
102
|
+
`Avro::IO::DatumWriter`. This subclass uses additional information about
|
103
|
+
the index of union members to optimize the encoding of Avro messages.
|
104
|
+
By default this information is included in the hash passed to the encoder
|
105
|
+
but can be omitted by setting this option to `false`.
|
106
|
+
|
107
|
+
|
100
108
|
### Models
|
101
109
|
|
102
110
|
Models are defined based on an Avro schema for a record.
|
@@ -6,7 +6,7 @@ module Avromatic
|
|
6
6
|
# branch 'salsify-master' with the tag 'v1.9.0.3'
|
7
7
|
class DatumReader < Avro::IO::DatumReader
|
8
8
|
|
9
|
-
UNION_MEMBER_INDEX =
|
9
|
+
UNION_MEMBER_INDEX = Avromatic::IO::UNION_MEMBER_INDEX
|
10
10
|
|
11
11
|
def read_data(writers_schema, readers_schema, decoder, initial_record = {})
|
12
12
|
# schema matching
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Avromatic
|
2
|
+
module IO
|
3
|
+
# Subclass DatumWriter to use additional information about union member
|
4
|
+
# index.
|
5
|
+
class DatumWriter < Avro::IO::DatumWriter
|
6
|
+
def write_union(writers_schema, datum, encoder)
|
7
|
+
optional = writers_schema.schemas.first.type_sym == :null
|
8
|
+
if datum.is_a?(Hash) && datum.key?(Avromatic::IO::UNION_MEMBER_INDEX)
|
9
|
+
index_of_schema = datum[Avromatic::IO::UNION_MEMBER_INDEX]
|
10
|
+
# Avromatic does not treat the null of an optional field as part of the union
|
11
|
+
index_of_schema += 1 if optional
|
12
|
+
else
|
13
|
+
index_of_schema = writers_schema.schemas.find_index do |schema|
|
14
|
+
Avro::Schema.validate(schema, datum)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
unless index_of_schema
|
18
|
+
raise Avro::IO::AvroTypeError.new(writers_schema, datum)
|
19
|
+
end
|
20
|
+
encoder.write_long(index_of_schema)
|
21
|
+
write_data(writers_schema.schemas[index_of_schema], datum, encoder)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/avromatic/io.rb
ADDED
data/lib/avromatic/messaging.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'avro_turf/messaging'
|
2
|
-
require 'avromatic/io
|
2
|
+
require 'avromatic/io'
|
3
3
|
|
4
4
|
module Avromatic
|
5
|
-
# Subclass AvroTurf::Messaging to use a custom DatumReader
|
5
|
+
# Subclass AvroTurf::Messaging to use a custom DatumReader and DatumWriter
|
6
6
|
class Messaging < AvroTurf::Messaging
|
7
7
|
attr_reader :registry
|
8
8
|
|
@@ -30,5 +30,30 @@ module Avromatic
|
|
30
30
|
reader = Avromatic::IO::DatumReader.new(writers_schema, readers_schema)
|
31
31
|
reader.read(decoder)
|
32
32
|
end
|
33
|
+
|
34
|
+
def encode(message, schema_name: nil, namespace: @namespace, subject: nil)
|
35
|
+
schema = @schema_store.find(schema_name, namespace)
|
36
|
+
|
37
|
+
# Schemas are registered under the full name of the top level Avro record
|
38
|
+
# type, or `subject` if it's provided.
|
39
|
+
schema_id = @registry.register(subject || schema.fullname, schema)
|
40
|
+
|
41
|
+
stream = StringIO.new
|
42
|
+
encoder = Avro::IO::BinaryEncoder.new(stream)
|
43
|
+
|
44
|
+
# Always start with the magic byte.
|
45
|
+
encoder.write(MAGIC_BYTE)
|
46
|
+
|
47
|
+
# The schema id is encoded as a 4-byte big-endian integer.
|
48
|
+
encoder.write([schema_id].pack('N'))
|
49
|
+
|
50
|
+
# The following line differs from the parent class to use a custom DatumWriter
|
51
|
+
writer = Avromatic::IO::DatumWriter.new(schema)
|
52
|
+
|
53
|
+
# The actual message comes last.
|
54
|
+
writer.write(message, encoder)
|
55
|
+
|
56
|
+
stream.string
|
57
|
+
end
|
33
58
|
end
|
34
59
|
end
|
@@ -15,18 +15,53 @@ module Avromatic
|
|
15
15
|
to: :class
|
16
16
|
private :avro_serializer, :datum_writer, :datum_reader
|
17
17
|
|
18
|
+
EMPTY_ARRAY = [].freeze
|
19
|
+
|
20
|
+
included do
|
21
|
+
@attribute_member_types = {}
|
22
|
+
end
|
23
|
+
|
18
24
|
module ClassMethods
|
19
|
-
def recursive_serialize(value,
|
25
|
+
def recursive_serialize(value, name: nil, member_types: nil)
|
26
|
+
member_types = attribute_member_types(name) if name
|
27
|
+
member_types ||= EMPTY_ARRAY
|
28
|
+
|
20
29
|
if value.is_a?(Avromatic::Model::Attributes)
|
21
|
-
value.value_attributes_for_avro
|
30
|
+
hash = value.value_attributes_for_avro
|
31
|
+
if Avromatic.use_custom_datum_writer
|
32
|
+
member_index = member_types.index(value.class) if member_types.any?
|
33
|
+
hash[Avromatic::IO::UNION_MEMBER_INDEX] = member_index if member_index
|
34
|
+
end
|
35
|
+
hash
|
22
36
|
elsif value.is_a?(Array)
|
23
|
-
value.map { |v| recursive_serialize(v) }
|
37
|
+
value.map { |v| recursive_serialize(v, member_types: member_types) }
|
24
38
|
elsif value.is_a?(Hash)
|
25
|
-
value.each_with_object({}) do |(k, v),
|
26
|
-
|
39
|
+
value.each_with_object({}) do |(k, v), map|
|
40
|
+
map[k] = recursive_serialize(v, member_types: member_types)
|
27
41
|
end
|
28
42
|
else
|
29
|
-
avro_serializer[
|
43
|
+
avro_serializer[name].call(value)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def attribute_member_types(name)
|
50
|
+
@attribute_member_types.fetch(name) do
|
51
|
+
member_types = nil
|
52
|
+
attribute = attribute_set[name] if name
|
53
|
+
if attribute
|
54
|
+
if attribute.primitive == Array &&
|
55
|
+
attribute.member_type.is_a?(Avromatic::Model::Attribute::Union)
|
56
|
+
member_types = attribute.member_type.primitive.types
|
57
|
+
elsif attribute.primitive == Hash &&
|
58
|
+
attribute.value_type.is_a?(Avromatic::Model::Attribute::Union)
|
59
|
+
member_types = attribute.value_type.primitive.types
|
60
|
+
elsif attribute.options[:primitive] == Avromatic::Model::AttributeType::Union
|
61
|
+
member_types = attribute.primitive.types
|
62
|
+
end
|
63
|
+
end
|
64
|
+
@attribute_member_types[name] = member_types
|
30
65
|
end
|
31
66
|
end
|
32
67
|
end
|
@@ -44,15 +79,15 @@ module Avromatic
|
|
44
79
|
avro_hash(value_avro_field_names)
|
45
80
|
end
|
46
81
|
|
47
|
-
private
|
48
|
-
|
49
82
|
def key_attributes_for_avro
|
50
83
|
avro_hash(key_avro_field_names)
|
51
84
|
end
|
52
85
|
|
86
|
+
private
|
87
|
+
|
53
88
|
def avro_hash(fields)
|
54
89
|
attributes.slice(*fields).each_with_object(Hash.new) do |(key, value), result|
|
55
|
-
result[key.to_s] = self.class.recursive_serialize(value, key)
|
90
|
+
result[key.to_s] = self.class.recursive_serialize(value, name: key)
|
56
91
|
end
|
57
92
|
end
|
58
93
|
|
@@ -94,7 +129,11 @@ module Avromatic
|
|
94
129
|
|
95
130
|
module ClassMethods
|
96
131
|
def datum_reader_class
|
97
|
-
Avromatic::IO::DatumReader
|
132
|
+
Avromatic.use_custom_datum_reader ? Avromatic::IO::DatumReader : Avro::IO::DatumReader
|
133
|
+
end
|
134
|
+
|
135
|
+
def datum_writer_class
|
136
|
+
Avromatic.use_custom_datum_writer ? Avromatic::IO::DatumWriter : Avro::IO::DatumWriter
|
98
137
|
end
|
99
138
|
|
100
139
|
# Store a hash of Procs by field name (as a symbol) to convert
|
@@ -106,8 +145,8 @@ module Avromatic
|
|
106
145
|
|
107
146
|
def datum_writer
|
108
147
|
@datum_writer ||= begin
|
109
|
-
hash = { value:
|
110
|
-
hash[:key] =
|
148
|
+
hash = { value: datum_writer_class.new(value_avro_schema) }
|
149
|
+
hash[:key] = datum_writer_class.new(key_avro_schema) if key_avro_schema
|
111
150
|
hash
|
112
151
|
end
|
113
152
|
end
|
data/lib/avromatic/version.rb
CHANGED
data/lib/avromatic.rb
CHANGED
@@ -9,7 +9,8 @@ module Avromatic
|
|
9
9
|
class << self
|
10
10
|
attr_accessor :schema_registry, :registry_url, :schema_store, :logger,
|
11
11
|
:messaging, :type_registry, :nested_models,
|
12
|
-
:use_custom_datum_reader, :
|
12
|
+
:use_custom_datum_reader, :use_custom_datum_writer,
|
13
|
+
:use_schema_fingerprint_lookup
|
13
14
|
|
14
15
|
delegate :register_type, to: :type_registry
|
15
16
|
end
|
@@ -18,6 +19,7 @@ module Avromatic
|
|
18
19
|
self.logger = Logger.new($stdout)
|
19
20
|
self.type_registry = Avromatic::Model::TypeRegistry.new
|
20
21
|
self.use_custom_datum_reader = true
|
22
|
+
self.use_custom_datum_writer = true
|
21
23
|
self.use_schema_fingerprint_lookup = true
|
22
24
|
|
23
25
|
def self.configure
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: avromatic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.24.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Salsify Engineering
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-06-
|
11
|
+
date: 2017-06-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: avro
|
@@ -273,7 +273,9 @@ files:
|
|
273
273
|
- gemfiles/rails4_2.gemfile
|
274
274
|
- gemfiles/rails5_0.gemfile
|
275
275
|
- lib/avromatic.rb
|
276
|
+
- lib/avromatic/io.rb
|
276
277
|
- lib/avromatic/io/datum_reader.rb
|
278
|
+
- lib/avromatic/io/datum_writer.rb
|
277
279
|
- lib/avromatic/messaging.rb
|
278
280
|
- lib/avromatic/model.rb
|
279
281
|
- lib/avromatic/model/attribute/abstract_timestamp.rb
|