nulogy_message_bus_producer 3.2.0 → 4.0.0.alpha

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +186 -25
  3. data/Rakefile +2 -4
  4. data/db/migrate/20200611150212_create_public_subscriptions_and_events_tables.rb +2 -2
  5. data/db/migrate/20210330204121_add_event_type_to_subscription_events.rb +9 -0
  6. data/lib/nulogy_message_bus_producer.rb +32 -12
  7. data/lib/nulogy_message_bus_producer/base_subscription.rb +1 -1
  8. data/lib/nulogy_message_bus_producer/config.rb +25 -1
  9. data/lib/nulogy_message_bus_producer/configuration/query_parser.rb +71 -0
  10. data/lib/nulogy_message_bus_producer/repopulate_replication_slots.rb +7 -5
  11. data/lib/nulogy_message_bus_producer/self_serve_subscription.rb +18 -0
  12. data/lib/nulogy_message_bus_producer/subscription_event.rb +3 -0
  13. data/lib/nulogy_message_bus_producer/subscriptions/configured_subscription.rb +14 -0
  14. data/lib/nulogy_message_bus_producer/subscriptions/finder.rb +40 -0
  15. data/lib/nulogy_message_bus_producer/subscriptions/no_variables.rb +43 -0
  16. data/lib/nulogy_message_bus_producer/subscriptions/postgres_transport.rb +11 -4
  17. data/lib/nulogy_message_bus_producer/subscriptions/query_validator.rb +47 -0
  18. data/lib/nulogy_message_bus_producer/subscriptions/risky_subscription_blocker.rb +17 -10
  19. data/lib/nulogy_message_bus_producer/subscriptions/valid_for_schema_validator.rb +14 -0
  20. data/lib/nulogy_message_bus_producer/version.rb +1 -1
  21. data/lib/tasks/engine/message_bus_producer.rake +4 -4
  22. data/spec/dummy/Rakefile +1 -1
  23. data/spec/dummy/app/mailers/application_mailer.rb +2 -2
  24. data/spec/dummy/bin/bundle +2 -2
  25. data/spec/dummy/bin/rails +3 -3
  26. data/spec/dummy/bin/rake +2 -2
  27. data/spec/dummy/bin/setup +10 -11
  28. data/spec/dummy/bin/update +10 -10
  29. data/spec/dummy/bin/yarn +6 -8
  30. data/spec/dummy/config.ru +1 -1
  31. data/spec/dummy/config/boot.rb +3 -3
  32. data/spec/dummy/config/database.yml +2 -2
  33. data/spec/dummy/config/environment.rb +1 -1
  34. data/spec/dummy/config/environments/development.rb +2 -2
  35. data/spec/dummy/config/environments/production.rb +5 -5
  36. data/spec/dummy/config/environments/test.rb +2 -2
  37. data/spec/dummy/config/initializers/assets.rb +2 -2
  38. data/spec/dummy/config/puma.rb +3 -3
  39. data/spec/dummy/config/spring.rb +2 -2
  40. data/spec/dummy/db/schema.rb +2 -1
  41. data/spec/dummy/log/development.log +321 -0
  42. data/spec/dummy/log/test.log +19061 -0
  43. data/spec/integration/lib/nulogy_message_bus_producer/config_spec.rb +37 -0
  44. data/spec/integration/lib/nulogy_message_bus_producer/repopulate_replication_slots_spec.rb +23 -14
  45. data/spec/integration/lib/nulogy_message_bus_producer/subscription_spec.rb +3 -59
  46. data/spec/integration/lib/nulogy_message_bus_producer/subscriptions/finder_spec.rb +54 -0
  47. data/spec/integration/lib/nulogy_message_bus_producer/subscriptions/no_variables_spec.rb +46 -0
  48. data/spec/integration/lib/nulogy_message_bus_producer/subscriptions/postgres_transport_spec.rb +99 -55
  49. data/spec/integration/lib/nulogy_message_bus_producer/{subscriber_graphql_schema_validator_spec.rb → subscriptions/query_validator_spec.rb} +5 -5
  50. data/spec/integration/lib/nulogy_message_bus_producer/subscriptions/risky_subscription_blocker_spec.rb +1 -19
  51. data/spec/integration/lib/nulogy_message_bus_producer_spec.rb +25 -0
  52. data/spec/integration_spec_helper.rb +0 -6
  53. data/spec/nulogy_message_bus_producer/configuration/query_parser_spec.rb +58 -0
  54. data/spec/nulogy_message_bus_producer/subscriptions/subscription_spec.rb +9 -0
  55. data/spec/spec_helper.rb +25 -1
  56. data/spec/support/kafka.rb +15 -9
  57. data/spec/support/kafka_connect.rb +1 -1
  58. data/spec/support/shared_examples/subscription_validations.rb +77 -0
  59. data/spec/support/spec_utils.rb +3 -2
  60. data/spec/support/sql_helpers.rb +9 -11
  61. data/spec/support/subscription_helpers.rb +22 -4
  62. data/spec/support/test_graphql_schema.rb +7 -0
  63. metadata +58 -38
  64. data/lib/nulogy_message_bus_producer/subscriber_graphql_schema_validator.rb +0 -45
  65. 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: 54bcc4198672edd1d3366678b06118df437c95267fd274f1df2969d5e029abff
4
- data.tar.gz: 5c4a2d3dd70682348e383a0398e48944845512fcb6a68478278e76b5f5ac3153
3
+ metadata.gz: ef6259b620567209e608c461298813e61646f25f8c7aa5adc10e4fa967069ed6
4
+ data.tar.gz: 61a9f10a879d6b2b05d25c1b3ad177f23948dcf79dd9a89766df29cc8f1c3bf9
5
5
  SHA512:
6
- metadata.gz: 04707ec3c4da493d52a4d817da040a88fb32dc3017cb549098e7a1d38d47a8ba24a34d707382c7391822fe640c0bd2792f540acb826da8eb4300a5e3482caaca
7
- data.tar.gz: a27eabba49d13fabae89628f1210232b7f46ce28c41514e1fc86d3ac344af8e8c650517dd76c7141a290f625474adcf34bb1ff11209a542d49d34194c5b08bcc
6
+ metadata.gz: d2b2a6558e97fe79eae7624d8bdaefc585b1a8747cd506cfde6d7757eea01d8f5b7153877efcdbbd424d5d4776a5c79cdfb3a61fdf3144e385a9c2010b7b88b0
7
+ data.tar.gz: 96f659ac685cef6807855baa4b3a4e633b0340f176fec2ac37dbf6c2cefbf20ec0f2d29a2b74196518cf6ee571bae5f56ffe08117cf86d72197125588ed14f8c
data/README.md CHANGED
@@ -1,39 +1,183 @@
1
1
  # Nulogy Message Bus Producer
2
2
 
3
- Nulogy's code for producing to to the Message Bus
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 migration `rake railties:install:migrations`
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)
12
+
13
+ ## Overview
14
+
15
+ The Producer gem supports two ways of producing messages:
16
+
17
+ ### Subscription
18
+
19
+ A subscription (either self-serve or configured) is triggered via a domain event.
20
+ The subscription `event_data` (TODO: column should also be renamed) will render the query against a public GraphQL Schema.
21
+
22
+ ### Publication
23
+
24
+ aka the pub half of `pubsub`.
25
+
26
+ A client publishes arbitrary `event_data` (serializable to JSON) to a `topic` under a `event_type`.
27
+
28
+ ### Comparison
29
+
30
+ | Attribute | Subscription | Publication |
31
+ |-----------------------|------------------------------------------------------|--------------------------|
32
+ | subscription_id | consumer supplied | random |
33
+ | subscription_group_id | consumer supplied | random |
34
+ | topic | consumer supplied | explicit (user supplied) |
35
+ | type | computed (domain event / GraphQL subscription field) | explicit (user supplied) |
36
+ | message ordering | per `company_uuid` per `subscription_group_id` | per `company_uuid` |
9
37
 
10
38
  ## Usage
11
39
 
12
- This engine contains the classes and validations for producing messages to the Message Bus.
40
+ ### Subscriptions
41
+
42
+ Subscriptions should inherit from `NulogyMessageBusProducer::BaseSubscription`.
43
+
44
+ Subscriptions are created by consumers to subscribe to certain events that the producer exposes.
45
+
46
+ When an event is fired/triggered, subscriptions are used to generate events into the
47
+ `NulogyMessageBusProducer.subscription_events_table_name` table.
48
+
49
+ Debezium then reads this table from the PG replication log and pushes them into Kafka.
50
+
51
+ There are two ways to create subscriptions:
52
+
53
+ #### Configured
54
+
55
+ Subscriptions provided by configuration in the producer app:
56
+
57
+ ```ruby
58
+ NulogyMessageBusProducer.configure do |c|
59
+ c.register_schema(schema: "ExampleDomain::Schema", key: "exampleDomain")
60
+
61
+ c.add_subscription!(
62
+ schema: "ExampleDomain::Schema",
63
+ query: <<~QUERY
64
+ subscription {
65
+ domainEvent(subscriptionId: "uuid", subscriptionGroupId: "uuid2", topicName: "consumer-inbox") {
66
+ domainObject {
67
+ field
68
+ }
69
+ }
70
+ }
71
+ QUERY
72
+ )
73
+ end
74
+ ```
75
+
76
+ These subscriptions are stored in the producer and require a deploy to update.
77
+
78
+ #### Self-Serve (deprecated)
79
+
80
+ You create these subscriptions via the public GraphQL API. e.g.
81
+
82
+ ```graphql
83
+ subscription {
84
+ workOrderUpdated(subscriptionId: "uuid", subscriptionGroupId: "uuid", topicName: "some-topic") {
85
+ workOrder {
86
+ id
87
+ code
88
+ }
89
+ }
90
+ }
91
+ ```
13
92
 
14
- In general, as long as a subscription inherits from `NulogyMessageBusProducer::BaseSubscription`, everything
15
- should be set up.
93
+ These subscriptions are written to the `NulogyMessageBusProducer.subscriptions_table_name` table.
16
94
 
17
- Subscriptions will be written to the `NulogyMessageBusProducer.subscriptions_table_name` while events generated from the subscriptions will be written to
18
- `NulogyMessageBusProducer.subscription_events_table_name`. Debezium then reads this table from the PG replication log and pushes them into Kafka.
95
+ This style of subscriptions may be removed in a future release.
96
+
97
+ There is a [guide to migrate from Self-Serve to Configured](docs/self_serve_to_configured_subscriptions.md)
98
+
99
+ ### Publications
100
+
101
+ The Message Bus has a unified `SubscriptionEvent` (TODO: rename) data structure that will create a Kafka message.
102
+ Thus, the publication-style of producing messages must provide any required fields to produce a valid `SubscriptionEvent`.
103
+
104
+ ```ruby
105
+ # publish
106
+ # NulogyMessageBusProducer.publish(topic:, type:, company_uuid:, data:)
107
+
108
+ NulogyMessageBusProducer.publish(
109
+ topic: "some-target-inbox",
110
+ type: "some-event-type",
111
+ company_uuid: company.uuid,
112
+ data: {message: "some data", value: "3", ...}
113
+ )
114
+ ```
115
+
116
+ Note that we do not support publishing to multiple topics at the moment.
117
+
118
+ A producer may want to wrap these methods:
119
+
120
+ ```ruby
121
+ class MetricsPublisher
122
+ def initialize(company, type: "some-kind-of-metric", topic: "metrics-stream")
123
+ @company_uuid = company.uuid
124
+ @topic = topic
125
+ @type = type
126
+ end
127
+
128
+ def publish(data)
129
+ NulogyMessageBusProducer.publish(
130
+ topic: @topic,
131
+ type: @type,
132
+ company_uuid: @company_uuid,
133
+ data: {message:"something", value: 3}
134
+ )
135
+ end
136
+ end
137
+
138
+ MetricsPublisher.new(Current.company).publish(metric_data)
139
+ ```
140
+
141
+ #### Self-Serve (soft-deprecated)
142
+
143
+ You create these subscriptions via the public GraphQL API. For testing, the [Insomnia](https://insomnia.rest/) client
144
+ is highly recommended.
145
+
146
+ ```graphql
147
+ subscription {
148
+ workOrderUpdated(subscriptionId: "uuid", subscriptionGroupId: "uuid", topicName: "some-topic") {
149
+ workOrder {
150
+ id
151
+ code
152
+ }
153
+ }
154
+ }
155
+ ```
156
+
157
+ These subscriptions are written to the `NulogyMessageBusProducer.subscriptions_table_name` table.
158
+
159
+ This style of subscriptions may be removed in a future release.
160
+
161
+ There is a [guide to migrate from Self-Serve to Configured](docs/self_serve_to_configured_subscriptions.md)
19
162
 
20
163
  ## Configuration
21
164
 
22
- | Configuration | Default | Description |
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 Subscription model |
27
- | subscription_events_table_name | "message_bus_subscription_events" | The name of the table for the SubscriptionEvents model |
165
+ | Configuration | Default | Description |
166
+ |--------------------------------|-----------------------------------|----------------------------------------------------------------------------------------------------|
167
+ | context_for_subscription | `->(_subscription) { {} }` | A lambda used to inject any GraphQL Context to be used when producing subscription events |
168
+ | producing_events_fails_with | :raise | How the producer should handle errors when producing subscription events |
169
+ | subscriptions_table_name | "message_bus_subscriptions" | The name of the table for the SelfServeSubscription model |
170
+ | subscription_events_table_name | "message_bus_subscription_events" | The name of the table for the SubscriptionEvents model |
171
+ | add_subscription! | [] (i.e. empty) | Add a subscription via configuration. It will supercede any configured via GraphQL for a given id. |
28
172
 
29
173
  ## Setup
30
174
 
31
175
  You should configure the gem with an initializer. A recommended setup:
32
176
 
33
177
  ```ruby
34
- # Table names are configurable (optional)
35
- NulogyMessageBusProducer.subscriptions_table_name = :message_bus_subscriptions
36
- NulogyMessageBusProducer.subscription_events_table_name = :message_bus_subscription_events
178
+ # (optional) Table names are configurable
179
+ # NulogyMessageBusProducer.subscriptions_table_name = :message_bus_subscriptions
180
+ # NulogyMessageBusProducer.subscription_events_table_name = :message_bus_subscription_events
37
181
 
38
182
  # Register known schemas
39
183
  NulogyMessageBusProducer.configure do |config|
@@ -90,6 +234,11 @@ module ExampleDomainPublicApi
90
234
  # For now, these are banned until we have a use-case which would require them.
91
235
  query_analyzer NulogyMessageBusProducer::Subscriptions::RiskySubscriptionBlocker
92
236
 
237
+ # This prevents creating subscriptions with variables.
238
+ # Since variables are not saved with the query,
239
+ # the Subscription would always fail when generating events.
240
+ query_analyzer NulogyMessageBusProducer::Subscriptions::NoVariables
241
+
93
242
  query Types::QueryType
94
243
  subscription Types::SubscriptionType
95
244
  end
@@ -171,7 +320,7 @@ class CreateSku
171
320
  if sku.save
172
321
  # This needs to be invoked within the same transaction as Sku.save
173
322
  # Otherwise, the sku could be saved without the event being triggered
174
- trigger_subscription(:sku_created, sku)
323
+ trigger_subscription("skuCreated", sku)
175
324
  end
176
325
  end
177
326
 
@@ -204,17 +353,29 @@ rails message_bus_producer:repopulate_replication_slots
204
353
 
205
354
  ## Rake Tasks
206
355
 
207
- | Rake command | Description |
208
- |--------------|-----------------|
209
- | (default) | RSpec + RuboCop |
210
- | `spec` | RSpec |
211
- | `rubocop` | RuboCop |
356
+ | Rake command | Description |
357
+ |------------------|------------------|
358
+ | (default) | RSpec + Standard |
359
+ | `spec` | RSpec |
360
+ | `standardrb` | Standard |
361
+ | `standardrb:fix` | Fix to Standard |
212
362
 
213
363
  # Gem Development Setup
214
364
 
215
365
  If you are doing work on this gem you will want to:
216
366
  ```shell script
217
367
  docker-compose up
218
- rake db:setup
219
- rake
368
+ bundle exec rake db:setup
369
+ bundle exec rake
220
370
  ```
371
+
372
+ # Gem Releases
373
+
374
+ You must be listed as a gem owner [on rubygems](https://rubygems.org/gems/nulogy_message_bus_producer) to cut a release:
375
+
376
+ * Merge your changes to `master`
377
+ * Commit a version bump
378
+ * Update `lib/nulogy_message_bus_producer/version.rb`
379
+ * Run `bundle install`
380
+ * Update the CHANGELOG
381
+ * 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 "rubocop/rake_task"
16
+ require "standard/rake"
17
17
 
18
- RuboCop::RakeTask.new
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: { name: "index_nulogy_mb_producer_subscriptions_on_event_type" }
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: { name: "index_nulogy_mb_producer_subscription_events_on_created_at" }
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
@@ -0,0 +1,9 @@
1
+ class AddEventTypeToSubscriptionEvents < ActiveRecord::Migration[5.2]
2
+ def up
3
+ add_column :message_bus_subscription_events, :event_type, :text
4
+ end
5
+
6
+ def down
7
+ remove_column :message_bus_subscription_events, :event_type
8
+ end
9
+ end
@@ -1,6 +1,7 @@
1
1
  require "graphql"
2
2
 
3
3
  require "nulogy_message_bus_producer/config"
4
+ require "nulogy_message_bus_producer/configuration/query_parser"
4
5
  require "nulogy_message_bus_producer/version"
5
6
  require "nulogy_message_bus_producer/engine"
6
7
 
@@ -14,11 +15,11 @@ module NulogyMessageBusProducer
14
15
  end
15
16
 
16
17
  def self.subscriptions_table_name=(table_name)
17
- NulogyMessageBusProducer::Subscription.table_name = table_name
18
+ NulogyMessageBusProducer::SelfServeSubscription.table_name = table_name
18
19
  end
19
20
 
20
21
  def self.subscriptions_table_name
21
- NulogyMessageBusProducer::Subscription.table_name
22
+ NulogyMessageBusProducer::SelfServeSubscription.table_name
22
23
  end
23
24
 
24
25
  def self.subscription_events_table_name=(table_name)
@@ -33,13 +34,26 @@ module NulogyMessageBusProducer
33
34
  config.context_for_subscription(subscription)
34
35
  end
35
36
 
36
- def self.trigger_event(schema, event_type, root_object)
37
- schema_key = NulogyMessageBusProducer.resolve_schema_key(schema)
37
+ def self.register_publication
38
+ raise "not implemented yet"
39
+ end
38
40
 
39
- subscriptions = Subscription.where(
40
- event_type: event_type,
41
- schema_key: schema_key
41
+ def self.publish(topic:, type:, company_uuid:, data:)
42
+ SubscriptionEvent.create_or_update(
43
+ id: SecureRandom.uuid,
44
+ subscription_id: SecureRandom.uuid,
45
+ partition_key: company_uuid,
46
+
47
+ company_uuid: company_uuid,
48
+ event_type: type,
49
+ event_json: data,
50
+ topic_name: topic
42
51
  )
52
+ end
53
+
54
+ def self.trigger_event(schema, event_type, root_object)
55
+ schema_key = NulogyMessageBusProducer.resolve_schema_key(schema)
56
+ subscriptions = Subscriptions::Finder.new(config).for_schema_event(schema_key, event_type)
43
57
 
44
58
  subscriptions.each do |subscription|
45
59
  args = {
@@ -51,7 +65,7 @@ module NulogyMessageBusProducer
51
65
  end
52
66
  end
53
67
 
54
- def self.resolve_schema(schema_key)
68
+ def self.resolve_schema(schema_key) # rubocop:disable Metrics/MethodLength
55
69
  if config.registered_schemas.key?(schema_key)
56
70
  config.registered_schemas[schema_key].constantize
57
71
  elsif block_given?
@@ -69,7 +83,9 @@ module NulogyMessageBusProducer
69
83
  end
70
84
 
71
85
  def self.resolve_schema_key(schema)
72
- config.registered_schemas.invert.fetch(schema.name) do
86
+ schema_name = schema.respond_to?(:name) ? schema.name : schema
87
+
88
+ config.registered_schemas.invert.fetch(schema_name) do
73
89
  raise KeyError, <<~MESSAGE
74
90
  The schema registry did not contain an entry for the schema '#{schema.name}'.
75
91
 
@@ -84,7 +100,7 @@ module NulogyMessageBusProducer
84
100
  def self.validate_existing!
85
101
  return unless Db.exists? && Db.subscriptions_exist?
86
102
 
87
- validator = NulogyMessageBusProducer::SubscriberGraphqlSchemaValidator.new
103
+ validator = NulogyMessageBusProducer::Subscriptions::QueryValidator.new
88
104
 
89
105
  return if validator.validate
90
106
 
@@ -140,9 +156,13 @@ end
140
156
 
141
157
  require "nulogy_message_bus_producer/application_record"
142
158
  require "nulogy_message_bus_producer/base_subscription"
143
- require "nulogy_message_bus_producer/subscription"
144
159
  require "nulogy_message_bus_producer/subscription_event"
145
160
  require "nulogy_message_bus_producer/repopulate_replication_slots"
146
- require "nulogy_message_bus_producer/subscriber_graphql_schema_validator"
161
+ require "nulogy_message_bus_producer/subscriptions/finder"
162
+ require "nulogy_message_bus_producer/subscriptions/no_variables"
147
163
  require "nulogy_message_bus_producer/subscriptions/postgres_transport"
164
+ require "nulogy_message_bus_producer/subscriptions/query_validator"
165
+ require "nulogy_message_bus_producer/subscriptions/valid_for_schema_validator"
166
+ require "nulogy_message_bus_producer/subscriptions/configured_subscription"
167
+ require "nulogy_message_bus_producer/self_serve_subscription"
148
168
  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::BasePublicSubscription
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:)