avromatic 2.2.5 → 3.0.1

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: 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