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

Sign up to get free protection for your applications and to get access to all the features.
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