avromatic 0.9.0.rc1 → 0.9.0.rc2
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/.rspec +1 -0
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +2 -1
- data/README.md +71 -1
- data/lib/avromatic.rb +3 -1
- data/lib/avromatic/model/attributes.rb +1 -8
- data/lib/avromatic/model/builder.rb +2 -0
- data/lib/avromatic/model/configurable.rb +4 -0
- data/lib/avromatic/model/configuration.rb +3 -2
- data/lib/avromatic/model/nested_models.rb +29 -0
- data/lib/avromatic/model/value_object.rb +0 -1
- data/lib/avromatic/model_registry.rb +45 -0
- data/lib/avromatic/version.rb +1 -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: 349bd4de9cfdaffd91c737ef6330d9b9d20ff8ed
|
4
|
+
data.tar.gz: cc1b8f6f5275cea982902ce4ae5d055e504a69a5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a1d4474e40c761995be5512600d9e84f6f743501b9f496901900686058cd4e5190c78712723125bf66d3e7a571cc786ea579fcc91021bcf35506a88f7ef69be7
|
7
|
+
data.tar.gz: 72e71deb56ff37c1f85a4c11b04d37f2672cc0d3b406ee574180257f690a6f7d057fe53250cfbd513610740120fe7e191d7d73970f7140be4c6b7b16d711c122
|
data/.rspec
CHANGED
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
# avromatic changelog
|
2
2
|
|
3
3
|
## v0.9.0 (unreleased)
|
4
|
-
- Add support for more than one non-null type in a union.
|
4
|
+
- Experimental: Add support for more than one non-null type in a union.
|
5
|
+
- Allow nested models to be referenced and reused.
|
5
6
|
- Fix the serialization of nested complex types.
|
6
7
|
|
7
8
|
## v0.8.0
|
data/README.md
CHANGED
@@ -37,7 +37,11 @@ Or install it yourself as:
|
|
37
37
|
returns an `Avro::Schema` object. An `AvroTurf::SchemaStore` can be used.
|
38
38
|
The `schema_store` is unnecessary if models are generated directly from
|
39
39
|
`Avro::Schema` objects. See [Models](#models).
|
40
|
-
|
40
|
+
* **nested_models**: An optional [ModelRegistry](https://github.com/salsify/avromatic/blob/master/lib/avromatic/model_registry.rb)
|
41
|
+
that is used to store, by full schema name, the generated models that are
|
42
|
+
embedded within top-level models. By default a new `Avromatic::ModelRegistry`
|
43
|
+
is created.
|
44
|
+
|
41
45
|
#### Using a Schema Registry/Messaging API
|
42
46
|
|
43
47
|
The configuration options below are required when using a schema registry
|
@@ -109,6 +113,72 @@ constant:
|
|
109
113
|
MyModel = Avromatic::Model.model(schema_name :my_model)
|
110
114
|
```
|
111
115
|
|
116
|
+
#### Experimental: Union Support
|
117
|
+
|
118
|
+
Avromatic contains experimental support for unions containing more than one
|
119
|
+
non-null member type. This feature is experimental because Virtus attributes
|
120
|
+
may attempt to coerce between types too aggressively.
|
121
|
+
|
122
|
+
For now, if a union contains [nested models](#nested-models) then it is
|
123
|
+
recommended that you assign model instances.
|
124
|
+
|
125
|
+
Some combination of the ordering of member types in the union and relying on
|
126
|
+
model validation may be required so that the correct member is selected,
|
127
|
+
especially when deserializing from Avro.
|
128
|
+
|
129
|
+
In the future, the type coercion used in the gem will be replaced to better
|
130
|
+
support the union use case.
|
131
|
+
|
132
|
+
#### Nested Models
|
133
|
+
|
134
|
+
Nested models are models that are embedded within top-level models generated
|
135
|
+
using Avromatic. Normally these nested models are automatically generated.
|
136
|
+
|
137
|
+
By default, nested models are stored in `Avromatic.nested_models`. This is an
|
138
|
+
`Avromatic::ModelRegistry` instance that provides access to previously generated
|
139
|
+
nested models by the full name of their Avro schema.
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
Avromatic.nested_models['com.my_company.test.example']
|
143
|
+
#=> <model class>
|
144
|
+
```
|
145
|
+
|
146
|
+
The `ModelRegistry` can be customized to remove a namespace prefix:
|
147
|
+
|
148
|
+
```ruby
|
149
|
+
Avromatic.nested_models =
|
150
|
+
Avromatic::ModelRegistry.new(remove_namespace_prefix: 'com.my_company'
|
151
|
+
```
|
152
|
+
|
153
|
+
The `:remove_namespace_prefix` value can be a string or a regexp.
|
154
|
+
|
155
|
+
By default, top-level generated models reuse `Avromatic.nested_models`. This
|
156
|
+
allows nested models to be shared across different generated models.
|
157
|
+
A `:nested_models` option can be specified when generating a model. This allows
|
158
|
+
the reuse of nested models to be scoped:
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
Avromatic::Model.model(schema_name, :my_model
|
162
|
+
nested_models: ModelRegistry.new)
|
163
|
+
```
|
164
|
+
|
165
|
+
It is also possible to explicitly generate a nested model that should be reused
|
166
|
+
and add it to the registry. This is useful when the nested model is extended:
|
167
|
+
|
168
|
+
```ruby
|
169
|
+
class UsefulSubrecord
|
170
|
+
include Avromatic::Model.build(schema_name: 'useful_subrecord')
|
171
|
+
|
172
|
+
def do_something_custom
|
173
|
+
...
|
174
|
+
end
|
175
|
+
end
|
176
|
+
Avromatic.nested_models.register(UsefulSubrecord)
|
177
|
+
```
|
178
|
+
|
179
|
+
With Rails, it may be necessary to perform this explicit registration in an
|
180
|
+
initializer so that lazy class loading works correctly in development.
|
181
|
+
|
112
182
|
#### Custom Types
|
113
183
|
|
114
184
|
Custom types can be configured for fields of named types (record, enum, fixed).
|
data/lib/avromatic.rb
CHANGED
@@ -1,16 +1,18 @@
|
|
1
1
|
require 'avromatic/version'
|
2
2
|
require 'avromatic/model'
|
3
|
+
require 'avromatic/model_registry'
|
3
4
|
require 'avro_turf'
|
4
5
|
require 'avro_turf/messaging'
|
5
6
|
|
6
7
|
module Avromatic
|
7
8
|
class << self
|
8
9
|
attr_accessor :schema_registry, :registry_url, :schema_store, :logger,
|
9
|
-
:messaging, :type_registry
|
10
|
+
:messaging, :type_registry, :nested_models
|
10
11
|
|
11
12
|
delegate :register_type, to: :type_registry
|
12
13
|
end
|
13
14
|
|
15
|
+
self.nested_models = ModelRegistry.new
|
14
16
|
self.logger = Logger.new($stdout)
|
15
17
|
self.type_registry = Avromatic::Model::TypeRegistry.new
|
16
18
|
|
@@ -126,14 +126,7 @@ module Avromatic
|
|
126
126
|
when :union
|
127
127
|
union_field_class(field_type)
|
128
128
|
when :record
|
129
|
-
|
130
|
-
# A hash of generated models should be kept by name for reuse.
|
131
|
-
Avromatic::Model.model(schema: field_type).tap do |record_class|
|
132
|
-
# Register the generated model with Axiom to prevent it being
|
133
|
-
# treated as a BasicObject.
|
134
|
-
# See https://github.com/solnic/virtus/issues/284#issuecomment-56405137
|
135
|
-
Axiom::Types::Object.new { primitive(record_class) }
|
136
|
-
end
|
129
|
+
build_nested_model(field_type)
|
137
130
|
else
|
138
131
|
raise "Unsupported type #{field_type}"
|
139
132
|
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/nested_models'
|
7
8
|
require 'avromatic/model/attribute/union'
|
8
9
|
require 'avromatic/model/attributes'
|
9
10
|
require 'avromatic/model/attribute/record'
|
@@ -42,6 +43,7 @@ module Avromatic
|
|
42
43
|
ActiveModel::Validations,
|
43
44
|
Virtus.value_object,
|
44
45
|
Avromatic::Model::Configurable,
|
46
|
+
Avromatic::Model::NestedModels,
|
45
47
|
Avromatic::Model::Attributes,
|
46
48
|
Avromatic::Model::ValueObject,
|
47
49
|
Avromatic::Model::RawSerialization,
|
@@ -4,7 +4,7 @@ module Avromatic
|
|
4
4
|
# This class holds configuration for a model built from Avro schema(s).
|
5
5
|
class Configuration
|
6
6
|
|
7
|
-
attr_reader :avro_schema, :key_avro_schema
|
7
|
+
attr_reader :avro_schema, :key_avro_schema, :nested_models
|
8
8
|
delegate :schema_store, to: Avromatic
|
9
9
|
|
10
10
|
# Either schema(_name) or value_schema(_name), but not both, must be
|
@@ -17,10 +17,12 @@ module Avromatic
|
|
17
17
|
# @option options [String, Symbol] :value_schema_name
|
18
18
|
# @option options [Avro::Schema] :key_schema
|
19
19
|
# @option options [String, Symbol] :key_schema_name
|
20
|
+
# @option options [Avromatic::ModelRegistry] :nested_models
|
20
21
|
def initialize(**options)
|
21
22
|
@avro_schema = find_avro_schema(**options)
|
22
23
|
raise ArgumentError.new('value_schema(_name) or schema(_name) must be specified') unless avro_schema
|
23
24
|
@key_avro_schema = find_schema_by_option(:key_schema, **options)
|
25
|
+
@nested_models = options[:nested_models]
|
24
26
|
end
|
25
27
|
|
26
28
|
alias_method :value_avro_schema, :avro_schema
|
@@ -39,7 +41,6 @@ module Avromatic
|
|
39
41
|
schema_name_option = :"#{option_name}_name"
|
40
42
|
options[option_name] ||
|
41
43
|
(options[schema_name_option] && schema_store.find(options[schema_name_option]))
|
42
|
-
|
43
44
|
end
|
44
45
|
end
|
45
46
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'active_support/inflector/methods'
|
2
|
+
|
3
|
+
module Avromatic
|
4
|
+
module Model
|
5
|
+
# This module handles integration with the ModelRegistry and support
|
6
|
+
# for nested model reuse.
|
7
|
+
module NestedModels
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
def build_nested_model(schema)
|
12
|
+
fullname = schema.fullname
|
13
|
+
|
14
|
+
if nested_models.registered?(fullname)
|
15
|
+
nested_models[fullname]
|
16
|
+
else
|
17
|
+
nested_model = Avromatic::Model.model(schema: schema,
|
18
|
+
nested_models: nested_models)
|
19
|
+
# Register the generated model with Axiom to prevent it being
|
20
|
+
# treated as a BasicObject.
|
21
|
+
# See https://github.com/solnic/virtus/issues/284#issuecomment-56405137
|
22
|
+
Axiom::Types::Object.new { primitive(nested_model) }
|
23
|
+
nested_models.register(nested_model)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'active_support/core_ext/string/access'
|
2
|
+
|
3
|
+
module Avromatic
|
4
|
+
# The ModelRegistry class is used to store and fetch nested models by
|
5
|
+
# their fullname. An optional namespace prefix can be removed from the full
|
6
|
+
# name that is used to store and fetch models.
|
7
|
+
class ModelRegistry
|
8
|
+
|
9
|
+
def initialize(remove_namespace_prefix: nil)
|
10
|
+
@prefix = remove_namespace_prefix
|
11
|
+
@hash = Hash.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def [](fullname)
|
15
|
+
@hash.fetch(fullname)
|
16
|
+
end
|
17
|
+
|
18
|
+
def register(model)
|
19
|
+
raise 'models with a key schema are not supported' if model.key_avro_schema
|
20
|
+
name = model.avro_schema.fullname
|
21
|
+
name = remove_prefix(name) if @prefix
|
22
|
+
@hash[name] = model
|
23
|
+
end
|
24
|
+
|
25
|
+
def registered?(fullname)
|
26
|
+
@hash.key?(fullname)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def remove_prefix(name)
|
32
|
+
value =
|
33
|
+
case @prefix
|
34
|
+
when String
|
35
|
+
name.from(@prefix.length) if name.start_with?(@prefix)
|
36
|
+
when Regexp
|
37
|
+
name.sub(@prefix, '')
|
38
|
+
else
|
39
|
+
raise "unsupported `remove_namespace_prefix` value: #{@prefix}"
|
40
|
+
end
|
41
|
+
|
42
|
+
value.start_with?('.') ? value.from(1) : value
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
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.9.0.
|
4
|
+
version: 0.9.0.rc2
|
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-09-
|
11
|
+
date: 2016-09-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: avro
|
@@ -257,11 +257,13 @@ files:
|
|
257
257
|
- lib/avromatic/model/logical_types.rb
|
258
258
|
- lib/avromatic/model/message_decoder.rb
|
259
259
|
- lib/avromatic/model/messaging_serialization.rb
|
260
|
+
- lib/avromatic/model/nested_models.rb
|
260
261
|
- lib/avromatic/model/null_custom_type.rb
|
261
262
|
- lib/avromatic/model/passthrough_serializer.rb
|
262
263
|
- lib/avromatic/model/raw_serialization.rb
|
263
264
|
- lib/avromatic/model/type_registry.rb
|
264
265
|
- lib/avromatic/model/value_object.rb
|
266
|
+
- lib/avromatic/model_registry.rb
|
265
267
|
- lib/avromatic/railtie.rb
|
266
268
|
- lib/avromatic/rspec.rb
|
267
269
|
- lib/avromatic/version.rb
|