avromatic 2.2.4 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +89 -0
  3. data/.gitignore +3 -0
  4. data/.rubocop.yml +4 -1
  5. data/Appraisals +8 -14
  6. data/CHANGELOG.md +23 -0
  7. data/README.md +3 -20
  8. data/avromatic.gemspec +9 -8
  9. data/bin/console +4 -3
  10. data/gemfiles/avro1_10_rails6_1.gemfile +9 -0
  11. data/gemfiles/{avro1_8_rails5_2.gemfile → avro1_9_rails6_1.gemfile} +3 -3
  12. data/lib/avromatic.rb +0 -5
  13. data/lib/avromatic/io.rb +1 -7
  14. data/lib/avromatic/io/datum_reader.rb +18 -68
  15. data/lib/avromatic/io/datum_writer.rb +5 -11
  16. data/lib/avromatic/io/union_datum.rb +25 -0
  17. data/lib/avromatic/messaging.rb +4 -2
  18. data/lib/avromatic/model/attributes.rb +28 -9
  19. data/lib/avromatic/model/configurable.rb +30 -2
  20. data/lib/avromatic/model/configuration.rb +5 -0
  21. data/lib/avromatic/model/field_helper.rb +5 -1
  22. data/lib/avromatic/model/messaging_serialization.rb +2 -1
  23. data/lib/avromatic/model/raw_serialization.rb +67 -24
  24. data/lib/avromatic/model/types/abstract_timestamp_type.rb +1 -1
  25. data/lib/avromatic/model/types/abstract_type.rb +3 -1
  26. data/lib/avromatic/model/types/array_type.rb +2 -2
  27. data/lib/avromatic/model/types/boolean_type.rb +1 -1
  28. data/lib/avromatic/model/types/custom_type.rb +1 -1
  29. data/lib/avromatic/model/types/date_type.rb +1 -1
  30. data/lib/avromatic/model/types/enum_type.rb +1 -1
  31. data/lib/avromatic/model/types/fixed_type.rb +1 -1
  32. data/lib/avromatic/model/types/float_type.rb +1 -1
  33. data/lib/avromatic/model/types/integer_type.rb +1 -1
  34. data/lib/avromatic/model/types/map_type.rb +2 -2
  35. data/lib/avromatic/model/types/null_type.rb +1 -1
  36. data/lib/avromatic/model/types/record_type.rb +4 -7
  37. data/lib/avromatic/model/types/string_type.rb +1 -1
  38. data/lib/avromatic/model/types/union_type.rb +12 -9
  39. data/lib/avromatic/model/validation.rb +2 -2
  40. data/lib/avromatic/version.rb +1 -1
  41. metadata +45 -34
  42. data/.travis.yml +0 -16
  43. data/gemfiles/avro_patches_rails5_2.gemfile +0 -9
  44. data/gemfiles/avro_patches_rails6_0.gemfile +0 -9
  45. data/lib/avromatic/patches.rb +0 -18
  46. data/lib/avromatic/patches/schema_validator_patch.rb +0 -39
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8cc3e17c99ffc3587dc747dbc97da2b63304e20e2bbc7f335a00878ae87bbcf2
4
- data.tar.gz: 47e581e34bf75f8ea6fd6775ab91c67c51566475e0d831452bd6ef922f185151
3
+ metadata.gz: d90a142c407a453ef9007373f215d8acd137937e54b46aa2c29e8edcf8440aef
4
+ data.tar.gz: c8eecbb9860859346d9a67e3e2a78a2e38447bdff4d4fb9208f57bcf89940215
5
5
  SHA512:
6
- metadata.gz: 29d285151df19f4a3611889c2b805a3de2018c08120a6fca53a88234ab5028b63f83c0f499118a56ca23709071a8ef811713575e6d621c74c42ff6936cd038af
7
- data.tar.gz: 97bb648dd3e554219b5ecf81611c1dbc482467fabc50c1f219c0d2b52e31eb891903be92cb20b472f3c9e4ac07d2507d59a2b16dacbec374d22a712b19c4c50c
6
+ metadata.gz: 77b078294c887e298e4ede5f1f47cfccaccffd0b065ad1d4bad9820d2af8c77e522462282d1d44db35acefaf6fc301ccb7a59dfda844c5ebee297d51792ee912
7
+ data.tar.gz: 8f57c2afee1266f790c031920efb7e1690420e4c6de36d22af3e11361bc5bf7eaabb3eba4e2974a994a7f7509e3db01335c954895c981db4069a8c7828b483de
@@ -0,0 +1,89 @@
1
+ version: 2.1
2
+ jobs:
3
+ lint:
4
+ docker:
5
+ - image: salsify/ruby_ci:2.5.8
6
+ working_directory: ~/avromatic
7
+ steps:
8
+ - checkout
9
+ - restore_cache:
10
+ keys:
11
+ - v2-gems-ruby-2.5.8-{{ checksum "avromatic.gemspec" }}-{{ checksum "Gemfile" }}
12
+ - v2-gems-ruby-2.5.8-
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.5.8-{{ 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_9_rails5_2.gemfile"
73
+ - "gemfiles/avro1_10_rails5_2.gemfile"
74
+ - "gemfiles/avro1_9_rails6_0.gemfile"
75
+ - "gemfiles/avro1_10_rails6_0.gemfile"
76
+ - "gemfiles/avro1_10_rails6_1.gemfile"
77
+ - "gemfiles/avro1_9_rails6_1.gemfile"
78
+ ruby-version:
79
+ - "2.5.8"
80
+ - "2.6.6"
81
+ - "2.7.2"
82
+ - test:
83
+ matrix:
84
+ parameters:
85
+ gemfile:
86
+ - "gemfiles/avro1_10_rails6_1.gemfile"
87
+ - "gemfiles/avro1_9_rails6_1.gemfile"
88
+ ruby-version:
89
+ - "3.0.0"
data/.gitignore CHANGED
@@ -9,3 +9,6 @@
9
9
  /tmp/
10
10
  /gemfiles/*.lock
11
11
  /log/*
12
+
13
+ *.iml
14
+ .idea
data/.rubocop.yml CHANGED
@@ -2,7 +2,10 @@ inherit_gem:
2
2
  salsify_rubocop: conf/rubocop.yml
3
3
 
4
4
  AllCops:
5
- TargetRubyVersion: 2.4
5
+ TargetRubyVersion: 2.5
6
+ Exclude:
7
+ - 'vendor/**/*'
8
+ - 'gemfiles/vendor/**/*'
6
9
 
7
10
  Style/MultilineBlockChain:
8
11
  Enabled: false
data/Appraisals CHANGED
@@ -1,11 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- appraise 'avro1_8-rails5_2' do
4
- gem 'avro', '1.8.2'
5
- gem 'activesupport', '~> 5.2.0'
6
- gem 'activemodel', '~> 5.2.0'
7
- end
8
-
9
3
  appraise 'avro1_9-rails5_2' do
10
4
  gem 'avro', '1.9.2'
11
5
  gem 'activesupport', '~> 5.2.0'
@@ -30,14 +24,14 @@ appraise 'avro1_10-rails6_0' do
30
24
  gem 'activemodel', '~> 6.0.0'
31
25
  end
32
26
 
33
- appraise 'avro-patches-rails5_2' do
34
- gem 'avro-patches', '>= 0.4.1', '< 1.0'
35
- gem 'activesupport', '~> 5.2.0'
36
- gem 'activemodel', '~> 5.2.0'
27
+ appraise 'avro1_9-rails6_1' do
28
+ gem 'avro', '1.9.2'
29
+ gem 'activesupport', '~> 6.1.0'
30
+ gem 'activemodel', '~> 6.1.0'
37
31
  end
38
32
 
39
- appraise 'avro-patches-rails6_0' do
40
- gem 'avro-patches', '>= 1.0.0'
41
- gem 'activesupport', '~> 6.0.0'
42
- gem 'activemodel', '~> 6.0.0'
33
+ appraise 'avro1_10-rails6_1' do
34
+ gem 'avro', '~> 1.10.0'
35
+ gem 'activesupport', '~> 6.1.0'
36
+ gem 'activemodel', '~> 6.1.0'
43
37
  end
data/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # avromatic changelog
2
2
 
3
+ ## 3.0.0
4
+ - Drop support for Ruby 2.4.
5
+ - Add support for Ruby 3.0.
6
+ - Drop support for Avro < 1.9.
7
+ - Drop support for Rails < 5.2.
8
+ - Fix decoding of unions containing false boolean values.
9
+
10
+ ## v2.4.0
11
+ - Ignore the `validate` argument and always validate during serialization. This
12
+ argument will be removed in Avromatic 3.0.
13
+ - Optimize model validation during serialization.
14
+ - Don't cache immutable model validation results or serialized Avro attributes if a model has mutable children.
15
+
16
+ ## v2.3.0
17
+ - Add support for Rails 6.1.
18
+ - Optimize nested model serialization.
19
+
20
+ ## v2.2.6
21
+ - Optimize memory usage when serializing models.
22
+
23
+ ## v2.2.5
24
+ - Optimize memory usage when serializing, deserializing and instantiating models.
25
+
3
26
  ## v2.2.4
4
27
  - Compatibility with Avro v1.10.x.
5
28
 
data/README.md CHANGED
@@ -1,9 +1,9 @@
1
1
  # Avromatic
2
2
 
3
- [![Build Status](https://travis-ci.org/salsify/avromatic.svg?branch=master)][travis]
3
+ [![Build Status](https://circleci.com/gh/salsify/avromatic.svg?style=svg)][circleci]
4
4
  [![Gem Version](https://badge.fury.io/rb/avromatic.svg)](https://badge.fury.io/rb/avromatic)
5
5
 
6
- [travis]: http://travis-ci.org/salsify/avromatic
6
+ [circleci]: https://circleci.com/gh/salsify/avromatic
7
7
 
8
8
  `Avromatic` generates Ruby models from [Avro](http://avro.apache.org/) schemas
9
9
  and provides utilities to encode and decode them.
@@ -142,7 +142,7 @@ instance.eql?(MyModel.new(id: 123, name: 'Tesla Model 3', enabled: true)) # => t
142
142
  instance.hash # => -1279155042741869898
143
143
 
144
144
  # Retrieve a hash of the model's attributes via to_h, to_hash or attributes
145
- instance .to_h # => {:id=>123, :name=>"Tesla Model 3", :enabled=>true}
145
+ instance.to_h # => {:id=>123, :name=>"Tesla Model 3", :enabled=>true}
146
146
  ```
147
147
 
148
148
  Or an `Avro::Schema` object can be specified directly:
@@ -430,23 +430,6 @@ Validation of required fields is done automatically when serializing a model to
430
430
  explicitly by calling the `valid?` or `invalid?` methods from the
431
431
  [ActiveModel::Validations](https://edgeapi.rubyonrails.org/classes/ActiveModel/Validations.html) interface.
432
432
 
433
- ### Logical Types
434
-
435
- Currently the official Apache Avro Ruby library does not support logical types ([AVRO-1695](https://issues.apache.org/jira/browse/AVRO-1695)).
436
- That feature is in progress and will hopefully be merged soon.
437
-
438
- Avromatic supports logical types as implemented in the [pull request](https://github.com/apache/avro/pull/116) referenced in AVRO-1695.
439
-
440
- Until that change is included in the official library, you can
441
- use the [avro-patches gem](https://github.com/salsify/avro-patches) which includes
442
- the changes from the above pull request.
443
-
444
- To use this gem, reference it in your Gemfile instead of `avro`:
445
-
446
- ```ruby
447
- gem 'avro-patches'
448
- ````
449
-
450
433
  ### RSpec Support
451
434
 
452
435
  This gem also includes an `"avromatic/rspec"` file that can be required to support
data/avromatic.gemspec CHANGED
@@ -20,21 +20,22 @@ Gem::Specification.new do |spec|
20
20
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
21
  spec.require_paths = ['lib']
22
22
 
23
- spec.required_ruby_version = '>= 2.4'
23
+ spec.required_ruby_version = '>= 2.5'
24
24
 
25
- spec.add_runtime_dependency 'activemodel', '>= 5.0', '< 6.1'
26
- spec.add_runtime_dependency 'activesupport', '>= 5.0', '< 6.1'
27
- spec.add_runtime_dependency 'avro', '>= 1.7.7', '< 1.11'
28
- spec.add_runtime_dependency 'avro_schema_registry-client', '>= 0.3.0'
25
+ spec.add_runtime_dependency 'activemodel', '>= 5.2', '< 6.2'
26
+ spec.add_runtime_dependency 'activesupport', '>= 5.2', '< 6.2'
27
+ spec.add_runtime_dependency 'avro', '>= 1.9.0', '< 1.11'
28
+ spec.add_runtime_dependency 'avro_schema_registry-client', '>= 0.4.0'
29
29
  spec.add_runtime_dependency 'avro_turf'
30
30
  spec.add_runtime_dependency 'ice_nine'
31
31
 
32
32
  spec.add_development_dependency 'appraisal'
33
33
  spec.add_development_dependency 'avro-builder', '>= 0.12.0'
34
- spec.add_development_dependency 'bundler', '>= 1.11'
34
+ spec.add_development_dependency 'bundler', '~> 2.0'
35
35
  spec.add_development_dependency 'overcommit', '0.35.0'
36
- spec.add_development_dependency 'rake', '~> 10.0'
37
- spec.add_development_dependency 'rspec', '~> 3.0'
36
+ spec.add_development_dependency 'rake', '~> 13.0'
37
+ spec.add_development_dependency 'rspec', '~> 3.8'
38
+ spec.add_development_dependency 'rspec_junit_formatter'
38
39
  spec.add_development_dependency 'salsify_rubocop', '~> 0.52.1.1'
39
40
  spec.add_development_dependency 'simplecov'
40
41
  spec.add_development_dependency 'webmock'
data/bin/console CHANGED
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
- require "bundler/setup"
4
- require "avromatic"
4
+ require 'bundler/setup'
5
+ require 'avromatic'
5
6
 
6
7
  # You can add fixtures and/or initialization code here to make experimenting
7
8
  # with your gem easier. You can also use a different console, if you like.
@@ -10,5 +11,5 @@ require "avromatic"
10
11
  # require "pry"
11
12
  # Pry.start
12
13
 
13
- require "irb"
14
+ require 'irb'
14
15
  IRB.start
@@ -0,0 +1,9 @@
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: "../"
@@ -2,8 +2,8 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "avro", "1.8.2"
6
- gem "activesupport", "~> 5.2.0"
7
- gem "activemodel", "~> 5.2.0"
5
+ gem "avro", "1.9.2"
6
+ gem "activesupport", "~> 6.1.0"
7
+ gem "activemodel", "~> 6.1.0"
8
8
 
9
9
  gemspec path: "../"
data/lib/avromatic.rb CHANGED
@@ -8,7 +8,6 @@ require 'avromatic/model'
8
8
  require 'avromatic/model_registry'
9
9
  require 'avromatic/messaging'
10
10
  require 'active_support/core_ext/string/inflections'
11
- require 'avromatic/patches'
12
11
 
13
12
  module Avromatic
14
13
  class << self
@@ -33,10 +32,6 @@ module Avromatic
33
32
  eager_load_models!
34
33
  end
35
34
 
36
- def self.use_encoding_providers?
37
- use_custom_datum_writer && defined?(Avromatic::Patches::SchemaValidatorPatch)
38
- end
39
-
40
35
  def self.build_schema_registry
41
36
  raise 'Avromatic must be configured with a registry_url' unless registry_url
42
37
  if use_schema_fingerprint_lookup
data/lib/avromatic/io.rb CHANGED
@@ -1,11 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Avromatic
4
- module IO
5
- UNION_MEMBER_INDEX = '__avromatic_member_index'
6
- ENCODING_PROVIDER = '__avromatic_encoding_provider'
7
- end
8
- end
9
-
10
3
  require 'avromatic/io/datum_reader'
11
4
  require 'avromatic/io/datum_writer'
5
+ require 'avromatic/io/union_datum'
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # rubocop:disable Style/WhenThen
4
3
  module Avromatic
5
4
  module IO
6
5
  # Subclass DatumReader to include additional information about the union
@@ -8,81 +7,32 @@ module Avromatic
8
7
  # branch 'salsify-master' with the tag 'v1.9.0.3'
9
8
  class DatumReader < Avro::IO::DatumReader
10
9
 
11
- UNION_MEMBER_INDEX = Avromatic::IO::UNION_MEMBER_INDEX
12
-
13
- def read_data(writers_schema, readers_schema, decoder, initial_record = nil)
14
- # schema matching
15
- unless self.class.match_schemas(writers_schema, readers_schema)
16
- raise Avro::IO::SchemaMatchException.new(writers_schema, readers_schema)
17
- end
18
-
10
+ def read_data(writers_schema, readers_schema, decoder)
19
11
  # schema resolution: reader's schema is a union, writer's schema is not
20
- if writers_schema.type_sym != :union && readers_schema.type_sym == :union
21
- rs_index = readers_schema.schemas.find_index do |s|
22
- self.class.match_schemas(writers_schema, s)
23
- end
12
+ return super unless writers_schema.type_sym != :union && readers_schema.type_sym == :union
24
13
 
25
- optional = readers_schema.schemas.first.type_sym == :null
26
- union_info = if readers_schema.schemas.size == 2 && optional
27
- # Avromatic does not treat the union of null and 1 other type as a union
28
- {}
29
- elsif optional
30
- # Avromatic does not treat the null of an optional field as part of the union
31
- { UNION_MEMBER_INDEX => rs_index - 1 }
32
- else
33
- { UNION_MEMBER_INDEX => rs_index }
34
- end
35
-
36
- return read_data(writers_schema, readers_schema.schemas[rs_index], decoder, union_info) if rs_index
37
- raise Avro::IO::SchemaMatchException.new(writers_schema, readers_schema)
14
+ rs_index = readers_schema.schemas.find_index do |s|
15
+ self.class.match_schemas(writers_schema, s)
38
16
  end
39
17
 
40
- # function dispatch for reading data based on type of writer's schema
41
- datum = case writers_schema.type_sym
42
- when :null; decoder.read_null
43
- when :boolean; decoder.read_boolean
44
- when :string; decoder.read_string
45
- when :int; decoder.read_int
46
- when :long; decoder.read_long
47
- when :float; decoder.read_float
48
- when :double; decoder.read_double
49
- when :bytes; decoder.read_bytes
50
- when :fixed; read_fixed(writers_schema, readers_schema, decoder)
51
- when :enum; read_enum(writers_schema, readers_schema, decoder)
52
- when :array; read_array(writers_schema, readers_schema, decoder)
53
- when :map; read_map(writers_schema, readers_schema, decoder)
54
- when :union; read_union(writers_schema, readers_schema, decoder)
55
- when :record, :error, :request; read_record(writers_schema, readers_schema, decoder, initial_record || {})
56
- else
57
- raise Avro::AvroError.new("Cannot read unknown schema type: #{writers_schema.type}")
58
- end
18
+ raise Avro::IO::SchemaMatchException.new(writers_schema, readers_schema) unless rs_index
59
19
 
60
- # Allow this code to be used with an official Avro release or the
61
- # avro-patches gem that includes logical_type support.
62
- if readers_schema.respond_to?(:logical_type)
63
- readers_schema.type_adapter.decode(datum)
64
- else
65
- datum
66
- end
67
- end
20
+ datum = read_data(writers_schema, readers_schema.schemas[rs_index], decoder)
21
+ optional = readers_schema.schemas.first.type_sym == :null
68
22
 
69
- # Override to specify an initial record that may contain union index
70
- def read_record(writers_schema, readers_schema, decoder, initial_record = {})
71
- readers_fields_hash = readers_schema.fields_hash
72
- read_record = Avromatic.use_custom_datum_reader ? initial_record : {}
73
- writers_schema.fields.each do |field|
74
- readers_field = readers_fields_hash[field.name]
75
- if readers_field
76
- field_val = read_data(field.type, readers_field.type, decoder)
77
- read_record[field.name] = field_val
78
- else
79
- skip_data(field.type, decoder)
80
- end
23
+ if readers_schema.schemas.size == 2 && optional
24
+ # Avromatic does not treat the union of null and 1 other type as a union
25
+ datum
26
+ elsif datum.nil?
27
+ # Avromatic does not treat the null of an optional field as part of the union
28
+ nil
29
+ else
30
+ # Avromatic does not treat the null of an optional field as part of the union so
31
+ # adjust the member index accordingly
32
+ member_index = optional ? rs_index - 1 : rs_index
33
+ Avromatic::IO::UnionDatum.new(member_index, datum)
81
34
  end
82
-
83
- read_record
84
35
  end
85
36
  end
86
37
  end
87
38
  end
88
- # rubocop:enable Style/WhenThen