Skip to content
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

Timestamp deleted from our domain event after mapping #1002

Closed
haines opened this issue Feb 4, 2021 · 5 comments
Closed

Timestamp deleted from our domain event after mapping #1002

haines opened this issue Feb 4, 2021 · 5 comments
Labels

Comments

@haines
Copy link

haines commented Feb 4, 2021

Our domain events don't inherit from RubyEventStore::Event, and the metadata is just a vanilla hash rather than a RubyEventStore::Metadata. That means that the DomainEvent transformation mutates our domain events here:

metadata = domain_event.metadata.to_h
timestamp = metadata.delete(:timestamp)
valid_at = metadata.delete(:valid_at)

I think this code assumes that to_h returns a copy of the metadata, but with a bare hash it just returns the metadata itself.

This causes problems because the event listeners that handle the event after it's been mapped can't access the timestamp.

@mostlyobvious
Copy link
Member

Can you show me your event implementation?

@haines
Copy link
Author

haines commented Feb 4, 2021

module Plumbing
  class Event < Dry::Struct
    include Contracts::Core
    include Contracts::Builtin

    INITIAL_VERSION = 1
    Contract Or[nil, Integer] => Integer

    def self.version(version = nil)
      if version
        @version = version
      else
        @version || INITIAL_VERSION
      end
    end

    Contract KeywordArgs[event_id: String, data: Hash, metadata: Hash] => Any

    def self.new(event_id:, data:, metadata:)
      normalized_attributes = {
        data: data,
        event_id: event_id,
        metadata: metadata
      }

      new_attributes = VersionConverter.new.call(normalized_attributes, self)
      super(event_id: event_id, metadata: new_attributes[:metadata], **new_attributes[:data])
    end

    Contract None => Event

    def self.new
      super(metadata: { version: version })
    end

    Contract Any => Event

    def self.new(attributes = {})
      super(**attributes.to_h, metadata: { version: version })
    end

    Contract Class => Any

    def self.inherited(klass)
      super
      klass.attribute :event_id, (Types::UUID.default { SecureRandom.uuid })
      klass.attribute :metadata, Types::Metadata.optional
    end

    Contract None => Hash

    def to_h
      {
        event_id: event_id,
        metadata: metadata,
        data: super.except(:event_id, :metadata),
        type: type
      }
    end

    Contract None => Integer

    def version
      metadata[:version]
    end

    Contract None => Time

    def timestamp
      metadata[:timestamp]
    end

    def data
      to_h[:data]
    end

    def ==(other)
      other.instance_of?(self.class) &&
        other.event_id.eql?(event_id) &&
        other.data.eql?(data)
    end

    def matches?(attributes)
      data.slice(*attributes.keys) == attributes.slice(*data.keys)
    end

    def to_s
      "#{self.class} #{to_h}"
    end

    def type
      self.class.name
    end
    alias event_type type

    alias == eql?

    def acting_user_id
      metadata[:user_id]
    end
  end
end

@mostlyobvious
Copy link
Member

That means that the DomainEvent transformation mutates our domain events

Right, this most probably happenned here: 1759ada#diff-ff913f01670ba8bfd82ad3c689029bf5c8589276cac50958397e108784906cb4L10

@mostlyobvious
Copy link
Member

@haines I'm planning a smaller release this week and 3ba0549 is going to be a part of it, can you please check if it solves your issue?

@mostlyobvious
Copy link
Member

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants