nulogy_message_bus_producer 3.2.1 → 3.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +82 -22
- data/Rakefile +2 -4
- data/db/migrate/20200611150212_create_public_subscriptions_and_events_tables.rb +2 -2
- data/lib/nulogy_message_bus_producer.rb +15 -8
- data/lib/nulogy_message_bus_producer/base_subscription.rb +1 -1
- data/lib/nulogy_message_bus_producer/config.rb +25 -1
- data/lib/nulogy_message_bus_producer/configuration/query_parser.rb +71 -0
- data/lib/nulogy_message_bus_producer/self_serve_subscription.rb +18 -0
- data/lib/nulogy_message_bus_producer/subscriptions/configured_subscription.rb +14 -0
- data/lib/nulogy_message_bus_producer/subscriptions/finder.rb +40 -0
- data/lib/nulogy_message_bus_producer/subscriptions/postgres_transport.rb +13 -6
- data/lib/nulogy_message_bus_producer/subscriptions/query_validator.rb +47 -0
- data/lib/nulogy_message_bus_producer/subscriptions/risky_subscription_blocker.rb +0 -5
- data/lib/nulogy_message_bus_producer/subscriptions/valid_for_schema_validator.rb +14 -0
- data/lib/nulogy_message_bus_producer/version.rb +1 -1
- data/spec/dummy/Rakefile +1 -1
- data/spec/dummy/app/mailers/application_mailer.rb +2 -2
- data/spec/dummy/bin/bundle +2 -2
- data/spec/dummy/bin/rails +3 -3
- data/spec/dummy/bin/rake +2 -2
- data/spec/dummy/bin/setup +14 -16
- data/spec/dummy/bin/update +10 -10
- data/spec/dummy/bin/yarn +13 -7
- data/spec/dummy/config.ru +2 -1
- data/spec/dummy/config/application.rb +11 -6
- data/spec/dummy/config/boot.rb +2 -4
- data/spec/dummy/config/cable.yml +2 -2
- data/spec/dummy/config/database.yml +2 -2
- data/spec/dummy/config/environment.rb +1 -1
- data/spec/dummy/config/environments/development.rb +29 -7
- data/spec/dummy/config/environments/production.rb +50 -20
- data/spec/dummy/config/environments/test.rb +25 -8
- data/spec/dummy/config/initializers/assets.rb +2 -2
- data/spec/dummy/config/initializers/backtrace_silencers.rb +4 -3
- data/spec/dummy/config/initializers/content_security_policy.rb +30 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +3 -1
- data/spec/dummy/config/initializers/new_framework_defaults_6_1.rb +67 -0
- data/spec/dummy/config/initializers/permissions_policy.rb +11 -0
- data/spec/dummy/config/locales/en.yml +1 -1
- data/spec/dummy/config/puma.rb +3 -3
- data/spec/dummy/config/spring.rb +2 -2
- data/spec/dummy/config/storage.yml +34 -0
- data/spec/dummy/db/schema.rb +0 -2
- data/spec/dummy/log/development.log +317 -0
- data/spec/dummy/log/test.log +13164 -0
- data/spec/integration/lib/nulogy_message_bus_producer/config_spec.rb +37 -0
- data/spec/integration/lib/nulogy_message_bus_producer/repopulate_replication_slots_spec.rb +6 -7
- data/spec/integration/lib/nulogy_message_bus_producer/subscription_spec.rb +3 -57
- data/spec/integration/lib/nulogy_message_bus_producer/subscriptions/finder_spec.rb +54 -0
- data/spec/integration/lib/nulogy_message_bus_producer/subscriptions/no_variables_spec.rb +1 -1
- data/spec/integration/lib/nulogy_message_bus_producer/subscriptions/postgres_transport_spec.rb +100 -54
- data/spec/integration/lib/nulogy_message_bus_producer/{subscriber_graphql_schema_validator_spec.rb → subscriptions/query_validator_spec.rb} +3 -3
- data/spec/integration/lib/nulogy_message_bus_producer/subscriptions/risky_subscription_blocker_spec.rb +0 -16
- data/spec/integration_spec_helper.rb +0 -6
- data/spec/nulogy_message_bus_producer/configuration/query_parser_spec.rb +58 -0
- data/spec/nulogy_message_bus_producer/subscriptions/subscription_spec.rb +9 -0
- data/spec/spec_helper.rb +26 -1
- data/spec/support/kafka.rb +9 -10
- data/spec/support/kafka_connect.rb +1 -1
- data/spec/support/shared_examples/subscription_validations.rb +77 -0
- data/spec/support/skip.rb +9 -0
- data/spec/support/sql_helpers.rb +1 -1
- data/spec/support/subscription_helpers.rb +22 -4
- data/spec/support/test_graphql_schema.rb +6 -2
- metadata +131 -79
- data/lib/nulogy_message_bus_producer/subscriber_graphql_schema_validator.rb +0 -45
- data/lib/nulogy_message_bus_producer/subscription.rb +0 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 42a5548fe112238674907a4b18853f42dcabbda48fb49dd711b824850b468c09
|
4
|
+
data.tar.gz: 7a33a695535255230f8ac46c6ddc75a0a343d8936d59f4b72e5d020b3b11b25a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: acf3750d5d987a1ecbec10258ea543095bd65b5a9e878eb7c73cc1e893a12e4ca14d13d3f3de0af97cc6796877f3995c11c9f99675f2b7437e4b91c0903f7de2
|
7
|
+
data.tar.gz: bc421953022e2682d89388d5b3ee02b4ee4194d9eba044b8b6ead775ebd166faee40927b2abe393904d26bcaa861eceae464c407a85541f1de5750227f6932e3
|
data/README.md
CHANGED
@@ -1,39 +1,93 @@
|
|
1
1
|
# Nulogy Message Bus Producer
|
2
2
|
|
3
|
-
|
3
|
+
[![Ruby Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://github.com/testdouble/standard)
|
4
|
+
|
5
|
+
This engine contains the classes and validations for producing messages to the Message Bus.
|
4
6
|
|
5
7
|
## Installation
|
6
8
|
|
7
|
-
1. Add the gem to your Gemfile `gem "nulogy_message_bus_producer"`
|
8
|
-
2. Install the
|
9
|
+
1. Add the gem to your Gemfile: `gem "nulogy_message_bus_producer"`
|
10
|
+
2. Install the migrations: `rake railties:install:migrations`
|
11
|
+
3. Use the [Nulogy GraphQL API](https://github.com/nulogy/nulogy_graphql_api)'s schema specs to [ensure schema changes are safe](https://github.com/nulogy/nulogy_graphql_api#schema-generation)
|
9
12
|
|
10
13
|
## Usage
|
11
14
|
|
12
|
-
|
15
|
+
Subscriptions should inherit from `NulogyMessageBusProducer::BaseSubscription`.
|
16
|
+
|
17
|
+
### Subscriptions
|
18
|
+
|
19
|
+
Subscriptions are created by consumers to subscribe to certain events that the producer exposes.
|
20
|
+
|
21
|
+
When an event is fired/triggered, subscriptions are used to generate events into the
|
22
|
+
`NulogyMessageBusProducer.subscription_events_table_name` table.
|
23
|
+
|
24
|
+
Debezium then reads this table from the PG replication log and pushes them into Kafka.
|
13
25
|
|
14
|
-
|
15
|
-
should be set up.
|
26
|
+
There are two ways to create subscriptions:
|
16
27
|
|
17
|
-
|
18
|
-
|
28
|
+
#### Configured
|
29
|
+
|
30
|
+
Subscriptions provided by configuration in the producer app:
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
NulogyMessageBusProducer.configure do |c|
|
34
|
+
c.register_schema(schema: "ExampleDomain::Schema", key: "exampleDomain")
|
35
|
+
|
36
|
+
c.add_subscription!(
|
37
|
+
schema: "ExampleDomain::Schema",
|
38
|
+
query: <<~QUERY
|
39
|
+
subscription {
|
40
|
+
domainEvent(subscriptionId: "uuid", subscriptionGroupId: "uuid2", topicName: "consumer-inbox") {
|
41
|
+
domainObject {
|
42
|
+
field
|
43
|
+
}
|
44
|
+
}
|
45
|
+
}
|
46
|
+
QUERY
|
47
|
+
)
|
48
|
+
end
|
49
|
+
```
|
50
|
+
|
51
|
+
#### Self-Serve (soft-deprecated)
|
52
|
+
|
53
|
+
You create these subscriptions via the public GraphQL API. For testing, the [Insomnia](https://insomnia.rest/) client
|
54
|
+
is highly recommended.
|
55
|
+
|
56
|
+
```graphql
|
57
|
+
subscription {
|
58
|
+
workOrderUpdated(subscriptionId: "uuid", subscriptionGroupId: "uuid", topicName: "some-topic") {
|
59
|
+
workOrder {
|
60
|
+
id
|
61
|
+
code
|
62
|
+
}
|
63
|
+
}
|
64
|
+
}
|
65
|
+
```
|
66
|
+
|
67
|
+
These subscriptions are written to the `NulogyMessageBusProducer.subscriptions_table_name` table.
|
68
|
+
|
69
|
+
This style of subscriptions may be removed in a future release.
|
70
|
+
|
71
|
+
There is a [guide to migrate from Self-Serve to Configured](docs/self_serve_to_configured_subscriptions.md)
|
19
72
|
|
20
73
|
## Configuration
|
21
74
|
|
22
|
-
| Configuration | Default
|
23
|
-
|
24
|
-
| context_for_subscription | `->(_subscription) { {} }` | A lambda used to inject any GraphQL Context to be used when producing subscription events
|
25
|
-
| producing_events_fails_with | :raise | How the producer should handle errors when producing subscription events
|
26
|
-
| subscriptions_table_name | "message_bus_subscriptions" | The name of the table for the
|
27
|
-
| subscription_events_table_name | "message_bus_subscription_events" | The name of the table for the SubscriptionEvents model
|
75
|
+
| Configuration | Default | Description |
|
76
|
+
|--------------------------------|-----------------------------------|----------------------------------------------------------------------------------------------------|
|
77
|
+
| context_for_subscription | `->(_subscription) { {} }` | A lambda used to inject any GraphQL Context to be used when producing subscription events |
|
78
|
+
| producing_events_fails_with | :raise | How the producer should handle errors when producing subscription events |
|
79
|
+
| subscriptions_table_name | "message_bus_subscriptions" | The name of the table for the SelfServeSubscription model |
|
80
|
+
| subscription_events_table_name | "message_bus_subscription_events" | The name of the table for the SubscriptionEvents model |
|
81
|
+
| add_subscription! | [] (i.e. empty) | Add a subscription via configuration. It will supercede any configured via GraphQL for a given id. |
|
28
82
|
|
29
83
|
## Setup
|
30
84
|
|
31
85
|
You should configure the gem with an initializer. A recommended setup:
|
32
86
|
|
33
87
|
```ruby
|
34
|
-
# Table names are configurable
|
35
|
-
NulogyMessageBusProducer.subscriptions_table_name = :message_bus_subscriptions
|
36
|
-
NulogyMessageBusProducer.subscription_events_table_name = :message_bus_subscription_events
|
88
|
+
# (optional) Table names are configurable
|
89
|
+
# NulogyMessageBusProducer.subscriptions_table_name = :message_bus_subscriptions
|
90
|
+
# NulogyMessageBusProducer.subscription_events_table_name = :message_bus_subscription_events
|
37
91
|
|
38
92
|
# Register known schemas
|
39
93
|
NulogyMessageBusProducer.configure do |config|
|
@@ -79,11 +133,6 @@ module ExampleDomainPublicApi
|
|
79
133
|
class Schema < GraphQL::Schema
|
80
134
|
use NulogyMessageBusProducer::Subscriptions::PostgresTransport
|
81
135
|
|
82
|
-
# You must use the Interpreter, as it will be the new default.
|
83
|
-
# See more here: https://graphql-ruby.org/queries/interpreter
|
84
|
-
use GraphQL::Analysis::AST
|
85
|
-
use GraphQL::Execution::Interpreter
|
86
|
-
|
87
136
|
# This prevents subscriptions which contain arguments or expand lists form being registered.
|
88
137
|
# Expanding unbounded lists inside of an event may severely impact the performance of the system.
|
89
138
|
# Arguments are a source of variation that may not be appropriately tested.
|
@@ -223,3 +272,14 @@ docker-compose up
|
|
223
272
|
rake db:setup
|
224
273
|
rake
|
225
274
|
```
|
275
|
+
|
276
|
+
# Gem Releases
|
277
|
+
|
278
|
+
You must be listed as a gem owner [on rubygems](https://rubygems.org/gems/nulogy_message_bus_producer) to cut a release:
|
279
|
+
|
280
|
+
* Merge your changes to `master`
|
281
|
+
* Commit a version bump
|
282
|
+
* Update `lib/nulogy_message_bus_producer/version.rb`
|
283
|
+
* Run `bundle install`
|
284
|
+
* Update the CHANGELOG
|
285
|
+
* Run `bundle exec rake release`
|
data/Rakefile
CHANGED
@@ -13,11 +13,9 @@ require "rspec/core/rake_task"
|
|
13
13
|
|
14
14
|
RSpec::Core::RakeTask.new(:spec)
|
15
15
|
|
16
|
-
require "
|
16
|
+
require "standard/rake"
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
task default: [:spec, :rubocop]
|
18
|
+
task default: %i[spec standard]
|
21
19
|
|
22
20
|
require "rake/release"
|
23
21
|
|
@@ -5,7 +5,7 @@ class CreatePublicSubscriptionsAndEventsTables < ActiveRecord::Migration[5.2]
|
|
5
5
|
|
6
6
|
create_table NulogyMessageBusProducer.subscriptions_table_name, id: :uuid, default: nil do |t|
|
7
7
|
t.uuid :subscription_group_id, null: false
|
8
|
-
t.string :event_type, null: false, index: {
|
8
|
+
t.string :event_type, null: false, index: {name: "index_nulogy_mb_producer_subscriptions_on_event_type"}
|
9
9
|
t.string :topic_name, null: false
|
10
10
|
t.string :query, null: false
|
11
11
|
t.text :schema_key, null: false
|
@@ -19,7 +19,7 @@ class CreatePublicSubscriptionsAndEventsTables < ActiveRecord::Migration[5.2]
|
|
19
19
|
t.string :topic_name, null: false
|
20
20
|
t.uuid :tenant_id, null: false
|
21
21
|
t.json :event_json, null: false
|
22
|
-
t.column :created_at, :datetime, index: {
|
22
|
+
t.column :created_at, :datetime, index: {name: "index_nulogy_mb_producer_subscription_events_on_created_at"}
|
23
23
|
end
|
24
24
|
end
|
25
25
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
require "graphql"
|
2
|
+
require "pp"
|
2
3
|
|
3
4
|
require "nulogy_message_bus_producer/config"
|
5
|
+
require "nulogy_message_bus_producer/configuration/query_parser"
|
4
6
|
require "nulogy_message_bus_producer/version"
|
5
7
|
require "nulogy_message_bus_producer/engine"
|
6
8
|
|
@@ -14,11 +16,11 @@ module NulogyMessageBusProducer
|
|
14
16
|
end
|
15
17
|
|
16
18
|
def self.subscriptions_table_name=(table_name)
|
17
|
-
NulogyMessageBusProducer::
|
19
|
+
NulogyMessageBusProducer::SelfServeSubscription.table_name = table_name
|
18
20
|
end
|
19
21
|
|
20
22
|
def self.subscriptions_table_name
|
21
|
-
NulogyMessageBusProducer::
|
23
|
+
NulogyMessageBusProducer::SelfServeSubscription.table_name
|
22
24
|
end
|
23
25
|
|
24
26
|
def self.subscription_events_table_name=(table_name)
|
@@ -35,7 +37,7 @@ module NulogyMessageBusProducer
|
|
35
37
|
|
36
38
|
def self.trigger_event(schema, event_type, root_object)
|
37
39
|
schema_key = NulogyMessageBusProducer.resolve_schema_key(schema)
|
38
|
-
subscriptions =
|
40
|
+
subscriptions = Subscriptions::Finder.new(config).for_schema_event(schema_key, event_type)
|
39
41
|
|
40
42
|
subscriptions.each do |subscription|
|
41
43
|
args = {
|
@@ -65,7 +67,9 @@ module NulogyMessageBusProducer
|
|
65
67
|
end
|
66
68
|
|
67
69
|
def self.resolve_schema_key(schema)
|
68
|
-
|
70
|
+
schema_name = schema.respond_to?(:name) ? schema.name : schema
|
71
|
+
|
72
|
+
config.registered_schemas.invert.fetch(schema_name) do
|
69
73
|
raise KeyError, <<~MESSAGE
|
70
74
|
The schema registry did not contain an entry for the schema '#{schema.name}'.
|
71
75
|
|
@@ -80,7 +84,7 @@ module NulogyMessageBusProducer
|
|
80
84
|
def self.validate_existing!
|
81
85
|
return unless Db.exists? && Db.subscriptions_exist?
|
82
86
|
|
83
|
-
validator = NulogyMessageBusProducer::
|
87
|
+
validator = NulogyMessageBusProducer::Subscriptions::QueryValidator.new
|
84
88
|
|
85
89
|
return if validator.validate
|
86
90
|
|
@@ -136,10 +140,13 @@ end
|
|
136
140
|
|
137
141
|
require "nulogy_message_bus_producer/application_record"
|
138
142
|
require "nulogy_message_bus_producer/base_subscription"
|
139
|
-
require "nulogy_message_bus_producer/subscription"
|
140
143
|
require "nulogy_message_bus_producer/subscription_event"
|
141
144
|
require "nulogy_message_bus_producer/repopulate_replication_slots"
|
142
|
-
require "nulogy_message_bus_producer/
|
143
|
-
require "nulogy_message_bus_producer/subscriptions/postgres_transport"
|
145
|
+
require "nulogy_message_bus_producer/subscriptions/finder"
|
144
146
|
require "nulogy_message_bus_producer/subscriptions/no_variables"
|
147
|
+
require "nulogy_message_bus_producer/subscriptions/postgres_transport"
|
148
|
+
require "nulogy_message_bus_producer/subscriptions/query_validator"
|
149
|
+
require "nulogy_message_bus_producer/subscriptions/valid_for_schema_validator"
|
150
|
+
require "nulogy_message_bus_producer/subscriptions/configured_subscription"
|
151
|
+
require "nulogy_message_bus_producer/self_serve_subscription"
|
145
152
|
require "nulogy_message_bus_producer/subscriptions/risky_subscription_blocker"
|
@@ -2,7 +2,7 @@ module NulogyMessageBusProducer
|
|
2
2
|
# This base class contains the fields required to create a subscription.
|
3
3
|
# For example, for a subscription to a model called AggregateRoot:
|
4
4
|
#
|
5
|
-
# class AggregateRootCreated < NulogyMessageBusProducer::
|
5
|
+
# class AggregateRootCreated < NulogyMessageBusProducer::BaseSubscription
|
6
6
|
# field :aggregate_root, Domain::Public::Types::AggregateRootType, null: true
|
7
7
|
# end
|
8
8
|
class BaseSubscription < GraphQL::Schema::Subscription
|
@@ -1,14 +1,16 @@
|
|
1
1
|
module NulogyMessageBusProducer
|
2
2
|
# Configuration for the gem
|
3
|
-
# This is a private class, so do not use it directly. Use the methods on NulogyMessageBusProducer.
|
4
3
|
class Config
|
5
4
|
FAILURE_MODES = [:raise, :soft_fail].freeze
|
6
5
|
|
7
6
|
attr_reader :registered_schemas
|
7
|
+
attr_reader :configured_subscriptions
|
8
8
|
attr_writer :context_for_subscription
|
9
9
|
|
10
10
|
def initialize(options = {})
|
11
11
|
@registered_schemas = {}
|
12
|
+
@configured_subscriptions = []
|
13
|
+
|
12
14
|
producing_events_fails_with(:raise)
|
13
15
|
|
14
16
|
update(options)
|
@@ -48,6 +50,28 @@ module NulogyMessageBusProducer
|
|
48
50
|
options.each { |key, value| public_send("#{key}=", value) }
|
49
51
|
end
|
50
52
|
|
53
|
+
def add_subscription!(schema:, query:)
|
54
|
+
@configured_subscriptions ||= []
|
55
|
+
|
56
|
+
schema_key = NulogyMessageBusProducer.resolve_schema_key(schema)
|
57
|
+
query_parser = Configuration::QueryParser.new(query)
|
58
|
+
subscription = Subscriptions::ConfiguredSubscription.new(
|
59
|
+
id: query_parser.subscription_id,
|
60
|
+
subscription_group_id: query_parser.subscription_group_id,
|
61
|
+
schema_key: schema_key,
|
62
|
+
event_type: query_parser.event_type,
|
63
|
+
topic_name: query_parser.topic,
|
64
|
+
query: query
|
65
|
+
)
|
66
|
+
|
67
|
+
if subscription.valid?
|
68
|
+
@configured_subscriptions << subscription
|
69
|
+
subscription
|
70
|
+
else
|
71
|
+
raise ArgumentError, subscription.errors.full_messages
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
51
75
|
private
|
52
76
|
|
53
77
|
def raise_handler(subscription_id:, context:, variables:, result:)
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module NulogyMessageBusProducer
|
2
|
+
module Configuration
|
3
|
+
class QueryParser
|
4
|
+
class ParseError < StandardError
|
5
|
+
attr_reader :source_error
|
6
|
+
|
7
|
+
def intialize(source_error)
|
8
|
+
@source_error = source_error
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(query)
|
13
|
+
@query = query
|
14
|
+
end
|
15
|
+
|
16
|
+
def subscription_id
|
17
|
+
parse
|
18
|
+
|
19
|
+
argument("subscriptionId")
|
20
|
+
rescue => e
|
21
|
+
error("subscriptionId", e)
|
22
|
+
end
|
23
|
+
|
24
|
+
def subscription_group_id
|
25
|
+
parse
|
26
|
+
|
27
|
+
argument("subscriptionGroupId")
|
28
|
+
rescue => e
|
29
|
+
error("subscriptionGroupId", e)
|
30
|
+
end
|
31
|
+
|
32
|
+
def event_type
|
33
|
+
parse
|
34
|
+
|
35
|
+
first_selection.name
|
36
|
+
rescue => e
|
37
|
+
error("event type", e)
|
38
|
+
end
|
39
|
+
|
40
|
+
def topic
|
41
|
+
parse
|
42
|
+
|
43
|
+
argument("topicName")
|
44
|
+
rescue => e
|
45
|
+
error("topic", e)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def parse
|
51
|
+
@gql ||= GraphQL::Language::Parser.parse(@query)
|
52
|
+
end
|
53
|
+
|
54
|
+
def argument(field)
|
55
|
+
first_selection
|
56
|
+
.arguments.detect { |e| e.name == field }
|
57
|
+
.value
|
58
|
+
end
|
59
|
+
|
60
|
+
def first_selection
|
61
|
+
@gql
|
62
|
+
.definitions.first
|
63
|
+
.selections.first
|
64
|
+
end
|
65
|
+
|
66
|
+
def error(field, err)
|
67
|
+
raise ParseError.new(err), "Error extracting #{field} from the subscription"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module NulogyMessageBusProducer
|
2
|
+
# This model saves self-serve subscriptions to external systems.
|
3
|
+
# An external system can subscribe to events and specify the shape of data it would like to receive for the event.
|
4
|
+
class SelfServeSubscription < ApplicationRecord
|
5
|
+
self.table_name = :message_bus_subscriptions
|
6
|
+
|
7
|
+
validates :id, presence: true
|
8
|
+
validates :subscription_group_id, presence: true
|
9
|
+
validates :schema_key, :event_type, presence: true
|
10
|
+
validates :query, :presence => true, "nulogy_message_bus_producer/subscriptions/valid_for_schema" => true
|
11
|
+
|
12
|
+
def self.create_or_update(attrs)
|
13
|
+
find_or_initialize_by(id: attrs[:id]).tap do |model|
|
14
|
+
model.update!(attrs)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module NulogyMessageBusProducer
|
2
|
+
module Subscriptions
|
3
|
+
class ConfiguredSubscription
|
4
|
+
include ActiveModel::Model
|
5
|
+
|
6
|
+
attr_accessor :id, :subscription_group_id, :schema_key, :event_type, :query, :topic_name
|
7
|
+
|
8
|
+
validates :id, presence: true
|
9
|
+
validates :subscription_group_id, presence: true
|
10
|
+
validates :schema_key, :event_type, presence: true
|
11
|
+
validates :query, :presence => true, "nulogy_message_bus_producer/subscriptions/valid_for_schema" => true
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module NulogyMessageBusProducer
|
2
|
+
module Subscriptions
|
3
|
+
# A facade to find subscriptions.
|
4
|
+
#
|
5
|
+
# It will retrieve subscriptions from these sources:
|
6
|
+
# - configured subscriptions via #add_subscription!
|
7
|
+
# - self-serve subscriptions via GraphQL API
|
8
|
+
#
|
9
|
+
# If a subscription exists with the same id in both sources, then
|
10
|
+
# the configured subscription will be returned.
|
11
|
+
class Finder
|
12
|
+
def initialize(config)
|
13
|
+
@config = config
|
14
|
+
end
|
15
|
+
|
16
|
+
# Note: raises like ActiveRecord#find
|
17
|
+
def find(id)
|
18
|
+
@config.configured_subscriptions.detect { |s| s.id == id } || SelfServeSubscription.find(id)
|
19
|
+
end
|
20
|
+
|
21
|
+
def for_schema_event(schema_key, event_type)
|
22
|
+
subscriptions = configured(schema_key, event_type) + self_serve(schema_key, event_type)
|
23
|
+
|
24
|
+
subscriptions.uniq(&:id)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def self_serve(schema_key, event_type)
|
30
|
+
SelfServeSubscription.where(event_type: event_type, schema_key: schema_key)
|
31
|
+
end
|
32
|
+
|
33
|
+
def configured(schema_key, event_type)
|
34
|
+
@config
|
35
|
+
.configured_subscriptions
|
36
|
+
.filter { |s| s.event_type == event_type && s.schema_key == schema_key }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|