-
Notifications
You must be signed in to change notification settings - Fork 3
v2 #12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
v2 #12
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,4 +9,8 @@ AllCops: | |
|
|
||
| Naming/FileName: | ||
| Exclude: | ||
| - '**/*.md' | ||
| - '**/*.md' | ||
|
|
||
| Lint/ConstantReassignment: | ||
| Exclude: | ||
| - '**/*.md' | ||
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,7 @@ | ||
| source 'https://rubygems.org' | ||
|
|
||
| gem 'sqlite3', '~> 1.4' | ||
| gem 'rails', '~> 7.0' | ||
| gem 'sqlite3', '~> 2.0' | ||
| gem 'rails', '~> 8.0' | ||
| gem 'rails_event_store', github: 'RailsEventStore/rails_event_store' | ||
|
|
||
| gemspec path: '..' |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| module Downstream | ||
| class DataEvent < Event | ||
| class << self | ||
| attr_writer :data_class | ||
|
|
||
| def data_class | ||
| return @data_class if @data_class | ||
|
|
||
| @data_class = superclass.data_class | ||
| end | ||
|
|
||
| undef_method :attributes | ||
| undef_method :defined_attributes | ||
| end | ||
|
|
||
| def initialize(event_id: nil, **attrs) | ||
| @event_id = event_id || SecureRandom.hex(10) | ||
| @data = self.class.data_class.new(**attrs) | ||
| freeze | ||
| end | ||
|
|
||
| def to_h | ||
| { | ||
| type:, | ||
| event_id:, | ||
| data: data.to_h.freeze | ||
| }.freeze | ||
| end | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,19 @@ module Downstream | |
| class Engine < ::Rails::Engine | ||
| config.downstream = Downstream.config | ||
|
|
||
| ::GlobalID::Locator.use "downstream" do |gid| | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Feels like a better place for this code. |
||
| params = gid.params.each_with_object({}) do |(key, value), memo| | ||
| memo[key.to_sym] = if value.is_a?(String) && value.start_with?("gid://") | ||
| GlobalID::Locator.locate(value) | ||
| else | ||
| value | ||
| end | ||
| end | ||
|
|
||
| gid.model_name.constantize | ||
| .new(event_id: gid.model_id, **params) | ||
| end | ||
|
|
||
| config.to_prepare do | ||
| Downstream.pubsub.reset | ||
| ActiveSupport.run_load_hooks("downstream-events", Downstream) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,18 +1,5 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| GlobalID::Locator.use "downstream" do |gid| | ||
| params = gid.params.each_with_object({}) do |(key, value), memo| | ||
| memo[key.to_sym] = if value.is_a?(String) && value.start_with?("gid://") | ||
| GlobalID::Locator.locate(value) | ||
| else | ||
| value | ||
| end | ||
| end | ||
|
|
||
| gid.model_name.constantize | ||
| .new(event_id: gid.model_id, **params) | ||
| end | ||
|
|
||
| module Downstream | ||
| class Event | ||
| extend ActiveModel::Naming | ||
|
|
@@ -26,7 +13,7 @@ class << self | |
| def identifier | ||
| return @identifier if instance_variable_defined?(:@identifier) | ||
|
|
||
| @identifier = name.underscore.tr("/", ".") | ||
| @identifier = name.underscore.tr("/", ".").gsub(/_event$/, "") | ||
| end | ||
|
|
||
| # define store readers | ||
|
|
@@ -56,6 +43,20 @@ def defined_attributes | |
| end | ||
| end | ||
|
|
||
| def define(*fields, &) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I do like the new public method, but I think the public interface with this definition doesn't clearly state what's going on, that one variant is mutable and the other immutable. Perhaps the strategy could be defined through an attributes parameter, like immutable: true. |
||
| fields.each do |field| | ||
| raise ArgumentError, "#{field} is reserved" if RESERVED_ATTRIBUTES.include?(field) | ||
| end | ||
|
|
||
| data_class = ::Data.define(*fields) | ||
|
|
||
| Class.new(DataEvent, &).tap do | ||
| _1.data_class = data_class | ||
|
|
||
| _1.delegate(*fields, to: :data) | ||
| end | ||
| end | ||
|
|
||
| def i18n_scope | ||
| :activemodel | ||
| end | ||
|
|
@@ -94,7 +95,7 @@ def to_h | |
| end | ||
|
|
||
| def to_global_id | ||
| new_data = data.each_with_object({}) do |(key, value), memo| | ||
| new_data = data.to_h.each_with_object({}) do |(key, value), memo| | ||
| memo[key] = if value.respond_to?(:to_global_id) | ||
| value.to_global_id | ||
| else | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| module Downstream | ||
| class Subscriber | ||
| class << self | ||
| # All public names are considered event handlers | ||
| # (same concept as action_names in controllers/mailers) | ||
| def event_names | ||
| @event_names ||= begin | ||
| # All public instance methods of this class, including ancestors | ||
| methods = (public_instance_methods(true) - | ||
| # Except for public instance methods of Base and its ancestors | ||
| Downstream.public_instance_methods(true) + | ||
| # Be sure to include shadowed public instance methods of this class | ||
| public_instance_methods(false)).uniq.map(&:to_s) | ||
| methods.to_set | ||
| end | ||
| end | ||
|
|
||
| # Downstream subscriber interface | ||
| def call(event) | ||
| new.process_event(event) | ||
| end | ||
| end | ||
|
|
||
| def process_event(event) | ||
| # TODO: callbacks? instrumentation? | ||
| # TODO: namespaced events? | ||
| public_send(event.type, event) | ||
| end | ||
| end | ||
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Data class is available since 3.2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Though the library can still be used with older Rubies (without data); we have a note in the Readme