avromatic 2.2.5 → 3.0.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bdd13d41971f1b38c3b1a9496ec698a14122b69ed5442b4cca7ac7e7d099c6b2
4
- data.tar.gz: af4fbf880781abeffc7e0807491ca43a0fdabdff5714c60bfe46b365caa355a5
3
+ metadata.gz: d4938e400e426cf06497e5819b1f92c9c3f12920ada5ed999a1a826bd19c7efb
4
+ data.tar.gz: e37322f05ec5adaff55e28bc8e15a2e2164dc3d8575fb8ed0dad6e5b283fa440
5
5
  SHA512:
6
- metadata.gz: 856111e8a1f7e5ec99cbbe20877095ff630182f27265617e7746437402e4146628c5ae2812f85a9f0cd5c234b748bd1b1c8abee8fddb92e21bc137537074a0d4
7
- data.tar.gz: 275aa990b3a84aaa679141955a93800cb4764fc0bbf44a290cbaebd4d54e1cd443f2a3943431b2781bcc6165df06861c7a0d6f9c6bf4c754732737518935d896
6
+ metadata.gz: 258766a91f94e209f18e0f2060bb2590d606bb973b93bd702a2acc45535d2591e7688b5d14695c004621a5eddf8d328528518447ccf26521c10d2fb3821dfdb6
7
+ data.tar.gz: fd1aea43406300f106aba81a9be6212e50d4e6bab68b4a3a25bb5f7aafaa01400bb1712bfe7a9a4206a6dc8fa7bf31491988bd43a69755b2582f6c44d26603ba
@@ -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,30 @@
1
1
  # avromatic changelog
2
2
 
3
+ ## 3.0.1
4
+ - Raise an error when registering a nested model that has already been auto-generated.
5
+ This avoids hard to troubleshoot coercion errors when instantiating models and fixes
6
+ a regression introduced in Avromatic 2.2.2.
7
+
8
+ ## 3.0.0
9
+ - Drop support for Ruby 2.4.
10
+ - Add support for Ruby 3.0.
11
+ - Drop support for Avro < 1.9.
12
+ - Drop support for Rails < 5.2.
13
+ - Fix decoding of unions containing false boolean values.
14
+
15
+ ## v2.4.0
16
+ - Ignore the `validate` argument and always validate during serialization. This
17
+ argument will be removed in Avromatic 3.0.
18
+ - Optimize model validation during serialization.
19
+ - Don't cache immutable model validation results or serialized Avro attributes if a model has mutable children.
20
+
21
+ ## v2.3.0
22
+ - Add support for Rails 6.1.
23
+ - Optimize nested model serialization.
24
+
25
+ ## v2.2.6
26
+ - Optimize memory usage when serializing models.
27
+
3
28
  ## v2.2.5
4
29
  - Optimize memory usage when serializing, deserializing and instantiating models.
5
30
 
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.
@@ -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
- nil
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
@@ -5,41 +5,29 @@ module Avromatic
5
5
  # Subclass DatumWriter to use additional information about union member
6
6
  # index.
7
7
  class DatumWriter < Avro::IO::DatumWriter
8
- class << self
9
- attr_accessor :optimize
10
- end
11
-
12
8
  def write_union(writers_schema, datum, encoder)
13
9
  optional = writers_schema.schemas.first.type_sym == :null
14
- if datum.is_a?(Hash) && datum.key?(Avromatic::IO::UNION_MEMBER_INDEX)
15
- index_of_schema = datum[Avromatic::IO::UNION_MEMBER_INDEX]
10
+ if datum.is_a?(Avromatic::IO::UnionDatum)
11
+ index_of_schema = datum.member_index
16
12
  # Avromatic does not treat the null of an optional field as part of the union
17
13
  index_of_schema += 1 if optional
14
+ datum = datum.datum
18
15
  elsif optional && writers_schema.schemas.size == 2
19
16
  # Optimize for the common case of a union that's just an optional field
20
17
  index_of_schema = datum.nil? ? 0 : 1
21
- elsif self.class.optimize && optional && datum.nil?
22
- index_of_schema = 0
23
18
  else
24
19
  index_of_schema = writers_schema.schemas.find_index do |schema|
25
20
  Avro::Schema.validate(schema, datum)
26
21
  end
27
22
  end
23
+
28
24
  unless index_of_schema
29
25
  raise Avro::IO::AvroTypeError.new(writers_schema, datum)
30
26
  end
27
+
31
28
  encoder.write_long(index_of_schema)
32
29
  write_data(writers_schema.schemas[index_of_schema], datum, encoder)
33
30
  end
34
-
35
- def write_record(writers_schema, datum, encoder)
36
- if datum.is_a?(Hash) && datum.key?(Avromatic::IO::ENCODING_PROVIDER)
37
- # This is only used for recursive serialization so validation has already been done
38
- encoder.write(datum[Avromatic::IO::ENCODING_PROVIDER].avro_raw_value(validate: false))
39
- else
40
- super
41
- end
42
- end
43
31
  end
44
32
  end
45
33
  end