deimos-ruby 1.4.0.pre.beta7 → 1.5.0.pre.beta2

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.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/CHANGELOG.md +13 -0
  4. data/Gemfile.lock +140 -58
  5. data/README.md +38 -11
  6. data/Rakefile +2 -2
  7. data/deimos-ruby.gemspec +3 -2
  8. data/docs/CONFIGURATION.md +1 -0
  9. data/docs/DATABASE_BACKEND.md +1 -1
  10. data/lib/deimos/active_record_consumer.rb +11 -12
  11. data/lib/deimos/active_record_producer.rb +2 -2
  12. data/lib/deimos/backends/base.rb +32 -0
  13. data/lib/deimos/backends/db.rb +6 -1
  14. data/lib/deimos/backends/kafka.rb +1 -1
  15. data/lib/deimos/backends/kafka_async.rb +1 -1
  16. data/lib/deimos/backends/test.rb +20 -0
  17. data/lib/deimos/base_consumer.rb +7 -7
  18. data/lib/deimos/batch_consumer.rb +0 -1
  19. data/lib/deimos/config/configuration.rb +4 -0
  20. data/lib/deimos/consumer.rb +0 -2
  21. data/lib/deimos/kafka_source.rb +1 -1
  22. data/lib/deimos/kafka_topic_info.rb +1 -1
  23. data/lib/deimos/message.rb +7 -7
  24. data/lib/deimos/producer.rb +10 -12
  25. data/lib/deimos/schema_backends/avro_base.rb +108 -0
  26. data/lib/deimos/schema_backends/avro_local.rb +30 -0
  27. data/lib/deimos/{schema_coercer.rb → schema_backends/avro_schema_coercer.rb} +39 -51
  28. data/lib/deimos/schema_backends/avro_schema_registry.rb +34 -0
  29. data/lib/deimos/schema_backends/avro_validation.rb +21 -0
  30. data/lib/deimos/schema_backends/base.rb +130 -0
  31. data/lib/deimos/schema_backends/mock.rb +42 -0
  32. data/lib/deimos/test_helpers.rb +42 -168
  33. data/lib/deimos/utils/db_producer.rb +5 -0
  34. data/lib/deimos/version.rb +1 -1
  35. data/lib/deimos.rb +22 -6
  36. data/lib/tasks/deimos.rake +1 -1
  37. data/spec/active_record_consumer_spec.rb +7 -0
  38. data/spec/{publish_backend_spec.rb → backends/base_spec.rb} +1 -1
  39. data/spec/backends/db_spec.rb +5 -0
  40. data/spec/batch_consumer_spec.rb +0 -8
  41. data/spec/config/configuration_spec.rb +20 -20
  42. data/spec/consumer_spec.rb +0 -1
  43. data/spec/deimos_spec.rb +0 -4
  44. data/spec/kafka_source_spec.rb +8 -0
  45. data/spec/producer_spec.rb +23 -37
  46. data/spec/rake_spec.rb +19 -0
  47. data/spec/schema_backends/avro_base_shared.rb +174 -0
  48. data/spec/schema_backends/avro_local_spec.rb +32 -0
  49. data/spec/schema_backends/avro_schema_registry_spec.rb +32 -0
  50. data/spec/schema_backends/avro_validation_spec.rb +24 -0
  51. data/spec/schema_backends/base_spec.rb +29 -0
  52. data/spec/spec_helper.rb +6 -0
  53. data/spec/utils/db_producer_spec.rb +10 -0
  54. metadata +56 -33
  55. data/lib/deimos/avro_data_coder.rb +0 -89
  56. data/lib/deimos/avro_data_decoder.rb +0 -36
  57. data/lib/deimos/avro_data_encoder.rb +0 -51
  58. data/lib/deimos/monkey_patches/schema_store.rb +0 -19
  59. data/lib/deimos/publish_backend.rb +0 -30
  60. data/spec/avro_data_decoder_spec.rb +0 -18
  61. data/spec/avro_data_encoder_spec.rb +0 -37
  62. data/spec/updateable_schema_store_spec.rb +0 -36
@@ -1,89 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Deimos
4
- # Base class for the encoder / decoder classes.
5
- class AvroDataCoder
6
- attr_accessor :schema, :namespace, :config, :schema_store
7
-
8
- # @param schema [String]
9
- # @param namespace [String]
10
- # @param schema_store [AvroTurf::SchemaStore]
11
- def initialize(schema:, namespace:, schema_store: nil)
12
- @schema = schema
13
- @namespace = namespace
14
- @schema_store = schema_store ||
15
- AvroTurf::SchemaStore.new(path: Deimos.config.schema.path)
16
- end
17
-
18
- # @param schema [String]
19
- # @return [Avro::Schema]
20
- def avro_schema(schema=nil)
21
- schema ||= @schema
22
- @schema_store.find(schema, @namespace)
23
- end
24
-
25
- private
26
-
27
- # @return [AvroTurf]
28
- def avro_turf
29
- @avro_turf ||= AvroTurf.new(
30
- schemas_path: Deimos.config.schema.path,
31
- schema_store: @schema_store
32
- )
33
- @avro_turf
34
- end
35
-
36
- # @return [AvroTurf::Messaging]
37
- def avro_turf_messaging
38
- @avro_turf_messaging ||= AvroTurf::Messaging.new(
39
- schema_store: @schema_store,
40
- registry_url: Deimos.config.schema.registry_url,
41
- schemas_path: Deimos.config.schema.path,
42
- namespace: @namespace
43
- )
44
- end
45
-
46
- # Generate a key schema from the given value schema and key ID. This
47
- # is used when encoding or decoding keys from an existing value schema.
48
- # @param key_id [Symbol]
49
- # @return [Hash]
50
- def _generate_key_schema(key_id)
51
- return @key_schema if @key_schema
52
-
53
- value_schema = @schema_store.find(@schema, @namespace)
54
- key_field = value_schema.fields.find { |f| f.name == key_id.to_s }
55
- name = _key_schema_name(@schema)
56
- @key_schema = {
57
- 'type' => 'record',
58
- 'name' => name,
59
- 'namespace' => @namespace,
60
- 'doc' => "Key for #{@namespace}.#{@schema}",
61
- 'fields' => [
62
- {
63
- 'name' => key_id,
64
- 'type' => key_field.type.type_sym.to_s
65
- }
66
- ]
67
- }
68
- @schema_store.add_schema(@key_schema)
69
- @key_schema
70
- end
71
-
72
- # @param value_schema [Hash]
73
- # @return [String]
74
- def _field_name_from_schema(value_schema)
75
- raise "Schema #{@schema} not found!" if value_schema.nil?
76
- if value_schema['fields'].nil? || value_schema['fields'].empty?
77
- raise "Schema #{@schema} has no fields!"
78
- end
79
-
80
- value_schema['fields'][0]['name']
81
- end
82
-
83
- # @param schema [String]
84
- # @return [String]
85
- def _key_schema_name(schema)
86
- "#{schema.gsub('-value', '')}_key"
87
- end
88
- end
89
- end
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'avro_turf/messaging'
4
- require 'deimos/avro_data_coder'
5
-
6
- module Deimos
7
- # Service Object to decode avro messages
8
- class AvroDataDecoder < AvroDataCoder
9
- # Decode some data.
10
- # @param payload [Hash|String]
11
- # @param schema [String]
12
- # @return [Hash]
13
- def decode(payload, schema: nil)
14
- schema ||= @schema
15
- avro_turf_messaging.decode(payload, schema_name: schema)
16
- end
17
-
18
- # Decode against a local schema.
19
- # @param payload [Hash]
20
- # @param schema [String]
21
- # @return [Hash]
22
- def decode_local(payload, schema: nil)
23
- schema ||= @schema
24
- avro_turf.decode(payload, schema_name: schema, namespace: @namespace)
25
- end
26
-
27
- # @param payload [String] the encoded key.
28
- # @param key_id [String|Symbol]
29
- # @return [Object] the decoded key (int/long/string).
30
- def decode_key(payload, key_id)
31
- key_schema = _generate_key_schema(key_id)
32
- field_name = _field_name_from_schema(key_schema)
33
- decode(payload, schema: key_schema['name'])[field_name]
34
- end
35
- end
36
- end
@@ -1,51 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'avro_turf/messaging'
4
- require 'deimos/avro_data_coder'
5
-
6
- module Deimos
7
- # Service Object to decode Avro messages.
8
- class AvroDataEncoder < AvroDataCoder
9
- # @param payload [Hash]
10
- # @param schema [String]
11
- # @return [String]
12
- def encode_local(payload, schema: nil)
13
- schema ||= @schema
14
- Avro::SchemaValidator.validate!(avro_schema(schema), payload,
15
- recursive: true,
16
- fail_on_extra_fields: true)
17
- avro_turf.encode(payload, schema_name: schema, namespace: @namespace)
18
- rescue Avro::IO::AvroTypeError
19
- # throw a more detailed error
20
- value_schema = @schema_store.find(schema, @namespace)
21
- Avro::SchemaValidator.validate!(value_schema, payload)
22
- end
23
-
24
- # @param payload [Hash]
25
- # @param schema [String]
26
- # @param topic [String]
27
- # @return [String]
28
- def encode(payload, schema: nil, topic: nil)
29
- schema ||= @schema
30
- Avro::SchemaValidator.validate!(avro_schema(schema), payload,
31
- recursive: true,
32
- fail_on_extra_fields: true)
33
- avro_turf_messaging.encode(payload, schema_name: schema, subject: topic)
34
- rescue Avro::IO::AvroTypeError
35
- # throw a more detailed error
36
- schema = @schema_store.find(@schema, @namespace)
37
- Avro::SchemaValidator.validate!(schema, payload)
38
- end
39
-
40
- # @param key_id [Symbol|String]
41
- # @param key [Object]
42
- # @param topic [String]
43
- # @return [String] the encoded key.
44
- def encode_key(key_id, key, topic=nil)
45
- key_schema = _generate_key_schema(key_id)
46
- field_name = _field_name_from_schema(key_schema)
47
- payload = { field_name => key }
48
- encode(payload, schema: key_schema['name'], topic: topic)
49
- end
50
- end
51
- end
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'avro_turf/schema_store'
4
-
5
- # Allows us to add in-memory schemas to the schema store in
6
- # addition to the ones stored in the file system.
7
- class AvroTurf::SchemaStore
8
- attr_accessor :schemas
9
-
10
- # @param schema_hash [Hash]
11
- def add_schema(schema_hash)
12
- name = schema_hash['name']
13
- namespace = schema_hash['namespace']
14
- full_name = Avro::Name.make_fullname(name, namespace)
15
- return if @schemas.key?(full_name)
16
-
17
- Avro::Schema.real_parse(schema_hash, @schemas)
18
- end
19
- end
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Deimos
4
- # Abstract class for all publish backends.
5
- class PublishBackend
6
- class << self
7
- # @param producer_class [Class < Deimos::Producer]
8
- # @param messages [Array<Deimos::Message>]
9
- def publish(producer_class:, messages:)
10
- Deimos.config.logger.info(
11
- message: 'Publishing messages',
12
- topic: producer_class.topic,
13
- payloads: messages.map do |message|
14
- {
15
- payload: message.payload,
16
- key: message.key
17
- }
18
- end
19
- )
20
- execute(producer_class: producer_class, messages: messages)
21
- end
22
-
23
- # @param producer_class [Class < Deimos::Producer]
24
- # @param messages [Array<Deimos::Message>]
25
- def execute(producer_class:, messages:)
26
- raise NotImplementedError
27
- end
28
- end
29
- end
30
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe Deimos::AvroDataDecoder do
4
-
5
- let(:decoder) do
6
- decoder = described_class.new(schema: 'MySchema',
7
- namespace: 'com.my-namespace')
8
- allow(decoder).to(receive(:decode)) { |payload| payload }
9
- decoder
10
- end
11
-
12
- it 'should decode a key' do
13
- # reset stub from TestHelpers
14
- allow(described_class).to receive(:new).and_call_original
15
- expect(decoder.decode_key({ 'test_id' => '123' }, 'test_id')).to eq('123')
16
- end
17
-
18
- end
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'avro_turf/messaging'
4
-
5
- describe Deimos::AvroDataEncoder do
6
-
7
- let(:encoder) do
8
- encoder = described_class.new(schema: 'MySchema',
9
- namespace: 'com.my-namespace')
10
- allow(encoder).to(receive(:encode)) { |payload| payload }
11
- encoder
12
- end
13
-
14
- specify 'generate_key_schema' do
15
- expect_any_instance_of(AvroTurf::SchemaStore).
16
- to receive(:add_schema).with(
17
- 'type' => 'record',
18
- 'name' => 'MySchema_key',
19
- 'namespace' => 'com.my-namespace',
20
- 'doc' => 'Key for com.my-namespace.MySchema',
21
- 'fields' => [
22
- {
23
- 'name' => 'test_id',
24
- 'type' => 'string'
25
- }
26
- ]
27
- )
28
- encoder.send(:_generate_key_schema, 'test_id')
29
- end
30
-
31
- it 'should encode a key' do
32
- # reset stub from TestHelpers
33
- allow(described_class).to receive(:new).and_call_original
34
- expect(encoder.encode_key('test_id', '123')).to eq('test_id' => '123')
35
- end
36
-
37
- end
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- describe AvroTurf::SchemaStore do
4
-
5
- it 'should add an in-memory schema' do
6
- schema_store = described_class.new(path: Deimos.config.schema.path)
7
- schema_store.load_schemas!
8
- found_schema = schema_store.find('MySchema', 'com.my-namespace').as_json
9
- expect(found_schema['name']).to eq('MySchema')
10
- expect(found_schema['namespace']).to eq('com.my-namespace')
11
- expect(found_schema['fields'].size).to eq(2)
12
- expect(found_schema['fields'][0]['type']['type_sym']).to eq('string')
13
- expect(found_schema['fields'][0]['name']).to eq('test_id')
14
- new_schema = {
15
- 'namespace' => 'com.my-namespace',
16
- 'name' => 'MyNewSchema',
17
- 'type' => 'record',
18
- 'doc' => 'Test schema',
19
- 'fields' => [
20
- {
21
- 'name' => 'my_id',
22
- 'type' => 'int',
23
- 'doc' => 'test int'
24
- }
25
- ]
26
- }
27
- schema_store.add_schema(new_schema)
28
- found_schema = schema_store.find('MyNewSchema', 'com.my-namespace').
29
- as_json
30
- expect(found_schema['name']).to eq('MyNewSchema')
31
- expect(found_schema['namespace']).to eq('com.my-namespace')
32
- expect(found_schema['fields'].size).to eq(1)
33
- expect(found_schema['fields'][0]['type']['type_sym']).to eq('int')
34
- expect(found_schema['fields'][0]['name']).to eq('my_id')
35
- end
36
- end