avromatic 0.8.0 → 0.9.0.rc0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|