Skip to content

Releases: RailsEventStore/rails_event_store

v0.30.0

31 May 13:17
Compare
Choose a tag to compare

RailsEventStore

  • Change: Introduce new read API with fluent interface [#184]

    Was:

    client = Rails.configuration.event_store
    
    client.read_all_streams_forward(count:  count, start: start)
    client.read_all_streams_backward(count:  count, start: start)
    client.read_events_forward(stream_name, count:  count, start: start)
    client.read_events_backward(stream_name, count:  count, start: start)
    client.read_stream_events_forward(stream_name)
    client.read_stream_events_backward(stream_name)

    Is now:

    client = Rails.configuration.event_store
    
    client.read.from(start).limit(count).each.to_a
    client.read.from(start).limit(count).backward.each.to_a
    client.read.stream(stream_name).from(start).limit(count).each.to_a
    client.read.stream(stream_name).from(start).limit(count).backward.each.to_a
    client.read.stream(stream_name).each.to_a
    client.read.stream(stream_name).backward.each.to_a

    Building query starts from read. You can append limit, stream, forward, backward and from to refine the query further. Finally calling each executes the read, returning enumerator.

    By default forward and from(:head) are applied when you don't specify anything. Beware, queries are not bounded unless you say so with limit.

    Old reader methods are now deprecated and will be removed in future releases.
    To help with migration:

    • warnings remind of deprecated API usage with some hints on new API equivalent
    • script to rewrite old API to new one is distributed with ruby_event_store gem

    Usage for dry run that outputs changes to stderr without modifying source:

    bundle exec res-deprecated-read-api-migrator FILE_OR_DIRECTORY
    

    Usage for in-place file modification:

    bundle exec res-deprecated-read-api-migrator -m FILE_OR_DIRECTORY
    

    When in doubt, you can also use this script to translate queries from STDIN, i.e.

    bundle exec res-deprecated-read-api-migrator -e 'client.read_all_streams_forward'
    
  • Add: Batch API to retrieve data in batches of given size (by default of 100) [#349]
    Used internally in RailsEventStore::Projection and AggregateRoot.

    Usage:

    client = Rails.configuration.event_store
    
    client.read.in_batches.each do |event|
      # do something with event, handling batches transparently
    end
    
    client.read.in_batches.each_batch do |batch|
      # do something with batch of default size
    end
    
    client.read.in_batches_of(1000).each_batch do |batch|
      # do something with batch of size 1000
    end
  • Add: RailsEventStore::Event#correlate_with(event_or_command), RailsEventStore::Event#correlation_id and RailsEventStore::Event#causation_id. You can now correlate messages together which makes debugging much easier [#364]

  • Remove: Deprecated subscribe and subscribe_to_all_events syntax is no more [#350]

RubyEventStore

  • Change: Introduce new read API with fluent interface. See usage and migration steps above [#184]
  • Add: Introduce batch API. See usage and migration steps above [#349]
  • Add: RubyEventStore::Event#correlate_with(event_or_command), RubyEventStore::Event#correlation_id and RubyEventStore::Event#causation_id. You can now correlate messages together which makes debugging much easier [#364]
  • Remove: Deprecated subscribe and subscribe_to_all_events syntax is no more [#350]

RailsEventStoreActiveRecord

  • no changes

AggregateRoot

  • Change: Use newly-introduced batch reading API to load stream events. This minimizes the risk of huge aggregates allocating lots of memory when reading aggregate stream [#360]

RailsEventStore::RSpec

  • Add: have_published(...).from(start) matcher can now assert on events read from particular starting point in stream. This correlates with client.read.from(start) on client read API [c582f2a]

  • Add: have_published(...).strict and have_applied(...).strict matchers to check if only events given as an expectation have been returned and nothing else [6c44cc8, 5e0e548, #119]

  • Change: Improve phrasing in documentation format [#358, #355]

  • Change: have_published matcher now reads stream events forward (from the oldest published) and without limit. Previously we did have a backward read (from the newest published) up to 100 events in order to avoid situation were lastly published event would not fit in (over 100) and not be matched.

    expect(event_store).to have_published(FooEvent, BarEvent)

    should have published events that have to (be a FooEvent and be a BarEvent)

    expect(FooEvent.new(data: { foo: "bar" }, metadata: { timestamp: Time.now }))
            .to(be_event(FooEvent).with_data(foo: "bar")
              .and(be_event(FooEvent).with_metadata(timestamp: kind_of(Time))))

    should be an event FooEvent (with data including {:foo=>"bar"}) and be an event FooEvent (with metadata including {:timestamp=>kind of Time})

BoundedContext

  • no changes

RailsEventStore::Browser

  • no changes

RubyEventStore::ROM

  • no changes

RailsEventStoreActiveRecord::Legacy

  • no changes

v0.29.0

06 May 16:52
Compare
Choose a tag to compare

RailsEventStore

  • Change: Rewrote the middleware so that it now uses RubyEventStore::Client#with_metadata to enrich published events' metadata when using a RailsEventStore::Client from Rails.application.config.event_store. By default metadata is enriched with remote_ip and request_id, you can set your own lambda in request_metadata keyword argument when initializing a client

RubyEventStore

  • Add: Added RubyEventStore::Client#with_metadata method that enriches all events published inside a block with metadata set with method argument. with_metadata calls can be nested, in such case metadata from all levels are merged
  • Change: Deprecated metadata_proc keyword argument in RubyEventStore::Client - with_metadata method should be used instead

RailsEventStoreActiveRecord

  • no changes

AggregateRoot

  • no changes

RailsEventStore::RSpec

  • Fix: Matchers now have description, making them usable with --format documentation [#127, #282, #326, #342]

  • Fix: Matchers now have failure_message_when_negated, making them usable with expect(...).not_to [#326, #342]

BoundedContext

  • no changes

RailsEventStore::Browser

  • no changes

RubyEventStore::ROM

  • Change: Lock in dry-types to 0.12 #332 #339

RailsEventStoreActiveRecord::Legacy

  • no changes

v0.28.2

06 May 15:48
Compare
Choose a tag to compare

RailsEventStore

  • no changes

RubyEventStore

  • no changes

RailsEventStoreActiveRecord

  • no changes

AggregateRoot

  • no changes

RailsEventStore::RSpec

  • no changes

BoundedContext

  • no changes

RailsEventStore::Browser

  • no changes

RubyEventStore::ROM

  • no changes

RailsEventStoreActiveRecord::Legacy

  • Fix: Avoid doubled serialization of data and metadata in RailsEventStoreActiveRecord::Legacy::EventRepository #345 #348

v0.28.1

05 May 09:09
Compare
Choose a tag to compare

RailsEventStore

  • Fix: Allow nil in event metadata #343 #344

RubyEventStore

  • Fix: Allow nil in event metadata #343 #344

RailsEventStoreActiveRecord

  • no changes

AggregateRoot

  • no changes

RailsEventStore::RSpec

  • no changes

BoundedContext

  • no changes

RailsEventStore::Browser

  • no changes

RubyEventStore::ROM

  • no changes

RailsEventStoreActiveRecord::Legacy

  • no changes

v0.28.0

01 May 23:00
Compare
Choose a tag to compare

RailsEventStore

  • Add: Support Rails 5.2

  • Change: Mappers (and serializers) now operate above the repository layer. If you have custom mapper or serializer move its configuration. [#257]

    Was:

    RailsEventStore::Client.new(
      repository: RailsEventStoreActiveRecord::EventRepository.new(
        mapper: RubyEventStore::Mappers::Default.new(
          serializer: JSON 
        )
      )
    )

    is now:

    RailsEventStore::Client.new(
      mapper: RubyEventStore::Mappers::Default.new(
        serializer: JSON 
      )
    )

    Read more in the documentation

RubyEventStore

  • Change: Mappers (and serializers) now operate above the repository layer. If you have custom mapper or serializer move its configuration. [#257]

    Was:

    RubyEventStore::Client.new(
      repository: RailsEventStoreActiveRecord::EventRepository.new(
        mapper: RubyEventStore::Mappers::Default.new(
          serializer: JSON 
        )
      )
    )

    is now:

    RubyEventStore::Client.new(
      mapper: RubyEventStore::Mappers::Default.new(
        serializer: JSON 
      )
    )

    Read more in the documentation

  • Add: NullMapper mapper. Useful in pair with InMemoryRepository for faster unit tests. Setup and usage in docs [#321] [#240]

  • Fixed: Protobuf mapper can be used with async handlers [#228]

  • Fixed: Documented InMemoryRepository which can be used for faster unit tests [#240] [#321]

  • Change: RubyEventStore#publish_event, RubyEventStore#publish_events and RubyEventStore#append_to_stream now raise IncorrectStreamData when passednil or empty stream name [#267]

  • Breaking: Metadata keys are limited to symbols. Metadata values are limited to [String, Integer, Float, Date, Time, TrueClass, FalseClass]. Using Hash, 'Array` or custom objects is no longer supported. [#271]

  • Breaking: Using protobuf mapper requires manual migration of columns to binary format [#280]

    change_column :event_store_events, :data,     :binary, null: true
    change_column :event_store_events, :metadata, :binary, null: true
  • Breaking: Using protobuf mapper requires adding protobuf_nested_struct gem to Gemfile [#280]

  • Breaking: When using protobuf mapper, the event_id is no longer stored in event's data [#280]

  • Breaking: When using protobuf mapper, the metadata fields are no longer stored in event's data [#280]

  • Breaking: When using protobuf mapper you need to use RubyEventStore::Proto class [#280]

    Was:

    event = MyApp::OrderPlaced.new(
      event_id: "f90b8848-e478-47fe-9b4a-9f2a1d53622b",
      customer_id: 123,
      order_id: "K3THNX9"
    )
    event_store.publish_event(event, stream_name: "Order-K3THNX9")

    Is now:

    event = RubyEventStore::Proto.new(
      data: MyApp::OrderPlaced.new(
        customer_id: 123,
        order_id: "K3THNX9",
      )
    )
    event_store.publish_event(event, stream_name: "Order-K3THNX9")

    Read more in the documentation

  • Remove: Custom mappers no longer should implement add_metadata method [#280]

  • Remove: Remove API to get all stream names RubyEventStore::Client#get_all_streams (8d7d3bc)

  • Breaking: Custom repositories should expect RubyEventStore::Stream and RubyEventStore::ExpectedVersion where previously stream_name and expected_version primitives were passed, in example:

    Was:

    def append_to_stream(events, stream_name, expected_version)
      # stream_name
      # expected_version
    end

    Is now:

    def append_to_stream(events, stream, expected_version)
      # stream.name
      # expected_version.any?
    end
  • Breaking: Custom repositories are expected to respond to read(specification) and return an Enumerator. The RubyEventStore::Specification::Result struct describes query conditions. This API replaces previous reader methods on repository [#184]:

    • read_events_forward(stream, after_event_id, count)
    • read_events_backward(stream, before_event_id, count)
    • read_stream_events_forward(stream)
    • read_stream_events_backward(stream)
    • read_all_streams_forward(after_event_id, count)
    • read_all_streams_backward(before_event_id, count)

RailsEventStoreActiveRecord

  • Add: Support Rails 5.2
  • Remove: LegacyEventRepository has been moved to separate rails_event_store_active_record-legacy gem, not installed as a dependency. See RailsEventStoreActiveRecord::Legacy section below.
  • Remove: Remove API to get all stream names RailsEventStoreActiveRecord::EventRepository [8d7d3bc]
  • Change: Restricted access to internal stream all with methods not intended to read from global stream. This stream name is an implementation detail of RailsEventStoreActiveRecord::EventRepository repository and reading from it using non-global stream API might result in different order of events. RubyEventStore::ReservedInternalName is raised when read_events_forward('all') is used over desired read_all_streams_forward.

AggregateRoot

  • Change: Dropped dependency on activesupport gem [#288]

RailsEventStore::RSpec

  • Add: Support Rails 5.2

BoundedContext

  • Fix: Generate better folders structure [#243]
  • Add: Support Rails 5.2

RailsEventStore::Browser

  • Add: Support Rails 5.2
  • Change: Remove stream names browsing and start with global stream events as a main screen. This is a workaround to avoid problem with inefficient API when browsing huge number of stream names. [#212, #298]

RubyEventStore::ROM

First release of Ruby Object Model (ROM) implementation of events repository for Ruby Event Store. This version of the ROM adapter supports rom-sql at this time. It is an alternative to the Active Record events repository implementation from rails_event_store_active_record gem.

Read the docs to get started.

RailsEventStoreActiveRecord::Legacy

Release of LegacyEventRepository as a separate gem. This repository has been deprecated and is compatible with single-table database schema we no longer support. If you haven't migrated and you're stuck with events repository schema from version below v0.19 then this is your option to defer it a bit more:

require 'rails_event_store_active_record/legacy'

Rails.application.configure do
  config.to_prepare do
    Rails.configuration.event_store = RailsEventStore::Client.new(
      repository: RailsEventStoreActiveRecord::Legacy::EventRepository.new
    )
  end
end

v0.27.1

26 Mar 18:51
Compare
Choose a tag to compare

RailsEventStore

  • no changes

RubyEventStore

  • no changes

RailsEventStoreActiveRecord

  • no changes

AggregateRoot

  • no changes

RailsEventStore::RSpec

  • no changes

BoundedContext

  • no changes

RailsEventStore::Browser

  • Fix: Re-release with correctly-built Browser javascript that failed when releasing 0.27.0 (#209)

v0.27.0

26 Mar 18:45
Compare
Choose a tag to compare

RailsEventStore

RubyEventStore

  • Add: Allow using ruby_event_store with repository from rails_event_store_active_record without rails - #236

    Documentation: http://railseventstore.org/docs/without_rails/

  • Add: ruby_event_store no longer uses active_support as dependency #232

  • Breaking: We dropped support for Ruby 2.2. It might continue to work, but we no longer test it and we don't guarantee it anymore.

RailsEventStoreActiveRecord

  • Add: Allow using rails_event_store_active_record without rails. - #236

    Documentation: http://railseventstore.org/docs/without_rails/

  • Breaking: We dropped support for Ruby 2.2. It might continue to work, but we no longer test it and we don't guarantee it anymore.

AggregateRoot

  • Breaking: We dropped support for Ruby 2.2. It might continue to work, but we no longer test it and we don't guarantee it anymore.

RailsEventStore::RSpec

  • Breaking: We dropped support for Ruby 2.2. It might continue to work, but we no longer test it and we don't guarantee it anymore.

BoundedContext

  • Breaking: We dropped support for Ruby 2.2. It might continue to work, but we no longer test it and we don't guarantee it anymore.

RailsEventStore::Browser

  • Breaking: We dropped support for Ruby 2.2. It might continue to work, but we no longer test it and we don't guarantee it anymore.

v0.26

06 Mar 10:09
Compare
Choose a tag to compare

RailsEventStore

  • Deprecate: subscribe(handler, array_of_event_types) is deprecated. Use subscribe(handler, to: event_types) instead. Example

    client = RailsEventStore::Client.new
    client.subscribe(OrderSummaryEmail.new, to: [OrderPlaced])
  • Deprecate: subscribe(subscriber, event_types, &task) has been deprecated. Use within(&task).subscribe(subscriber, to: event_types).call instead. #155 - Example:

    client = RailsEventStore::Client.new
    client.within do
      PlaceOrder.new
    end.subscribe(OrderSummaryEmail.new, to: [OrderPlaced]).call
  • Deprecate: subscribe_to_all_events(subscriber, &task) has been deprecated. Use within(&task).subscribe_to_all_events(subscriber).call instead. #155 - Example:

    client = RailsEventStore::Client.new
    client.within do
      PlaceOrder.new
    end.subscribe_to_all_events(LogEvents.new).call
  • Fix: Temporary subscribers are thread safe now - #196

  • Fix: Test the gem with newest Rails version. No changes required but the testing infrastructure - #192 #194

  • Add: subscribe(to:, &subscriber) API allows passing a subscriber as proc. - #155 #197 - Example:

    client = RailsEventStore::Client.new
    client.subscribe(to: [OrderPlaced]) do |ev|
      order = Order.find(event.data.fetch(:event_id))
      OrderMailer.summary(order).deliver_later
    end
  • Add: subscribe_to_all_events(&subscriber) API allows passing a subscriber as proc. - #155 #197 - Example:

    client = RailsEventStore::Client.new
    client.subscribe_to_all_events do |ev|
      Rails.logger.debug(ev.inspect)
    end
  • Add: Chainable API for temporary subscribers was added. Start with within(&task) then call subscribe or subscribe_to_all_events as many times you want passing either a handler or a block and then call call to trigger execution of the task with subscribers temporarily subscribed. - #155 #197 - Example:

    success = 0
    failure = 0
    
    client.within do
      ImportCustomer.call
    end.subscribe(to: [CustomerImported]) do |_ev|
      success += 1
    end.subscribe(to: [CustomerImportFailed]) do |_ev|
      failure += 1
    end.subscribe_to_all_events do |ev|
      Rails.logger.debug(ev.inspect)
    end.call

RubyEventStore

  • Deprecate/Add: Same API changes as for RailsEventStore listed above.
  • Fix: No more race conditions for InMemoryAdapter with multi-threading when used with :any expected version on the same stream. This more closely resembles production behavior of RailsEventStoreActiveRecord repository. #188

RailsEventStoreActiveRecord

  • Fix: Testing the gem with newest Rails version - #194

AggregateRoot

  • Add: Support for declarative event handler methods - #171 #190 . You can use on(event_class, &proc) to define a new handler method. Example:

    class Order
      include AggregateRoot
      class HasBeenAlreadySubmitted < StandardError; end
      class HasExpired < StandardError; end
    
      def initialize
        @state = :new
      end
    
      def submit
        raise HasBeenAlreadySubmitted if state == :submitted
        raise HasExpired if state == :expired
        apply OrderSubmitted.new(data: {delivery_date: Time.now + 24.hours})
      end
    
      def expire
        apply OrderExpired.new
      end
    
      on OrderSubmitted do |event|
        @state = :submitted
        @delivery_date = event.data.fetch(:delivery_date)
      end
    
      on OrderExpired do |_event|
        @state = :expired
      end
    
      private
    
      attr_reader :state
    end

RailsEventStore::RSpec

  • No changes

BoundedContext

  • Fix: Testing the gem with newest Rails version - #192

RailsEventStore::Browser

  • No changes

v0.25.2

10 Feb 01:28
Compare
Choose a tag to compare

RailsEventStore

  • no changes

RubyEventStore

  • no changes

RailsEventStoreActiveRecord

  • no changes

AggregateRoot

  • no changes

RailsEventStore::RSpec

  • no changes

BoundedContext

  • no changes

RailsEventStore::Browser

  • Fix: Excessive encoding of already encoded URLs is no more.
  • Fix: Handle dots in stream names on browser backend. Previously last dot part of name could have been interpreted as a format.

v0.25.1

10 Feb 00:49
Compare
Choose a tag to compare

RailsEventStore

  • no changes

RubyEventStore

  • no changes

RailsEventStoreActiveRecord

  • no changes

AggregateRoot

  • no changes

RailsEventStore::RSpec

  • no changes

BoundedContext

  • no changes

RailsEventStore::Browser

  • Fix: Encode stream names and event ids for internal links. An unescaped URL with slashes would be incorrectly interpreted by client-side router.