avromatic 4.1.1 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7bec6621c5d35e04596185542eaa4d96d00ef67f86f24b26378c68b22ecb3b3c
4
- data.tar.gz: 1468ebd3138c5dc63a5d18d86dab5757df5c67109867628d1161b01ef70db1f3
3
+ metadata.gz: 5d9619909ed1f1301168536a2907146f30da67a08dd2bb4377d7cb0aa6cb4b6f
4
+ data.tar.gz: 3ff48eef3f8880fbd2f36eeda17008723be7bdc269a5546f432e1f5e6c09635d
5
5
  SHA512:
6
- metadata.gz: da43c835a7f56011c1ed194bba7a02e5f98a190f65a8ce025b67f8a23d9a43093e2e64f83cdaf520d847c37ecf66cfd6ed276aee7f195a9f3f2b0c248967f5bf
7
- data.tar.gz: 920048102d5947af69eca3d4e4c357adf9eefaebbd83e8d70190d29a6fb8d30c65072c97fda65613d9ebed32e127f98d9f4952e1e91e081963e61a480a002af3
6
+ metadata.gz: 61cc46b27e9544faea7b411f5f10676d206c0504fabb69f2ebf0ad00b7d6adc0610973c4c27a6716ca1e7676c6436f4be8eb1c8298978fe7b4ece5c8910fe6ae
7
+ data.tar.gz: 5ec19a93b881b723589b5f8afdaf1a0e41b15d601ca2ab840f8c627f74db3eeeab21b678c396840675caae75a3a92ccf97b872ea355cb94b2850e58d22179e12
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Avromatic
4
- VERSION = '4.1.1'
4
+ VERSION = '4.2.0'
5
5
  end
data/lib/avromatic.rb CHANGED
@@ -79,7 +79,11 @@ module Avromatic
79
79
  end
80
80
 
81
81
  def self.eager_load_models=(models)
82
- @eager_load_model_names = Array(models).map { |model| model.is_a?(Class) ? model.name : model }
82
+ @eager_load_model_names = Array(models).map { |model| model.is_a?(Class) ? model.name : model }.freeze
83
+ end
84
+
85
+ def self.eager_load_models
86
+ @eager_load_model_names
83
87
  end
84
88
 
85
89
  def self.eager_load_models!
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: 4.1.1
4
+ version: 4.2.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: 2022-09-26 00:00:00.000000000 Z
11
+ date: 2022-10-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -273,30 +273,9 @@ executables: []
273
273
  extensions: []
274
274
  extra_rdoc_files: []
275
275
  files:
276
- - ".circleci/config.yml"
277
- - ".github/CODEOWNERS"
278
- - ".gitignore"
279
- - ".overcommit.yml"
280
- - ".rspec"
281
- - ".rubocop.yml"
282
- - ".ruby-gemset"
283
- - ".ruby-version"
284
- - Appraisals
285
- - CHANGELOG.md
286
- - Gemfile
287
276
  - LICENSE.txt
288
- - README.md
289
- - Rakefile
290
- - avromatic.gemspec
291
277
  - bin/console
292
278
  - bin/setup
293
- - gemfiles/.bundle/config
294
- - gemfiles/avro1_10_rails5_2.gemfile
295
- - gemfiles/avro1_10_rails6_0.gemfile
296
- - gemfiles/avro1_10_rails6_1.gemfile
297
- - gemfiles/avro1_10_rails7_0.gemfile
298
- - gemfiles/avro1_11_rails6_1.gemfile
299
- - gemfiles/avro1_11_rails7_0.gemfile
300
279
  - lib/avromatic.rb
301
280
  - lib/avromatic/io.rb
302
281
  - lib/avromatic/io/datum_reader.rb
@@ -342,7 +321,6 @@ files:
342
321
  - lib/avromatic/railtie.rb
343
322
  - lib/avromatic/rspec.rb
344
323
  - lib/avromatic/version.rb
345
- - log/.gitkeep
346
324
  homepage: https://github.com/salsify/avromatic.git
347
325
  licenses:
348
326
  - MIT
data/.circleci/config.yml DELETED
@@ -1,88 +0,0 @@
1
- version: 2.1
2
- jobs:
3
- lint:
4
- docker:
5
- - image: salsify/ruby_ci:2.7.4
6
- working_directory: ~/avromatic
7
- steps:
8
- - checkout
9
- - restore_cache:
10
- keys:
11
- - v2-gems-ruby-2.7.4-{{ checksum "avromatic.gemspec" }}-{{ checksum "Gemfile" }}
12
- - v2-gems-ruby-2.7.4-
13
- - run:
14
- name: Install Gems
15
- command: |
16
- if ! bundle check --path=vendor/bundle; then
17
- bundle install --path=vendor/bundle --jobs=4 --retry=3
18
- bundle clean
19
- fi
20
- - save_cache:
21
- key: v2-gems-ruby-2.7.4-{{ checksum "avromatic.gemspec" }}-{{ checksum "Gemfile" }}
22
- paths:
23
- - "vendor/bundle"
24
- - "gemfiles/vendor/bundle"
25
- - run:
26
- name: Run Rubocop
27
- command: bundle exec rubocop
28
- test:
29
- parameters:
30
- gemfile:
31
- type: string
32
- ruby-version:
33
- type: string
34
- docker:
35
- - image: salsify/ruby_ci:<< parameters.ruby-version >>
36
- environment:
37
- CIRCLE_TEST_REPORTS: "test-results"
38
- BUNDLE_GEMFILE: << parameters.gemfile >>
39
- working_directory: ~/avromatic
40
- steps:
41
- - checkout
42
- - restore_cache:
43
- keys:
44
- - v2-gems-ruby-<< parameters.ruby-version >>-{{ checksum "avromatic.gemspec" }}-{{ checksum "<< parameters.gemfile >>" }}
45
- - v2-gems-ruby-<< parameters.ruby-version >>-
46
- - run:
47
- name: Install Gems
48
- command: |
49
- if ! bundle check --path=vendor/bundle; then
50
- bundle install --path=vendor/bundle --jobs=4 --retry=3
51
- bundle clean
52
- fi
53
- - save_cache:
54
- key: v2-gems-ruby-<< parameters.ruby-version >>-{{ checksum "avromatic.gemspec" }}-{{ checksum "<< parameters.gemfile >>" }}
55
- paths:
56
- - "vendor/bundle"
57
- - "gemfiles/vendor/bundle"
58
- - run:
59
- name: Run Tests
60
- command: |
61
- bundle exec rspec --format RspecJunitFormatter --out $CIRCLE_TEST_REPORTS/rspec/junit.xml --format progress spec
62
- - store_test_results:
63
- path: "test-results"
64
- workflows:
65
- build:
66
- jobs:
67
- - lint
68
- - test:
69
- matrix:
70
- parameters:
71
- gemfile:
72
- - "gemfiles/avro1_10_rails5_2.gemfile"
73
- - "gemfiles/avro1_10_rails6_0.gemfile"
74
- - "gemfiles/avro1_10_rails6_1.gemfile"
75
- - "gemfiles/avro1_10_rails7_0.gemfile"
76
- - "gemfiles/avro1_11_rails7_0.gemfile"
77
- ruby-version:
78
- - "2.7.4"
79
- - test:
80
- matrix:
81
- parameters:
82
- gemfile:
83
- - "gemfiles/avro1_10_rails6_1.gemfile"
84
- - "gemfiles/avro1_10_rails7_0.gemfile"
85
- - "gemfiles/avro1_11_rails7_0.gemfile"
86
- ruby-version:
87
- - "3.0.3"
88
- - "3.1.0"
data/.github/CODEOWNERS DELETED
@@ -1 +0,0 @@
1
- * @jturkel @tjwp @salsify/infrastructure-services
data/.gitignore DELETED
@@ -1,14 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /Gemfile.lock
4
- /_yardoc/
5
- /coverage/
6
- /doc/
7
- /pkg/
8
- /spec/reports/
9
- /tmp/
10
- /gemfiles/*.lock
11
- /log/*
12
-
13
- *.iml
14
- .idea
data/.overcommit.yml DELETED
@@ -1,14 +0,0 @@
1
- PreCommit:
2
- RuboCop:
3
- enabled: true
4
- required: false
5
- on_warn: fail
6
-
7
- HardTabs:
8
- enabled: true
9
- required: false
10
-
11
- CommitMsg:
12
- TrailingPeriod:
13
- enabled: false
14
-
data/.rspec DELETED
@@ -1,3 +0,0 @@
1
- --format documentation
2
- --color
3
- --require spec_helper
data/.rubocop.yml DELETED
@@ -1,17 +0,0 @@
1
- inherit_gem:
2
- salsify_rubocop: conf/rubocop.yml
3
-
4
- AllCops:
5
- TargetRubyVersion: 2.7
6
- Exclude:
7
- - 'vendor/**/*'
8
- - 'gemfiles/**/*'
9
-
10
- Style/MultilineBlockChain:
11
- Enabled: false
12
-
13
- Style/NumericPredicate:
14
- Enabled: false
15
-
16
- Style/FrozenStringLiteralComment:
17
- Enabled: true
data/.ruby-gemset DELETED
@@ -1 +0,0 @@
1
- avromatic
data/.ruby-version DELETED
@@ -1 +0,0 @@
1
- 2.7.4
data/Appraisals DELETED
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- appraise 'avro1_10-rails5_2' do
4
- gem 'avro', '~> 1.10.0'
5
- gem 'activesupport', '~> 5.2.0'
6
- gem 'activemodel', '~> 5.2.0'
7
- end
8
-
9
- appraise 'avro1_10-rails6_0' do
10
- gem 'avro', '~> 1.10.0'
11
- gem 'activesupport', '~> 6.0.0'
12
- gem 'activemodel', '~> 6.0.0'
13
- end
14
-
15
- appraise 'avro1_10-rails6_1' do
16
- gem 'avro', '~> 1.10.0'
17
- gem 'activesupport', '~> 6.1.0'
18
- gem 'activemodel', '~> 6.1.0'
19
- end
20
-
21
- appraise 'avro1_10-rails7_0' do
22
- gem 'avro', '~> 1.10.0'
23
- gem 'activesupport', '~> 7.0.0'
24
- gem 'activemodel', '~> 7.0.0'
25
- end
26
-
27
- appraise 'avro1_11-rails6_1' do
28
- gem 'avro', '~> 1.11.0'
29
- gem 'activesupport', '~> 6.1.0'
30
- gem 'activemodel', '~> 6.1.0'
31
- end
32
-
33
- appraise 'avro1_11-rails7_0' do
34
- gem 'avro', '~> 1.11.0'
35
- gem 'activesupport', '~> 7.0.0'
36
- gem 'activemodel', '~> 7.0.0'
37
- end
data/CHANGELOG.md DELETED
@@ -1,275 +0,0 @@
1
- # avromatic changelog
2
-
3
- ## 4.1.1
4
- - Fix eager loading of nested models when using the Zeitwerk classloader with Rails.
5
-
6
- ## 4.1.0
7
- - Add support for specifying a subject for the avro schema when building an Avromatic model
8
-
9
- ## 4.0.0
10
- - Drop support for Ruby 2.6.
11
- - Drop support for Avro 1.9.
12
- - Add support for Avro 1.11.
13
- - Add support for Rails 7.0.
14
-
15
- ## 3.0.2
16
- - Reset the schema registry client between RSpec tests to ensure any cached values are
17
- consistent with the fake schema registry.
18
-
19
- ## 3.0.1
20
- - Raise an error when registering a nested model that has already been auto-generated.
21
- This avoids hard to troubleshoot coercion errors when instantiating models and fixes
22
- a regression introduced in Avromatic 2.2.2.
23
-
24
- ## 3.0.0
25
- - Drop support for Ruby 2.4.
26
- - Add support for Ruby 3.0.
27
- - Drop support for Avro < 1.9.
28
- - Drop support for Rails < 5.2.
29
- - Fix decoding of unions containing false boolean values.
30
-
31
- ## v2.4.0
32
- - Ignore the `validate` argument and always validate during serialization. This
33
- argument will be removed in Avromatic 3.0.
34
- - Optimize model validation during serialization.
35
- - Don't cache immutable model validation results or serialized Avro attributes if a model has mutable children.
36
-
37
- ## v2.3.0
38
- - Add support for Rails 6.1.
39
- - Optimize nested model serialization.
40
-
41
- ## v2.2.6
42
- - Optimize memory usage when serializing models.
43
-
44
- ## v2.2.5
45
- - Optimize memory usage when serializing, deserializing and instantiating models.
46
-
47
- ## v2.2.4
48
- - Compatibility with Avro v1.10.x.
49
-
50
- ## v2.2.3
51
- - Fix bug where method `#referenced_model_classes` was declared as private instead of public.
52
-
53
- ## v2.2.2
54
- - Fix missing models in the model registry when in development by loading the nested models of eager loaded models.
55
- - Fake schema registry support for stubbing URLs with usernames and passwords.
56
-
57
- ## v2.2.1
58
- - Avoid allocating default empty hash in `Avromatic::IO::DatumReader.read_data`
59
-
60
- ## v2.2.0
61
- - Add support for Rails 6.0.
62
- - Drop support for Ruby < 2.4.
63
-
64
- ## v2.1.0
65
- - Add `key_schema_name` and `value_schema_name` attributes to `UnexpectedKeyError`.
66
-
67
- ## v2.0.2
68
- - Optimize model initialization and decoding
69
-
70
- ## v2.0.1
71
- - Allow generated model attribute accessors to be overridden. This was a regression in Avromatic 2.0.0.
72
- - Ensure that timestamp-millis are coerced when the number of microseconds is divisible by 1,000 but the
73
- number of nanoseconds is not divisible by 1,000,000.
74
-
75
- ## v2.0.0
76
- - Remove [virtus](https://github.com/solnic/virtus) dependency resulting in a 3x performance improvement in model instantation and 1.4x - 2.0x performance improvement in Avro serialization and Avromatic code simplification.
77
- - Raise `Avromatic::Model::CoercionError` when attribute values can't be coerced to the target type in model constructors and attribute setters. Previously coercion errors weren't detected until Avro serialization or an explicit call to `valid?`.
78
- - Prevent model instances from being constructed with unknown attributes. Previously unknown attributes were ignored.
79
- This can be disabled by setting `Avromatic.allow_unknown_attributes` to `true`.
80
- WARNING: Setting `Avromatic.allow_unknown_attributes` to `true` will result in incorrect union member coercions
81
- if an earlier union member is satisfied by a subset of the latter union member's attributes.
82
- - Validate required attributes are present when serializing to Avro for better error messages. Explicit
83
- validation can still be done by calling the `valid?` or `invalid?` methods from the
84
- [ActiveModel::Validations](https://edgeapi.rubyonrails.org/classes/ActiveModel/Validations.html) interface
85
- but errors will now appear under the `:base` key. Previously these errors were detected late in the Avro serialization process resulting in hard to understand error messages.
86
- - Support for custom types in unions with more than one non-null type.
87
- - Drop support for Ruby < 2.3 and Rails < 5.0.
88
- - Call `super()` in model constructor making it easier to define class/module hierarchies for models.
89
-
90
- ## v1.0.0
91
- - No changes.
92
-
93
- ## v0.33.0
94
- - Fix compatibility with avro-patches v0.4.0.
95
-
96
- ## v0.32.0
97
- - Improve partial assignment using a hash for records outside of unions.
98
- - Prevent invalid types from being assigned to primitives in unions.
99
- - Add validation that primitive attributes have the expected type.
100
-
101
- ## v0.31.0
102
- - Add support for Rails 5.2.
103
-
104
- ## v0.30.0
105
- - Add `Avromatic::Model::MessageDecoder#model` method to return the Avromatic
106
- model class for a message.
107
-
108
- ## v0.29.1
109
- - Add `Avromatic.build_messaging!` to `avromatic/rspec`.
110
-
111
- ## v0.29.0
112
- - Add new public methods `#avro_key_datum` and `#avro_value_datum` on an
113
- Avromatic model instance that return the attributes of the model suitable for
114
- Avro encoding without any customizations.
115
-
116
- ## v0.28.1
117
- - Fix a bug that raised an error when encoding a cached model containing optional
118
- field(s). With this change, immutable model caching now enabled only when
119
- `avro-patches` is present.
120
-
121
- ## v0.28.0
122
- - Add support for caching avro encodings for immutable models
123
-
124
- ## v0.27.0
125
- - Patches avromatic model classes to cache `Virtus::ValueObject::AllowedWriterMethods#allowed_writer_methods`
126
- - Support Rails 5.1
127
-
128
- ## v0.26.0
129
- - Caches result of Avromatic::Model::RawSerialization#value_attributes_for_avro for immutable models
130
-
131
- ## v0.25.0
132
- - Disallow optional fields in schemas used for keys by default.
133
-
134
- ## v0.24.0
135
- - Add `Avromatic::IO::DatumWriter` to optimize the encoding of Avro unions
136
- from Avromatic models.
137
- - Expose the `#key_attributes_for_avro` method on models.
138
-
139
- ## v0.23.0
140
- - Add mutable option when defining a model.
141
-
142
- ## v0.22.0
143
- - Require `avro_schema_registry_client` v0.3.0 or later to avoid
144
- using `avro-salsify-fork`.
145
-
146
- ## v0.21.1
147
- - Fix a bug in the optimization of optional union decoding.
148
-
149
- ## v0.21.0
150
- - Remove monkey-patches for `AvroTurf::ConfluentSchemaRegistry` and
151
- `FakeConfluentSchemaRegistryServer` and depend on `avro_schema_registry-client`
152
- instead.
153
- - Rename the configuration option `use_cacheable_schema_registration` to
154
- `use_schema_fingerprint_lookup`.
155
-
156
- ## v0.20.0
157
- - Support schema stores with a `#clear_schemas` method.
158
-
159
- ## v0.19.0
160
- - Use a fingerprint based on `avro-resolution_canonical_form`.
161
-
162
- ## v0.18.1
163
- - Replace another reference to `avromatic/test/fake_schema_registry_server`.
164
-
165
- ## v0.18.0
166
- - Compatibility with `avro_turf` v0.8.0. `avromatic/test/fake_schema_registry_server`
167
- is now deprecated and will be removed in a future release.
168
- Use `avromatic/test/fake_confluent_schema_registry_server` instead.
169
-
170
- ## v0.17.1
171
- - Correctly namespace Avro errors raised by `Avromatic::IO::DatumReader`.
172
-
173
- ## v0.17.0
174
- - Add `.register_schemas!` method to generated models to register the associated
175
- schemas in a schema registry.
176
-
177
- ## v0.16.0
178
- - Add `#lookup_subject_schema` method to `AvroTurf::SchemaRegistry` patch to
179
- directly support looking up existing schema ids by fingerprint.
180
-
181
- ## v0.15.1
182
- - Add `Avromatic.use_cacheable_schema_registration` option to control the lookup
183
- of existing schema ids by fingerprint.
184
-
185
- ## v0.15.0
186
- - Add patch to `AvroTurf::SchemaRegistry` to lookup existing schema ids using
187
- `GET /subjects/:subject/fingerprints/:fingerprint` from `#register`.
188
- This endpoint is supported in the avro-schema-registry.
189
- - Add patch to the `FakeSchemaRegistryServer` from `AvroTurf` to support the
190
- fingerprint endpoint.
191
-
192
- ## v0.14.0
193
- - Add `Avromatic::Messaging` and `Avromatic::IO::DatumReader` classes to
194
- optimize the decoding of Avro unions to Avromatic models.
195
-
196
- ## v0.13.0
197
- - Add interfaces to deserialize as a hash of attributes instead of a model.
198
-
199
- ## v0.12.0
200
- - Clear the schema store, if it supports it, prior to code reloading in Rails
201
- applications. This allows schema changes to be picked up during code
202
- reloading.
203
-
204
- ## v0.11.2
205
- - Fix for models containing optional array and map fields.
206
-
207
- ## v0.11.1
208
- - Another fix for Rails initialization and reloading. Do not clear the nested
209
- models registry the first time that the `to_prepare` hook is called.
210
-
211
- ## v0.11.0
212
- - Replace `Avromatic.on_initialize` proc with `Avromatic.eager_load_models`
213
- array. The models listed by this configuration are added to the registry
214
- at the end of `.configure` and prior to code reloading in Rails applications.
215
- This is a compatibility breaking change.
216
-
217
- ## v0.10.0
218
- - Add `Avromatic.on_initialize` proc that is called at the end of `.configure`
219
- and on code reloading in Rails applications.
220
-
221
- ## v0.9.0
222
- - Experimental: Add support for more than one non-null type in a union.
223
- - Allow nested models to be referenced and reused.
224
- - Fix the serialization of nested complex types.
225
- - Add support for recursive models.
226
- - Allow required array and map fields to be empty. Only nil values for required
227
- array and map fields are now considered invalid.
228
- - Validate nested models. This includes models embedded within other complex
229
- types (array, map, and union).
230
- - Truncate values for timestamps to the precision supported by the logical type.
231
-
232
- ## v0.8.0
233
- - Add support for logical types. Currently this requires using the
234
- `avro-salsify-fork` gem for logical types support with Ruby.
235
-
236
- ## v0.7.1
237
- - Raise a more descriptive error when attempting to generate a model for a
238
- non-record Avro type.
239
-
240
- ## v0.7.0
241
- - Add RSpec `FakeSchemaRegistryServer` test helper.
242
-
243
- ## v0.6.2
244
- - Remove dependency on `Hash#transform_values` from `ActiveSupport` v4.2.
245
-
246
- ## v0.6.1
247
- - Fix serialization of array and map types that contain nested models.
248
-
249
- ## v0.6.0
250
- - Require `avro_turf` v0.7.0 or later.
251
-
252
- ## v0.5.0
253
- - Rename `Avromatic::Model::Decoder` to `MessageDecoder`.
254
- - Rename `.deserialize` on generated models to `.avro_message_decode`.
255
- - Add `#avro_raw_key`, `#avro_raw_value` and `.avro_raw_decode` methods to
256
- generated models to support encoding and decoding without a schema registry.
257
-
258
- ## v0.4.0
259
- - Allow the specification of a custom type, including conversion to/from Avro,
260
- for named types.
261
-
262
- ## v0.3.0
263
- - Remove dependency on the `private_attr` gem.
264
-
265
- ## v0.2.0
266
- - Allow a module level schema registry to be configured.
267
-
268
- ## v0.1.2
269
- - Do not build an `AvroTurf::Messaging` object for each model class.
270
-
271
- ## v0.1.1
272
- - Fix Railtie.
273
-
274
- ## v0.1.0
275
- - Initial release
data/Gemfile DELETED
@@ -1,6 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- source 'https://rubygems.org'
4
-
5
- # Specify your gem's dependencies in avromatic.gemspec
6
- gemspec
data/README.md DELETED
@@ -1,477 +0,0 @@
1
- # Avromatic
2
-
3
- [![Build Status](https://circleci.com/gh/salsify/avromatic.svg?style=svg)][circleci]
4
- [![Gem Version](https://badge.fury.io/rb/avromatic.svg)](https://badge.fury.io/rb/avromatic)
5
-
6
- [circleci]: https://circleci.com/gh/salsify/avromatic
7
-
8
- `Avromatic` generates Ruby models from [Avro](http://avro.apache.org/) schemas
9
- and provides utilities to encode and decode them.
10
-
11
- **This README reflects Avromatic 2.0. Please see the
12
- [1-0-stable](https://github.com/salsify/avromatic/blob/1-0-stable/README.md) branch for Avromatic 1.0.**
13
-
14
- ## Installation
15
-
16
- Add this line to your application's Gemfile:
17
-
18
- ```ruby
19
- gem 'avromatic'
20
- ```
21
-
22
- And then execute:
23
-
24
- $ bundle
25
-
26
- Or install it yourself as:
27
-
28
- $ gem install avromatic
29
-
30
- See the [Logical Types](#logical-types) section below for details on using
31
- Avromatic with unreleased Avro features.
32
-
33
- ## Usage
34
-
35
- ### Configuration
36
-
37
- `Avromatic` supports the following configuration:
38
-
39
- #### Model Generation
40
-
41
- * **schema_store**: A schema store is required to load Avro schemas from the filesystem.
42
- It should be an object that responds to `find(name, namespace = nil)` and
43
- returns an `Avro::Schema` object. An `AvroTurf::SchemaStore` can be used.
44
- The `schema_store` is unnecessary if models are generated directly from
45
- `Avro::Schema` objects. See [Models](#models).
46
- * **nested_models**: An optional [ModelRegistry](https://github.com/salsify/avromatic/blob/master/lib/avromatic/model_registry.rb)
47
- that is used to store, by full schema name, the generated models that are
48
- embedded within top-level models. By default a new `Avromatic::ModelRegistry`
49
- is created.
50
- * **eager_load_models**: An optional array of models, or strings with class
51
- names for models, that are added to `nested_models` at the end of
52
- `Avromatic.configure` and during code reloading in Rails applications. This
53
- option is useful for defining models that will be extended when the load order
54
- is important.
55
- * **allow_unknown_attributes**: Optionally allow model constructors to silently
56
- ignore unknown attributes. Defaults to `false`. WARNING: Setting this to `true`
57
- will result in incorrect union member coercions if an earlier union member is
58
- satisfied by a subset of the latter union member's attributes.
59
-
60
- #### Custom Types
61
-
62
- See the section below on configuring [Custom Types](#custom-type-configuration).
63
-
64
- #### Using a Schema Registry/Messaging API
65
-
66
- The configuration options below are required when using a schema registry
67
- (see [Confluent Schema Registry](http://docs.confluent.io/2.0.1/schema-registry/docs/intro.html))
68
- and the [Messaging API](#messaging-api).
69
-
70
- * **schema_registry**: An `AvroSchemaRegistry::Client` or
71
- `AvroTurf::ConfluentSchemaRegistry` object used to store Avro schemas
72
- so that they can be referenced by id. Either `schema_registry` or
73
- `registry_url` must be configured.
74
- * **registry_url**: URL for the schema registry. Either `schema_registry` or
75
- `registry_url` must be configured. The `build_schema_registry!` method may
76
- be used to create a caching schema registry client instance based on other
77
- configuration values.
78
- * **use_schema_fingerprint_lookup**: Avromatic supports a Schema Registry
79
- [extension](https://github.com/salsify/avro-schema-registry#extensions) that
80
- provides an endpoint to lookup existing schema ids by fingerprint.
81
- A successful response from this GET request can be cached indefinitely.
82
- The use of this additional endpoint can be disabled by setting this option to
83
- `false` and this is recommended if using a Schema Registry that does not support
84
- the endpoint.
85
- * **messaging**: An `AvroTurf::Messaging` object to be shared by all generated models
86
- The `build_messaging!` method may be used to create a `Avromatic::Messaging`
87
- instance based on the other configuration values.
88
- * **logger**: The logger to use for the schema registry client.
89
-
90
- Example using a schema registry:
91
-
92
- ```ruby
93
- Avromatic.configure do |config|
94
- config.schema_store = AvroTurf::SchemaStore.new(path: 'avro/schemas')
95
- config.registry_url = Rails.configuration.x.avro_schema_registry_url
96
- config.build_schema_registry!
97
- config.build_messaging!
98
- end
99
- ```
100
-
101
- #### Decoding
102
-
103
- * **use_custom_datum_reader**: `Avromatic` includes a modified subclass of
104
- `Avro::IO::DatumReader`. This subclass returns additional information about
105
- the index of union members when decoding Avro messages. This information is
106
- used to optimize model creation when decoding. By default this information
107
- is included in the hash returned by the `DatumReader` but can be omitted by
108
- setting this option to `false`.
109
-
110
- #### Encoding
111
- * **use_custom_datum_writer**: `Avromatic` includes a modified subclass of
112
- `Avro::IO::DatumWriter`. This subclass supports caching avro encodings for
113
- immutable models and uses additional information about the index of union
114
- members to optimize the encoding of Avro messages. By default this
115
- information is included in the hash passed to the encoder but can be omitted
116
- by setting this option to `false`.
117
-
118
-
119
- ### Models
120
-
121
- Models are defined based on an Avro schema for a record.
122
-
123
- The Avro schema can be specified by name and loaded using the schema store:
124
-
125
- ```ruby
126
- class MyModel
127
- include Avromatic::Model.build(schema_name: :my_model)
128
- end
129
-
130
- # Construct instances by passing in a hash of attributes
131
- instance = MyModel.new(id: 123, name: 'Tesla Model 3', enabled: true)
132
-
133
- # Access attribute values with readers
134
- instance.name # => "Tesla Model 3"
135
-
136
- # Models are immutable by default
137
- instance.name = 'Tesla Model X' # => NoMethodError (private method `name=' called for #<MyModel:0x00007ff711e64e60>)
138
-
139
- # Booleans can also be accessed by '?' readers that coerce nil to false
140
- instance.enabled? # => true
141
-
142
- # Models implement ===, eql? and hash
143
- instance == MyModel.new(id: 123, name: 'Tesla Model 3', enabled: true) # => true
144
- instance.eql?(MyModel.new(id: 123, name: 'Tesla Model 3', enabled: true)) # => true
145
- instance.hash # => -1279155042741869898
146
-
147
- # Retrieve a hash of the model's attributes via to_h, to_hash or attributes
148
- instance.to_h # => {:id=>123, :name=>"Tesla Model 3", :enabled=>true}
149
- ```
150
-
151
- Or an `Avro::Schema` object can be specified directly:
152
-
153
- ```ruby
154
- class MyModel
155
- include Avromatic::Model.build(schema: schema_object)
156
- end
157
- ```
158
-
159
- A specific subject name can be associated with the schema:
160
- ```ruby
161
- class MyModel
162
- include Avromatic::Model.build(schema_name: 'my_model',
163
- schema_subject: 'my_model-value')
164
- end
165
- ```
166
-
167
- Models are generated as immutable value
168
- objects by default, but can optionally be defined as mutable:
169
-
170
- ```ruby
171
- class MyModel
172
- include Avromatic::Model.build(schema_name: :my_model, mutable: true)
173
- end
174
- ```
175
-
176
- Generated models include attributes for each field in the Avro schema
177
- including any default values defined in the schema.
178
-
179
- A model may be defined with both a key and a value schema:
180
-
181
- ```ruby
182
- class MyTopic
183
- include Avromatic::Model.build(value_schema_name: :topic_value,
184
- key_schema_name: :topic_key)
185
- end
186
- ```
187
-
188
- When key and value schemas are both specified, attributes are added to the model
189
- for the union of the fields in the two schemas.
190
-
191
- By default, optional fields are not allowed in key schemas since their values may
192
- be accidentally omitted leading to problems if data is partitioned based on the
193
- key values.
194
-
195
- This behavior can be overridden by specifying the `:allow_optional_key_fields`
196
- option for the model:
197
-
198
- ```ruby
199
- class MyTopic
200
- include Avromatic::Model.build(value_schema_name: :topic_value,
201
- key_schema_name: :topic_key,
202
- allow_optional_key_fields: true)
203
- end
204
- ```
205
-
206
- A specific subject name can be associated with both the value and key schemas:
207
- ```ruby
208
- class MyTopic
209
- include Avromatic::Model.build(value_schema_name: :topic_value,
210
- value_schema_subject: 'topic_value-value',
211
- key_schema_name: :topic_key,
212
- key_schema_subject: 'topic_key-value')
213
- end
214
- ```
215
-
216
- A model can also be generated as an anonymous class that can be assigned to a
217
- constant:
218
-
219
- ```ruby
220
- MyModel = Avromatic::Model.model(schema_name :my_model)
221
- ```
222
-
223
- #### Experimental: Union Support
224
-
225
- Avromatic contains experimental support for unions containing more than one
226
- non-null member type. This feature is experimental because Avromatic
227
- may attempt to coerce between types too aggressively.
228
-
229
- For now, if a union contains [nested models](#nested-models) then it is
230
- recommended that you assign model instances.
231
-
232
- Some combination of the ordering of member types in the union and relying on
233
- model validation may be required so that the correct member is selected,
234
- especially when deserializing from Avro.
235
-
236
- In the future, the type coercion used in the gem will be enhanced to better
237
- support the union use case.
238
-
239
- #### Nested Models
240
-
241
- Nested models are models that are embedded within top-level models generated
242
- using Avromatic. Normally these nested models are automatically generated.
243
-
244
- By default, nested models are stored in `Avromatic.nested_models`. This is an
245
- `Avromatic::ModelRegistry` instance that provides access to previously generated
246
- nested models by the full name of their Avro schema.
247
-
248
- ```ruby
249
- Avromatic.nested_models['com.my_company.test.example']
250
- #=> <model class>
251
- ```
252
-
253
- The `ModelRegistry` can be customized to remove a namespace prefix:
254
-
255
- ```ruby
256
- Avromatic.nested_models =
257
- Avromatic::ModelRegistry.new(remove_namespace_prefix: 'com.my_company')
258
- ```
259
-
260
- The `:remove_namespace_prefix` value can be a string or a regexp.
261
-
262
- By default, top-level generated models reuse `Avromatic.nested_models`. This
263
- allows nested models to be shared across different generated models.
264
- A `:nested_models` option can be specified when generating a model. This allows
265
- the reuse of nested models to be scoped:
266
-
267
- ```ruby
268
- Avromatic::Model.model(schema_name, :my_model
269
- nested_models: ModelRegistry.new)
270
- ```
271
-
272
- Only models without a key schema can be used as nested models. When a model is
273
- generated with just a value schema then it is automatically registered so that
274
- it can be used as a nested model.
275
-
276
- To extend a model that will be used as a nested model, you must ensure that it
277
- is defined, which will register it, prior it being referenced by another model.
278
-
279
- Using the `Avromatic.eager_load_models` option allows models that are extended
280
- and will be used as nested models to be defined at the end of the `.configure`
281
- block. In Rails applications, these models are also re-registered after
282
- `nested_models` is cleared when code reloads to ensure that classes load in the
283
- correct order:
284
-
285
- ```ruby
286
- Avromatic.configure do |config|
287
- config.eager_load_models = [
288
- # reference any extended models that should be defined first
289
- 'MyNestedModel'
290
- ]
291
- end
292
- ```
293
-
294
- #### Custom Type Configuration
295
-
296
- Custom types can be configured for fields of named types (record, enum, fixed).
297
- These customizations are registered on the `Avromatic` module. Once a custom type
298
- is registered, it is used for all models with a schema that references that type.
299
- It is recommended to register types within a block passed to `Avromatic.configure`:
300
-
301
- ```ruby
302
- Avromatic.configure do |config|
303
- config.register_type('com.example.my_string', MyString)
304
- end
305
- ```
306
-
307
- The full name of the type and an optional class may be specified. When a class is
308
- provided then values for attributes of that type are defined using the specified
309
- class.
310
-
311
- If the provided class responds to the class methods `from_avro` and `to_avro`
312
- then those methods are used to convert values when assigning to the model and
313
- before encoding using Avro respectively.
314
-
315
- `from_avro` and `to_avro` methods may be also be specified as Procs when
316
- registering the type:
317
-
318
- ```ruby
319
- Avromatic.configure do |config|
320
- config.register_type('com.example.updown_string') do |type|
321
- type.from_avro = ->(value) { value.upcase }
322
- type.to_avro = ->(value) { value.downcase }
323
- end
324
- end
325
- ```
326
-
327
- Nil handling is not required as the conversion methods are not be called if the
328
- inbound or outbound value is nil.
329
-
330
- If a custom type is registered for a record-type field, then any `to_avro`
331
- method/Proc should return a Hash with string keys for encoding using Avro.
332
-
333
- ### Encoding and Decoding
334
-
335
- `Avromatic` provides two different interfaces for encoding the key (optional)
336
- and value associated with a model.
337
-
338
- #### Manually Managed Schemas
339
-
340
- The attributes for the value schema used to define a model can be encoded using:
341
-
342
- ```ruby
343
- encoded_value = model.avro_raw_value
344
- ```
345
-
346
- In order to decode this data, a copy of the value schema is required.
347
-
348
- If a model also has an Avro schema for a key, then the key attributes can be
349
- encoded using:
350
-
351
- ```ruby
352
- encoded_key = model.avro_raw_key
353
- ```
354
-
355
- If attributes were encoded using the same schema(s) used to define a model, then
356
- the data can be decoded to create a new model instance:
357
-
358
- ```ruby
359
- MyModel.avro_raw_decode(key: encoded_key, value: encoded_value)
360
- ```
361
-
362
- If the attributes where encoded using a different version of the model's schemas,
363
- then a new model instance can be created by also providing the schemas used to
364
- encode the data:
365
-
366
- ```ruby
367
- MyModel.avro_raw_decode(key: encoded_key,
368
- key_schema: writers_key_schema,
369
- value: encoded_value,
370
- value_schema: writers_value_schema)
371
- ```
372
-
373
- #### Messaging API
374
-
375
- The other interface for encoding and decoding attributes uses the
376
- `AvroTurf::Messaging` API. This interface leverages a schema registry and
377
- prefixes the encoded data with an id to identify the schema. In this approach,
378
- a schema registry is used to ensure that the correct schemas are available during
379
- decoding.
380
-
381
- The attributes for the value schema can be encoded with a schema id prefix using:
382
-
383
- ```ruby
384
- message_value = model.avro_message_value
385
- ```
386
-
387
- If a model has an Avro schema for a key, then those attributes can also be encoded
388
- prefixed with a schema id:
389
-
390
- ```ruby
391
- message_key = model.avro_message_key
392
- ```
393
-
394
- A model instance can be created from a key and value encoded in this manner:
395
-
396
- ```ruby
397
- MyTopic.avro_message_decode(message_key, message_value)
398
- ```
399
-
400
- Or just a value if only one schema is used:
401
-
402
- ```ruby
403
- MyValue.avro_message_decode(message_value)
404
- ```
405
-
406
- The schemas associated with a model can also be added to a schema registry without
407
- encoding a message:
408
-
409
- ```ruby
410
- MyTopic.register_schemas!
411
- ```
412
-
413
- #### Avromatic::Model::MessageDecoder
414
-
415
- A stream of messages encoded from various models using the messaging approach
416
- can be decoded using `Avromatic::Model::MessageDecoder`. The decoder must be
417
- initialized with the list of models to decode:
418
-
419
- ```ruby
420
- decoder = Avromatic::Model::MessageDecoder.new(MyModel1, MyModel2)
421
-
422
- decoder.decode(model1_messge_key, model1_message_value)
423
- # => instance of MyModel1
424
- decoder.decode(model2_message_value)
425
- # => instance of MyModel2
426
- ```
427
-
428
- ### Validations and Coercions
429
-
430
- An exception will be thrown if an attribute value cannot be coerced to the corresponding Avro schema field's type.
431
- The following coercions are supported:
432
-
433
- | Ruby Type | Avro Type |
434
- | --------- | --------- |
435
- | String, Symbol | string |
436
- | Array | array |
437
- | Hash | map |
438
- | Integer, Float | int |
439
- | Integer | long |
440
- | Float | float |
441
- | Float | double |
442
- | String | bytes |
443
- | Date, Time, DateTime | date |
444
- | Time, DateTime | timestamp-millis |
445
- | Time, DateTime | timestamp-micros |
446
- | TrueClass, FalseClass | boolean |
447
- | NilClass | null |
448
- | Hash | record |
449
-
450
- Validation of required fields is done automatically when serializing a model to Avro. It can also be done
451
- explicitly by calling the `valid?` or `invalid?` methods from the
452
- [ActiveModel::Validations](https://edgeapi.rubyonrails.org/classes/ActiveModel/Validations.html) interface.
453
-
454
- ### RSpec Support
455
-
456
- This gem also includes an `"avromatic/rspec"` file that can be required to support
457
- using Avromatic with a fake schema registry during tests.
458
-
459
- Requiring this file configures a RSpec before hook that directs any schema
460
- registry requests to a fake, in-memory schema registry and rebuilds the
461
- `Avromatic::Messaging` object for each example.
462
-
463
- ## Development
464
-
465
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
466
-
467
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
468
-
469
- ## Contributing
470
-
471
- Bug reports and pull requests are welcome on GitHub at https://github.com/salsify/avromatic.
472
-
473
-
474
- ## License
475
-
476
- The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
477
-
data/Rakefile DELETED
@@ -1,32 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'bundler/gem_tasks'
4
- require 'rspec/core/rake_task'
5
- require 'appraisal/task'
6
- require 'avro/builder'
7
-
8
- RSpec::Core::RakeTask.new(:default_spec)
9
-
10
- Appraisal::Task.new
11
-
12
- if !ENV['APPRAISAL_INITIALIZED']
13
- task default: :appraisal
14
- task spec: :appraisal
15
- else
16
- task default: :default_spec
17
- end
18
-
19
- namespace :avro do
20
- desc 'Generate Avro schema files used by specs'
21
- task :generate_spec do
22
- root = 'spec/avro/dsl'
23
- Avro::Builder.add_load_path(root)
24
- Dir["#{root}/**/*.rb"].each do |dsl_file|
25
- puts "Generating Avro schema from #{dsl_file}"
26
- output_file = dsl_file.sub('/dsl/', '/schema/').sub(/\.rb$/, '.avsc')
27
- schema = Avro::Builder.build(File.read(dsl_file))
28
- FileUtils.mkdir_p(File.dirname(output_file))
29
- File.write(output_file, schema.end_with?("\n") ? schema : schema << "\n")
30
- end
31
- end
32
- end
data/avromatic.gemspec DELETED
@@ -1,53 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- lib = File.expand_path('lib', __dir__)
4
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
- require 'avromatic/version'
6
-
7
- Gem::Specification.new do |spec|
8
- spec.name = 'avromatic'
9
- spec.version = Avromatic::VERSION
10
- spec.authors = ['Salsify Engineering']
11
- spec.email = ['engineering@salsify.com']
12
-
13
- spec.summary = 'Generate Ruby models from Avro schemas'
14
- spec.description = spec.summary
15
- spec.homepage = 'https://github.com/salsify/avromatic.git'
16
- spec.license = 'MIT'
17
-
18
- if spec.respond_to?(:metadata)
19
- spec.metadata['allowed_push_host'] = 'https://rubygems.org'
20
- spec.metadata['rubygems_mfa_required'] = 'true'
21
- else
22
- raise 'RubyGems 2.0 or newer is required to set allowed_push_host.'
23
- end
24
-
25
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
26
- spec.bindir = 'exe'
27
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
- spec.require_paths = ['lib']
29
-
30
- spec.metadata['rubygems_mfa_required'] = 'true'
31
-
32
- spec.required_ruby_version = '>= 2.7'
33
-
34
- spec.add_runtime_dependency 'activemodel', '>= 5.2', '< 7.1'
35
- spec.add_runtime_dependency 'activesupport', '>= 5.2', '< 7.1'
36
- spec.add_runtime_dependency 'avro', '>= 1.10.0', '< 1.12'
37
- spec.add_runtime_dependency 'avro_schema_registry-client', '>= 0.4.0'
38
- spec.add_runtime_dependency 'avro_turf'
39
- spec.add_runtime_dependency 'ice_nine'
40
-
41
- spec.add_development_dependency 'appraisal'
42
- spec.add_development_dependency 'avro-builder', '>= 0.12.0'
43
- spec.add_development_dependency 'bundler', '~> 2.0'
44
- spec.add_development_dependency 'overcommit', '0.35.0'
45
- spec.add_development_dependency 'rake', '~> 13.0'
46
- spec.add_development_dependency 'rspec', '~> 3.8'
47
- spec.add_development_dependency 'rspec_junit_formatter'
48
- spec.add_development_dependency 'salsify_rubocop', '~> 1.27.1'
49
- spec.add_development_dependency 'simplecov'
50
- spec.add_development_dependency 'webmock'
51
- # For AvroSchemaRegistry::FakeServer
52
- spec.add_development_dependency 'sinatra'
53
- end
@@ -1,2 +0,0 @@
1
- ---
2
- BUNDLE_RETRY: "1"
@@ -1,9 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "avro", "~> 1.10.0"
6
- gem "activesupport", "~> 5.2.0"
7
- gem "activemodel", "~> 5.2.0"
8
-
9
- gemspec path: "../"
@@ -1,9 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "avro", "~> 1.10.0"
6
- gem "activesupport", "~> 6.0.0"
7
- gem "activemodel", "~> 6.0.0"
8
-
9
- gemspec path: "../"
@@ -1,9 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "avro", "~> 1.10.0"
6
- gem "activesupport", "~> 6.1.0"
7
- gem "activemodel", "~> 6.1.0"
8
-
9
- gemspec path: "../"
@@ -1,9 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "avro", "~> 1.10.0"
6
- gem "activesupport", "~> 7.0.0"
7
- gem "activemodel", "~> 7.0.0"
8
-
9
- gemspec path: "../"
@@ -1,9 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "avro", "~> 1.11.0"
6
- gem "activesupport", "~> 6.1.0"
7
- gem "activemodel", "~> 6.1.0"
8
-
9
- gemspec path: "../"
@@ -1,9 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "avro", "~> 1.11.0"
6
- gem "activesupport", "~> 7.0.0"
7
- gem "activemodel", "~> 7.0.0"
8
-
9
- gemspec path: "../"
data/log/.gitkeep DELETED
File without changes