avromatic 0.8.0 → 0.9.0.rc0
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/CHANGELOG.md +3 -0
- data/README.md +4 -2
- data/lib/avromatic/model/attribute/union.rb +52 -0
- data/lib/avromatic/model/attribute_type/union.rb +29 -0
- data/lib/avromatic/model/attributes.rb +41 -13
- data/lib/avromatic/model/builder.rb +1 -0
- data/lib/avromatic/model/type_registry.rb +3 -2
- data/lib/avromatic/version.rb +1 -1
- metadata +7 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1a36670183dc6e3348395dcc336222da9ac1bd00
|
4
|
+
data.tar.gz: b37d41366b6737fb4aa7d4793128c13d90860920
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d316d600c9e38743538abc7b1a598cb13cfa102c6181476ed7e2684ccf63000a6856998ebc9ad065bfb71c98a54adab72a8675aa06f67622f5d2eb415acfea73
|
7
|
+
data.tar.gz: 86ac869dd270188af7f24f22ce1259ed2cf0b109e09d23ff3da9af4288deb191ab1fc7a05f4c2d81159335216b07e3e63e8618c86d3e0c4b09055246881b830f
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -116,6 +116,9 @@ These customizations are registered on the `Avromatic` module. Once a custom typ
|
|
116
116
|
is registered, it is used for all models with a schema that references that type.
|
117
117
|
It is recommended to register types within a block passed to `Avromatic.configure`:
|
118
118
|
|
119
|
+
Note: custom types are not currently supported on members of unions with more
|
120
|
+
than one non-null type.
|
121
|
+
|
119
122
|
```ruby
|
120
123
|
Avromatic.configure do |config|
|
121
124
|
config.register_type('com.example.my_string', MyString)
|
@@ -248,8 +251,7 @@ The following validations are supported:
|
|
248
251
|
|
249
252
|
The following types/features are not supported for generated models:
|
250
253
|
|
251
|
-
-
|
252
|
-
another type, is supported.
|
254
|
+
- Custom types for members within a union.
|
253
255
|
- Reused models for nested records: Currently an anonymous model class is
|
254
256
|
generated for each subrecord.
|
255
257
|
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'avromatic/model/attribute_type/union'
|
2
|
+
|
3
|
+
module Avromatic
|
4
|
+
module Model
|
5
|
+
module Attribute
|
6
|
+
|
7
|
+
# This subclass of Virtus::Attribute is used for any unions that are
|
8
|
+
# defined as subclasses of the primitive Avromatic::Model::AttributeType::Union.
|
9
|
+
# Values are coerced by first checking if they already match one of the
|
10
|
+
# member types, and then by attempting to coerce to each member type in
|
11
|
+
# order.
|
12
|
+
class Union < Virtus::Attribute
|
13
|
+
primitive Avromatic::Model::AttributeType::Union
|
14
|
+
|
15
|
+
def initialize(*)
|
16
|
+
super
|
17
|
+
|
18
|
+
primitive.types.each do |type|
|
19
|
+
member_attributes << Virtus::Attribute.build(type)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def coerce(input)
|
24
|
+
return input if value_coerced?(input)
|
25
|
+
|
26
|
+
result = nil
|
27
|
+
member_attributes.find do |union_attribute|
|
28
|
+
begin
|
29
|
+
coerced = union_attribute.coerce(input)
|
30
|
+
result = coerced unless coerced.is_a?(Avromatic::Model::Attributes) && coerced.invalid?
|
31
|
+
rescue
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
result
|
36
|
+
end
|
37
|
+
|
38
|
+
def value_coerced?(value)
|
39
|
+
member_attributes.any? do |union_attribute|
|
40
|
+
union_attribute.value_coerced?(value)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def member_attributes
|
47
|
+
@member_attributes ||= Array.new
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Avromatic
|
2
|
+
module Model
|
3
|
+
module AttributeType
|
4
|
+
|
5
|
+
# This class is used as the base class for Virtus attributes that
|
6
|
+
# represent unions. A subclass is generated using Union[*types]. This
|
7
|
+
# subclass is specified when defining a Virtus attribute.
|
8
|
+
class Union
|
9
|
+
class << self
|
10
|
+
attr_reader :types
|
11
|
+
|
12
|
+
protected
|
13
|
+
|
14
|
+
attr_writer :types
|
15
|
+
end
|
16
|
+
|
17
|
+
# Factory method to define Union types with the specified list of
|
18
|
+
# types (classes).
|
19
|
+
def self.[](*types)
|
20
|
+
Class.new(self).tap do |klass|
|
21
|
+
klass.types = types
|
22
|
+
# See https://github.com/solnic/virtus/issues/284#issuecomment-56405137
|
23
|
+
Axiom::Types::Object.new { primitive(klass) }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -13,9 +13,10 @@ module Avromatic
|
|
13
13
|
# TODO: This is a hack until I find a better solution for unions with
|
14
14
|
# Virtus. This only handles a union for an optional field with :null
|
15
15
|
# and one other type.
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
# This hack lives on for now because custom type coercion is not pushed
|
17
|
+
# down into unions. This means that custom types can only be optional
|
18
|
+
# fields, not members of real unions.
|
19
|
+
field_type.schemas.reject { |schema| schema.type_sym == :null }.first
|
19
20
|
end
|
20
21
|
|
21
22
|
module ClassMethods
|
@@ -60,10 +61,10 @@ module Avromatic
|
|
60
61
|
|
61
62
|
attribute(field.name,
|
62
63
|
field_class,
|
63
|
-
avro_field_options(field))
|
64
|
+
avro_field_options(field, field_class))
|
64
65
|
|
65
66
|
add_validation(field)
|
66
|
-
add_serializer(field)
|
67
|
+
add_serializer(field, field_class)
|
67
68
|
end
|
68
69
|
end
|
69
70
|
|
@@ -127,22 +128,29 @@ module Avromatic
|
|
127
128
|
when :record
|
128
129
|
# TODO: This should add the generated model to a module.
|
129
130
|
# A hash of generated models should be kept by name for reuse.
|
130
|
-
|
131
|
-
include Avromatic::Model.build(schema: field_type)
|
132
|
-
end
|
131
|
+
Avromatic::Model.model(schema: field_type)
|
133
132
|
else
|
134
133
|
raise "Unsupported type #{field_type}"
|
135
134
|
end
|
136
135
|
end
|
137
136
|
|
138
137
|
def union_field_class(field_type)
|
139
|
-
|
138
|
+
field_classes = field_type.schemas.reject { |schema| schema.type_sym == :null }
|
139
|
+
.map { |schema| avro_field_class(schema) }
|
140
|
+
|
141
|
+
if field_classes.size == 1
|
142
|
+
field_classes.first
|
143
|
+
else
|
144
|
+
Avromatic::Model::AttributeType::Union[*field_classes]
|
145
|
+
end
|
140
146
|
end
|
141
147
|
|
142
|
-
def avro_field_options(field)
|
148
|
+
def avro_field_options(field, field_class)
|
143
149
|
options = {}
|
144
150
|
|
145
|
-
|
151
|
+
prevent_union_including_custom_type!(field, field_class)
|
152
|
+
|
153
|
+
custom_type = Avromatic.type_registry.fetch(field, field_class)
|
146
154
|
coercer = custom_type.deserializer
|
147
155
|
options[:coercer] = coercer if coercer
|
148
156
|
|
@@ -154,8 +162,10 @@ module Avromatic
|
|
154
162
|
options
|
155
163
|
end
|
156
164
|
|
157
|
-
def add_serializer(field)
|
158
|
-
|
165
|
+
def add_serializer(field, field_class)
|
166
|
+
prevent_union_including_custom_type!(field, field_class)
|
167
|
+
|
168
|
+
custom_type = Avromatic.type_registry.fetch(field, field_class)
|
159
169
|
serializer = custom_type.serializer
|
160
170
|
|
161
171
|
avro_serializer[field.name.to_sym] = serializer if serializer
|
@@ -164,6 +174,24 @@ module Avromatic
|
|
164
174
|
def default_for(value)
|
165
175
|
value.duplicable? ? value.dup.deep_freeze : value
|
166
176
|
end
|
177
|
+
|
178
|
+
# TODO: the methods below are temporary until support for custom types
|
179
|
+
# as union members are supported.
|
180
|
+
def member_uses_custom_type?(field)
|
181
|
+
field.type.schemas.any? do |klass|
|
182
|
+
Avromatic.type_registry.fetch(klass) != NullCustomType
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def prevent_union_including_custom_type!(field, field_class)
|
187
|
+
if field_class.is_a?(Class) &&
|
188
|
+
field_class < Avromatic::Model::AttributeType::Union &&
|
189
|
+
member_uses_custom_type?(field)
|
190
|
+
|
191
|
+
raise 'custom types within unions are currently unsupported'
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
167
195
|
end
|
168
196
|
|
169
197
|
end
|
@@ -4,6 +4,7 @@ require 'active_model'
|
|
4
4
|
require 'avromatic/model/configuration'
|
5
5
|
require 'avromatic/model/value_object'
|
6
6
|
require 'avromatic/model/configurable'
|
7
|
+
require 'avromatic/model/attribute/union'
|
7
8
|
require 'avromatic/model/attributes'
|
8
9
|
require 'avromatic/model/raw_serialization'
|
9
10
|
require 'avromatic/model/messaging_serialization'
|
@@ -23,10 +23,11 @@ module Avromatic
|
|
23
23
|
|
24
24
|
# @object [Avro::Schema] Custom type may be fetched based on a Avro field
|
25
25
|
# or schema. If there is no custom type, then NullCustomType is returned.
|
26
|
-
|
26
|
+
# @field_class [Object] Value class that has been determined for a field.
|
27
|
+
def fetch(object, field_class = nil)
|
27
28
|
field_type = object.is_a?(Avro::Schema::Field) ? object.type : object
|
28
29
|
|
29
|
-
if field_type.type_sym == :union
|
30
|
+
if field_class && field_type.type_sym == :union && !(field_class < Avromatic::Model::AttributeType::Union)
|
30
31
|
field_type = Avromatic::Model::Attributes.first_union_schema(field_type)
|
31
32
|
end
|
32
33
|
|
data/lib/avromatic/version.rb
CHANGED
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.9.0.rc0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Salsify Engineering
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-09-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: avro
|
@@ -246,6 +246,8 @@ files:
|
|
246
246
|
- gemfiles/rails4_2.gemfile
|
247
247
|
- lib/avromatic.rb
|
248
248
|
- lib/avromatic/model.rb
|
249
|
+
- lib/avromatic/model/attribute/union.rb
|
250
|
+
- lib/avromatic/model/attribute_type/union.rb
|
249
251
|
- lib/avromatic/model/attributes.rb
|
250
252
|
- lib/avromatic/model/builder.rb
|
251
253
|
- lib/avromatic/model/configurable.rb
|
@@ -278,12 +280,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
278
280
|
version: '0'
|
279
281
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
280
282
|
requirements:
|
281
|
-
- - "
|
283
|
+
- - ">"
|
282
284
|
- !ruby/object:Gem::Version
|
283
|
-
version:
|
285
|
+
version: 1.3.1
|
284
286
|
requirements: []
|
285
287
|
rubyforge_project:
|
286
|
-
rubygems_version: 2.
|
288
|
+
rubygems_version: 2.4.8
|
287
289
|
signing_key:
|
288
290
|
specification_version: 4
|
289
291
|
summary: Generate Ruby models from Avro schemas
|