ruby_event_store 1.2.2 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +3 -1
- data/lib/ruby_event_store.rb +3 -7
- data/lib/ruby_event_store/broker.rb +3 -3
- data/lib/ruby_event_store/client.rb +47 -23
- data/lib/ruby_event_store/composed_dispatcher.rb +2 -2
- data/lib/ruby_event_store/constants.rb +1 -0
- data/lib/ruby_event_store/errors.rb +0 -1
- data/lib/ruby_event_store/event.rb +8 -1
- data/lib/ruby_event_store/immediate_async_dispatcher.rb +2 -2
- data/lib/ruby_event_store/in_memory_repository.rb +98 -59
- data/lib/ruby_event_store/instrumented_dispatcher.rb +2 -2
- data/lib/ruby_event_store/instrumented_repository.rb +3 -3
- data/lib/ruby_event_store/mappers/default.rb +3 -8
- data/lib/ruby_event_store/mappers/encryption_mapper.rb +3 -4
- data/lib/ruby_event_store/mappers/instrumented_mapper.rb +4 -4
- data/lib/ruby_event_store/mappers/json_mapper.rb +7 -7
- data/lib/ruby_event_store/mappers/pipeline.rb +2 -5
- data/lib/ruby_event_store/mappers/pipeline_mapper.rb +2 -2
- data/lib/ruby_event_store/mappers/transformation/domain_event.rb +16 -8
- data/lib/ruby_event_store/mappers/transformation/encryption.rb +20 -12
- data/lib/ruby_event_store/mappers/transformation/event_class_remapper.rb +11 -4
- data/lib/ruby_event_store/mappers/transformation/stringify_metadata_keys.rb +12 -7
- data/lib/ruby_event_store/mappers/transformation/symbolize_metadata_keys.rb +12 -7
- data/lib/ruby_event_store/mappers/transformation/upcast.rb +37 -0
- data/lib/ruby_event_store/null.rb +13 -0
- data/lib/ruby_event_store/projection.rb +2 -1
- data/lib/ruby_event_store/record.rb +68 -0
- data/lib/ruby_event_store/serialized_record.rb +23 -4
- data/lib/ruby_event_store/spec/broker_lint.rb +9 -9
- data/lib/ruby_event_store/spec/event_repository_lint.rb +267 -105
- data/lib/ruby_event_store/spec/mapper_lint.rb +6 -6
- data/lib/ruby_event_store/spec/subscriptions_lint.rb +25 -0
- data/lib/ruby_event_store/specification.rb +100 -7
- data/lib/ruby_event_store/specification_reader.rb +2 -2
- data/lib/ruby_event_store/specification_result.rb +86 -2
- data/lib/ruby_event_store/subscriptions.rb +23 -9
- data/lib/ruby_event_store/transform_keys.rb +5 -5
- data/lib/ruby_event_store/version.rb +1 -1
- metadata +15 -21
- data/CHANGELOG.md +0 -93
- data/Gemfile +0 -11
- data/Makefile +0 -22
- data/lib/ruby_event_store/mappers/protobuf.rb +0 -24
- data/lib/ruby_event_store/mappers/transformation/item.rb +0 -56
- data/lib/ruby_event_store/mappers/transformation/proto_event.rb +0 -17
- data/lib/ruby_event_store/mappers/transformation/protobuf_encoder.rb +0 -30
- data/lib/ruby_event_store/mappers/transformation/protobuf_nested_struct_metadata.rb +0 -30
- data/lib/ruby_event_store/mappers/transformation/serialization.rb +0 -34
- data/lib/ruby_event_store/mappers/transformation/serialized_record.rb +0 -27
- data/ruby_event_store.gemspec +0 -29
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 88203a9b943002241df25fa83c6f067e7944810e66d713eeb11e8cebf13271e2
         | 
| 4 | 
            +
              data.tar.gz: 1b032e898517d787a2e6d0cb6b15775792591abc094e68d2483590f916e69c9e
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 780c9e0f6064311d45be29c0553c47e65e679a3967b91e6caca48a55ef9c34a06070e421b1413c1a35634c6e45c1452204ac29fae2aa706fe7a0e46d1dd99f40
         | 
| 7 | 
            +
              data.tar.gz: 66b7a11ce2d3b58a5f9c2690a7f7f998fc9130c302343923cdd5a57a63d6a398ea258cced2d1b3161e07d9fb081d04bd7c4f305d6576cae59bd6e50f50ba6a92
         | 
    
        data/README.md
    CHANGED
    
    | @@ -1,3 +1,5 @@ | |
| 1 1 | 
             
            # RubyEventStore
         | 
| 2 2 |  | 
| 3 | 
            -
             | 
| 3 | 
            +
            Ruby implementation of an event store. Ships with in-memory event repository, generic instrumentation and dispatches events synchronously.
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            Find out more at [https://railseventstore.org](https://railseventstore.org/)
         | 
    
        data/lib/ruby_event_store.rb
    CHANGED
    
    | @@ -15,19 +15,16 @@ require 'ruby_event_store/specification_reader' | |
| 15 15 | 
             
            require 'ruby_event_store/event'
         | 
| 16 16 | 
             
            require 'ruby_event_store/stream'
         | 
| 17 17 | 
             
            require 'ruby_event_store/expected_version'
         | 
| 18 | 
            +
            require 'ruby_event_store/record'
         | 
| 18 19 | 
             
            require 'ruby_event_store/serialized_record'
         | 
| 20 | 
            +
            require 'ruby_event_store/null'
         | 
| 19 21 | 
             
            require 'ruby_event_store/transform_keys'
         | 
| 20 22 | 
             
            require 'ruby_event_store/mappers/encryption_key'
         | 
| 21 23 | 
             
            require 'ruby_event_store/mappers/in_memory_encryption_key_repository'
         | 
| 22 24 | 
             
            require 'ruby_event_store/mappers/transformation/domain_event'
         | 
| 23 25 | 
             
            require 'ruby_event_store/mappers/transformation/encryption'
         | 
| 24 26 | 
             
            require 'ruby_event_store/mappers/transformation/event_class_remapper'
         | 
| 25 | 
            -
            require 'ruby_event_store/mappers/transformation/ | 
| 26 | 
            -
            require 'ruby_event_store/mappers/transformation/proto_event'
         | 
| 27 | 
            -
            require 'ruby_event_store/mappers/transformation/protobuf_encoder'
         | 
| 28 | 
            -
            require 'ruby_event_store/mappers/transformation/protobuf_nested_struct_metadata'
         | 
| 29 | 
            -
            require 'ruby_event_store/mappers/transformation/serialization'
         | 
| 30 | 
            -
            require 'ruby_event_store/mappers/transformation/serialized_record'
         | 
| 27 | 
            +
            require 'ruby_event_store/mappers/transformation/upcast'
         | 
| 31 28 | 
             
            require 'ruby_event_store/mappers/transformation/stringify_metadata_keys'
         | 
| 32 29 | 
             
            require 'ruby_event_store/mappers/transformation/symbolize_metadata_keys'
         | 
| 33 30 | 
             
            require 'ruby_event_store/mappers/pipeline'
         | 
| @@ -38,7 +35,6 @@ require 'ruby_event_store/mappers/encryption_mapper' | |
| 38 35 | 
             
            require 'ruby_event_store/mappers/instrumented_mapper'
         | 
| 39 36 | 
             
            require 'ruby_event_store/mappers/json_mapper'
         | 
| 40 37 | 
             
            require 'ruby_event_store/mappers/null_mapper'
         | 
| 41 | 
            -
            require 'ruby_event_store/mappers/protobuf'
         | 
| 42 38 | 
             
            require 'ruby_event_store/batch_enumerator'
         | 
| 43 39 | 
             
            require 'ruby_event_store/correlated_commands'
         | 
| 44 40 | 
             
            require 'ruby_event_store/link_by_metadata'
         | 
| @@ -7,10 +7,10 @@ module RubyEventStore | |
| 7 7 | 
             
                  @dispatcher = dispatcher
         | 
| 8 8 | 
             
                end
         | 
| 9 9 |  | 
| 10 | 
            -
                def call(event,  | 
| 10 | 
            +
                def call(event, record)
         | 
| 11 11 | 
             
                  subscribers = subscriptions.all_for(event.event_type)
         | 
| 12 12 | 
             
                  subscribers.each do |subscriber|
         | 
| 13 | 
            -
                    dispatcher.call(subscriber, event,  | 
| 13 | 
            +
                    dispatcher.call(subscriber, event, record)
         | 
| 14 14 | 
             
                  end
         | 
| 15 15 | 
             
                end
         | 
| 16 16 |  | 
| @@ -35,7 +35,7 @@ module RubyEventStore | |
| 35 35 | 
             
                end
         | 
| 36 36 |  | 
| 37 37 | 
             
                private
         | 
| 38 | 
            -
                attr_reader : | 
| 38 | 
            +
                attr_reader :dispatcher, :subscriptions
         | 
| 39 39 |  | 
| 40 40 | 
             
                def verify_subscription(subscriber)
         | 
| 41 41 | 
             
                  raise SubscriberNotExist, "subscriber must be first argument or block" unless subscriber
         | 
| @@ -10,8 +10,11 @@ module RubyEventStore | |
| 10 10 | 
             
                               dispatcher: Dispatcher.new,
         | 
| 11 11 | 
             
                               clock: default_clock,
         | 
| 12 12 | 
             
                               correlation_id_generator: default_correlation_id_generator)
         | 
| 13 | 
            +
             | 
| 14 | 
            +
             | 
| 13 15 | 
             
                  @repository     = repository
         | 
| 14 16 | 
             
                  @mapper         = mapper
         | 
| 17 | 
            +
                  @subscriptions  = subscriptions
         | 
| 15 18 | 
             
                  @broker         = Broker.new(subscriptions: subscriptions, dispatcher: dispatcher)
         | 
| 16 19 | 
             
                  @clock          = clock
         | 
| 17 20 | 
             
                  @metadata       = Concurrent::ThreadLocalVar.new
         | 
| @@ -21,20 +24,20 @@ module RubyEventStore | |
| 21 24 |  | 
| 22 25 | 
             
                # Persists events and notifies subscribed handlers about them
         | 
| 23 26 | 
             
                #
         | 
| 24 | 
            -
                # @param events [Array<Event | 
| 27 | 
            +
                # @param events [Array<Event>, Event] event(s)
         | 
| 25 28 | 
             
                # @param stream_name [String] name of the stream for persisting events.
         | 
| 26 29 | 
             
                # @param expected_version [:any, :auto, :none, Integer] controls optimistic locking strategy. {http://railseventstore.org/docs/expected_version/ Read more}
         | 
| 27 30 | 
             
                # @return [self]
         | 
| 28 31 | 
             
                def publish(events, stream_name: GLOBAL_STREAM, expected_version: :any)
         | 
| 29 32 | 
             
                  enriched_events = enrich_events_metadata(events)
         | 
| 30 | 
            -
                   | 
| 31 | 
            -
                   | 
| 32 | 
            -
                  enriched_events.zip( | 
| 33 | 
            +
                  records         = transform(enriched_events)
         | 
| 34 | 
            +
                  append_records_to_stream(records, stream_name: stream_name, expected_version: expected_version)
         | 
| 35 | 
            +
                  enriched_events.zip(records) do |event, record|
         | 
| 33 36 | 
             
                    with_metadata(
         | 
| 34 37 | 
             
                      correlation_id: event.metadata.fetch(:correlation_id),
         | 
| 35 38 | 
             
                      causation_id:   event.event_id,
         | 
| 36 39 | 
             
                    ) do
         | 
| 37 | 
            -
                      broker.(event,  | 
| 40 | 
            +
                      broker.(event, record)
         | 
| 38 41 | 
             
                    end
         | 
| 39 42 | 
             
                  end
         | 
| 40 43 | 
             
                  self
         | 
| @@ -45,8 +48,11 @@ module RubyEventStore | |
| 45 48 | 
             
                # @param (see #publish)
         | 
| 46 49 | 
             
                # @return [self]
         | 
| 47 50 | 
             
                def append(events, stream_name: GLOBAL_STREAM, expected_version: :any)
         | 
| 48 | 
            -
                   | 
| 49 | 
            -
             | 
| 51 | 
            +
                  append_records_to_stream(
         | 
| 52 | 
            +
                    transform(enrich_events_metadata(events)),
         | 
| 53 | 
            +
                    stream_name: stream_name,
         | 
| 54 | 
            +
                    expected_version: expected_version
         | 
| 55 | 
            +
                  )
         | 
| 50 56 | 
             
                  self
         | 
| 51 57 | 
             
                end
         | 
| 52 58 |  | 
| @@ -58,7 +64,7 @@ module RubyEventStore | |
| 58 64 | 
             
                # @param expected_version (see #publish)
         | 
| 59 65 | 
             
                # @return [self]
         | 
| 60 66 | 
             
                def link(event_ids, stream_name:, expected_version: :any)
         | 
| 61 | 
            -
                  repository.link_to_stream(event_ids, Stream.new(stream_name), ExpectedVersion.new(expected_version))
         | 
| 67 | 
            +
                  repository.link_to_stream(Array(event_ids), Stream.new(stream_name), ExpectedVersion.new(expected_version))
         | 
| 62 68 | 
             
                  self
         | 
| 63 69 | 
             
                end
         | 
| 64 70 |  | 
| @@ -121,6 +127,14 @@ module RubyEventStore | |
| 121 127 | 
             
                  broker.add_global_subscription(subscriber || proc)
         | 
| 122 128 | 
             
                end
         | 
| 123 129 |  | 
| 130 | 
            +
                # Get list of handlers subscribed to an event
         | 
| 131 | 
            +
                #
         | 
| 132 | 
            +
                # @param to [Class, String] type of events to get list of sybscribed handlers
         | 
| 133 | 
            +
                # @return [Array<Object, Class>]
         | 
| 134 | 
            +
                def subscribers_for(event_type)
         | 
| 135 | 
            +
                  subscriptions.all_for(event_type)
         | 
| 136 | 
            +
                end
         | 
| 137 | 
            +
             | 
| 124 138 | 
             
                # Builder object for collecting temporary handlers (subscribers)
         | 
| 125 139 | 
             
                # which are active only during the invocation of the provided
         | 
| 126 140 | 
             
                # block of code.
         | 
| @@ -222,9 +236,22 @@ module RubyEventStore | |
| 222 236 | 
             
                # Deserialize event which was serialized for async event handlers
         | 
| 223 237 | 
             
                # {http://railseventstore.org/docs/subscribe/#async-handlers Read more}
         | 
| 224 238 | 
             
                #
         | 
| 225 | 
            -
                # @return [Event | 
| 226 | 
            -
                def deserialize(event_type:, event_id:, data:, metadata:)
         | 
| 227 | 
            -
                   | 
| 239 | 
            +
                # @return [Event] deserialized event
         | 
| 240 | 
            +
                def deserialize(serializer:, event_type:, event_id:, data:, metadata:, timestamp: nil, valid_at: nil)
         | 
| 241 | 
            +
                  extract_timestamp = lambda do |m|
         | 
| 242 | 
            +
                    (m[:timestamp] || Time.parse(m.fetch('timestamp'))).iso8601
         | 
| 243 | 
            +
                  end
         | 
| 244 | 
            +
             | 
| 245 | 
            +
                  mapper.record_to_event(
         | 
| 246 | 
            +
                    SerializedRecord.new(
         | 
| 247 | 
            +
                      event_type: event_type,
         | 
| 248 | 
            +
                      event_id:   event_id,
         | 
| 249 | 
            +
                      data:       data,
         | 
| 250 | 
            +
                      metadata:   metadata,
         | 
| 251 | 
            +
                      timestamp:  timestamp || timestamp_ = extract_timestamp[serializer.load(metadata)],
         | 
| 252 | 
            +
                      valid_at:   valid_at  || timestamp_,
         | 
| 253 | 
            +
                    ).deserialize(serializer)
         | 
| 254 | 
            +
                  )
         | 
| 228 255 | 
             
                end
         | 
| 229 256 |  | 
| 230 257 | 
             
                # Read additional metadata which will be added for published events
         | 
| @@ -262,12 +289,10 @@ module RubyEventStore | |
| 262 289 | 
             
                #   end
         | 
| 263 290 | 
             
                #   event_store.overwrite(events)
         | 
| 264 291 | 
             
                #
         | 
| 265 | 
            -
                # @param events [Array<Event | 
| 292 | 
            +
                # @param events [Array<Event>, Event] event(s) to serialize and overwrite again
         | 
| 266 293 | 
             
                # @return [self]
         | 
| 267 294 | 
             
                def overwrite(events_or_event)
         | 
| 268 | 
            -
                   | 
| 269 | 
            -
                  serialized_events = serialize_events(events)
         | 
| 270 | 
            -
                  repository.update_messages(serialized_events)
         | 
| 295 | 
            +
                  repository.update_messages(transform(Array(events_or_event)))
         | 
| 271 296 | 
             
                  self
         | 
| 272 297 | 
             
                end
         | 
| 273 298 |  | 
| @@ -280,10 +305,8 @@ module RubyEventStore | |
| 280 305 |  | 
| 281 306 | 
             
                private
         | 
| 282 307 |  | 
| 283 | 
            -
                def  | 
| 284 | 
            -
                  events.map  | 
| 285 | 
            -
                    mapper.event_to_serialized_record(ev)
         | 
| 286 | 
            -
                  end
         | 
| 308 | 
            +
                def transform(events)
         | 
| 309 | 
            +
                  events.map { |ev| mapper.event_to_record(ev) }
         | 
| 287 310 | 
             
                end
         | 
| 288 311 |  | 
| 289 312 | 
             
                def enrich_events_metadata(events)
         | 
| @@ -295,11 +318,12 @@ module RubyEventStore | |
| 295 318 | 
             
                def enrich_event_metadata(event)
         | 
| 296 319 | 
             
                  metadata.each { |key, value| event.metadata[key] ||= value }
         | 
| 297 320 | 
             
                  event.metadata[:timestamp]      ||= clock.call
         | 
| 321 | 
            +
                  event.metadata[:valid_at]       ||= event.metadata.fetch(:timestamp)
         | 
| 298 322 | 
             
                  event.metadata[:correlation_id] ||= correlation_id_generator.call
         | 
| 299 323 | 
             
                end
         | 
| 300 324 |  | 
| 301 | 
            -
                def  | 
| 302 | 
            -
                  repository.append_to_stream( | 
| 325 | 
            +
                def append_records_to_stream(records, stream_name:, expected_version:)
         | 
| 326 | 
            +
                  repository.append_to_stream(records, Stream.new(stream_name), ExpectedVersion.new(expected_version))
         | 
| 303 327 | 
             
                end
         | 
| 304 328 |  | 
| 305 329 | 
             
                protected
         | 
| @@ -309,13 +333,13 @@ module RubyEventStore | |
| 309 333 | 
             
                end
         | 
| 310 334 |  | 
| 311 335 | 
             
                def default_clock
         | 
| 312 | 
            -
                  ->{ Time.now.utc }
         | 
| 336 | 
            +
                  ->{ Time.now.utc.round(TIMESTAMP_PRECISION) }
         | 
| 313 337 | 
             
                end
         | 
| 314 338 |  | 
| 315 339 | 
             
                def default_correlation_id_generator
         | 
| 316 340 | 
             
                  ->{ SecureRandom.uuid }
         | 
| 317 341 | 
             
                end
         | 
| 318 342 |  | 
| 319 | 
            -
                attr_reader :repository, :mapper, :broker, :clock, :correlation_id_generator
         | 
| 343 | 
            +
                attr_reader :repository, :mapper, :subscriptions, :broker, :clock, :correlation_id_generator
         | 
| 320 344 | 
             
              end
         | 
| 321 345 | 
             
            end
         | 
| @@ -6,10 +6,10 @@ module RubyEventStore | |
| 6 6 | 
             
                  @dispatchers = dispatchers
         | 
| 7 7 | 
             
                end
         | 
| 8 8 |  | 
| 9 | 
            -
                def call(subscriber, event,  | 
| 9 | 
            +
                def call(subscriber, event, record)
         | 
| 10 10 | 
             
                  @dispatchers.each do |dispatcher|
         | 
| 11 11 | 
             
                    if dispatcher.verify(subscriber)
         | 
| 12 | 
            -
                      dispatcher.call(subscriber, event,  | 
| 12 | 
            +
                      dispatcher.call(subscriber, event, record)
         | 
| 13 13 | 
             
                      break
         | 
| 14 14 | 
             
                    end
         | 
| 15 15 | 
             
                  end
         | 
| @@ -41,6 +41,13 @@ module RubyEventStore | |
| 41 41 | 
             
                  metadata[:timestamp]
         | 
| 42 42 | 
             
                end
         | 
| 43 43 |  | 
| 44 | 
            +
                # Validity time from metadata
         | 
| 45 | 
            +
                #
         | 
| 46 | 
            +
                # @return [Time, nil]
         | 
| 47 | 
            +
                def valid_at
         | 
| 48 | 
            +
                  metadata[:valid_at]
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
             | 
| 44 51 | 
             
                # Two events are equal if:
         | 
| 45 52 | 
             
                # * they are of the same class
         | 
| 46 53 | 
             
                # * have identical event id
         | 
| @@ -116,7 +123,7 @@ module RubyEventStore | |
| 116 123 | 
             
                # on correlation_id and message_id of the provided message.
         | 
| 117 124 | 
             
                # {http://railseventstore.org/docs/correlation_causation/ Find out more}
         | 
| 118 125 | 
             
                #
         | 
| 119 | 
            -
                # @param other_message [Event,  | 
| 126 | 
            +
                # @param other_message [Event, command] message to correlate with. Most likely an event or a command. Must respond to correlation_id and message_id.
         | 
| 120 127 | 
             
                # @return [String] set causation_id
         | 
| 121 128 | 
             
                def correlate_with(other_message)
         | 
| 122 129 | 
             
                  self.correlation_id = other_message.correlation_id || other_message.message_id
         | 
| @@ -4,19 +4,40 @@ require 'ostruct' | |
| 4 4 | 
             
            module RubyEventStore
         | 
| 5 5 | 
             
              class InMemoryRepository
         | 
| 6 6 |  | 
| 7 | 
            -
                def initialize
         | 
| 8 | 
            -
                  @ | 
| 9 | 
            -
                  @ | 
| 10 | 
            -
                  @ | 
| 7 | 
            +
                def initialize(serializer: NULL)
         | 
| 8 | 
            +
                  @serializer = serializer
         | 
| 9 | 
            +
                  @streams = Hash.new { |h, k| h[k] = Array.new }
         | 
| 10 | 
            +
                  @mutex   = Mutex.new
         | 
| 11 | 
            +
                  @storage = Hash.new
         | 
| 11 12 | 
             
                end
         | 
| 12 13 |  | 
| 13 | 
            -
                def append_to_stream( | 
| 14 | 
            -
                   | 
| 14 | 
            +
                def append_to_stream(records, stream, expected_version)
         | 
| 15 | 
            +
                  serialized_records = records.map { |record| record.serialize(serializer) }
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  with_synchronize(expected_version, stream) do |resolved_version|
         | 
| 18 | 
            +
                    raise WrongExpectedEventVersion unless last_stream_version(stream).equal?(resolved_version)
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                    serialized_records.each do |serialized_record|
         | 
| 21 | 
            +
                      raise EventDuplicatedInStream if has_event?(serialized_record.event_id)
         | 
| 22 | 
            +
                      storage[serialized_record.event_id] = serialized_record
         | 
| 23 | 
            +
                      streams[stream.name] << serialized_record.event_id
         | 
| 24 | 
            +
                    end
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
                  self
         | 
| 15 27 | 
             
                end
         | 
| 16 28 |  | 
| 17 29 | 
             
                def link_to_stream(event_ids, stream, expected_version)
         | 
| 18 | 
            -
                   | 
| 19 | 
            -
             | 
| 30 | 
            +
                  serialized_records = event_ids.map { |id| read_event(id) }
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  with_synchronize(expected_version, stream) do |resolved_version|
         | 
| 33 | 
            +
                    raise WrongExpectedEventVersion unless last_stream_version(stream).equal?(resolved_version)
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                    serialized_records.each do |serialized_record|
         | 
| 36 | 
            +
                      raise EventDuplicatedInStream if has_event_in_stream?(serialized_record.event_id, stream.name)
         | 
| 37 | 
            +
                      streams[stream.name] << serialized_record.event_id
         | 
| 38 | 
            +
                    end
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
                  self
         | 
| 20 41 | 
             
                end
         | 
| 21 42 |  | 
| 22 43 | 
             
                def delete_stream(stream)
         | 
| @@ -24,24 +45,34 @@ module RubyEventStore | |
| 24 45 | 
             
                end
         | 
| 25 46 |  | 
| 26 47 | 
             
                def has_event?(event_id)
         | 
| 27 | 
            -
             | 
| 48 | 
            +
                  storage.has_key?(event_id)
         | 
| 28 49 | 
             
                end
         | 
| 29 50 |  | 
| 30 51 | 
             
                def last_stream_event(stream)
         | 
| 31 | 
            -
                   | 
| 52 | 
            +
                  last_id = event_ids_of_stream(stream).last
         | 
| 53 | 
            +
                  storage.fetch(last_id).deserialize(serializer) if last_id
         | 
| 32 54 | 
             
                end
         | 
| 33 55 |  | 
| 34 56 | 
             
                def read(spec)
         | 
| 35 | 
            -
                   | 
| 57 | 
            +
                  serialized_records = read_scope(spec)
         | 
| 36 58 | 
             
                  if spec.batched?
         | 
| 37 | 
            -
                    batch_reader = ->(offset, limit)  | 
| 38 | 
            -
             | 
| 59 | 
            +
                    batch_reader = ->(offset, limit) do
         | 
| 60 | 
            +
                      serialized_records
         | 
| 61 | 
            +
                        .drop(offset)
         | 
| 62 | 
            +
                        .take(limit)
         | 
| 63 | 
            +
                        .map { |serialized_record| serialized_record.deserialize(serializer) }
         | 
| 64 | 
            +
                    end
         | 
| 65 | 
            +
                    BatchEnumerator.new(spec.batch_size, serialized_records.size, batch_reader).each
         | 
| 39 66 | 
             
                  elsif spec.first?
         | 
| 40 | 
            -
                     | 
| 67 | 
            +
                    serialized_records.first&.deserialize(serializer)
         | 
| 41 68 | 
             
                  elsif spec.last?
         | 
| 42 | 
            -
                     | 
| 69 | 
            +
                    serialized_records.last&.deserialize(serializer)
         | 
| 43 70 | 
             
                  else
         | 
| 44 | 
            -
                     | 
| 71 | 
            +
                    Enumerator.new do |y|
         | 
| 72 | 
            +
                      serialized_records.each do |serialized_record|
         | 
| 73 | 
            +
                        y << serialized_record.deserialize(serializer)
         | 
| 74 | 
            +
                      end
         | 
| 75 | 
            +
                    end
         | 
| 45 76 | 
             
                  end
         | 
| 46 77 | 
             
                end
         | 
| 47 78 |  | 
| @@ -49,53 +80,73 @@ module RubyEventStore | |
| 49 80 | 
             
                  read_scope(spec).count
         | 
| 50 81 | 
             
                end
         | 
| 51 82 |  | 
| 52 | 
            -
                def update_messages( | 
| 53 | 
            -
                   | 
| 54 | 
            -
                     | 
| 55 | 
            -
                     | 
| 56 | 
            -
             | 
| 57 | 
            -
             | 
| 58 | 
            -
             | 
| 59 | 
            -
             | 
| 60 | 
            -
             | 
| 83 | 
            +
                def update_messages(records)
         | 
| 84 | 
            +
                  records.each do |record|
         | 
| 85 | 
            +
                    read_event(record.event_id)
         | 
| 86 | 
            +
                    serialized_record =
         | 
| 87 | 
            +
                      Record.new(
         | 
| 88 | 
            +
                        event_id:   record.event_id,
         | 
| 89 | 
            +
                        event_type: record.event_type,
         | 
| 90 | 
            +
                        data:       record.data,
         | 
| 91 | 
            +
                        metadata:   record.metadata,
         | 
| 92 | 
            +
                        timestamp:  Time.iso8601(storage.fetch(record.event_id).timestamp),
         | 
| 93 | 
            +
                        valid_at:   record.valid_at,
         | 
| 94 | 
            +
                      ).serialize(serializer)
         | 
| 95 | 
            +
                    storage[record.event_id] = serialized_record
         | 
| 61 96 | 
             
                  end
         | 
| 62 97 | 
             
                end
         | 
| 63 98 |  | 
| 64 99 | 
             
                def streams_of(event_id)
         | 
| 65 | 
            -
                  streams | 
| 66 | 
            -
                     | 
| 67 | 
            -
             | 
| 100 | 
            +
                  streams
         | 
| 101 | 
            +
                    .select { |name,| has_event_in_stream?(event_id, name) }
         | 
| 102 | 
            +
                    .map    { |name,| Stream.new(name) }
         | 
| 68 103 | 
             
                end
         | 
| 69 104 |  | 
| 70 105 | 
             
                private
         | 
| 71 106 | 
             
                def read_scope(spec)
         | 
| 72 | 
            -
                   | 
| 73 | 
            -
                   | 
| 74 | 
            -
                   | 
| 75 | 
            -
                   | 
| 76 | 
            -
                   | 
| 77 | 
            -
                   | 
| 78 | 
            -
                   | 
| 79 | 
            -
                   | 
| 107 | 
            +
                  serialized_records = serialized_records_of_stream(spec.stream)
         | 
| 108 | 
            +
                  serialized_records = ordered(serialized_records, spec)
         | 
| 109 | 
            +
                  serialized_records = serialized_records.select{|e| spec.with_ids.any?{|x| x.eql?(e.event_id)}} if spec.with_ids?
         | 
| 110 | 
            +
                  serialized_records = serialized_records.select{|e| spec.with_types.any?{|x| x.eql?(e.event_type)}} if spec.with_types?
         | 
| 111 | 
            +
                  serialized_records = serialized_records.reverse if spec.backward?
         | 
| 112 | 
            +
                  serialized_records = serialized_records.drop(index_of(serialized_records, spec.start) + 1) if spec.start
         | 
| 113 | 
            +
                  serialized_records = serialized_records.take(index_of(serialized_records, spec.stop)) if spec.stop
         | 
| 114 | 
            +
                  serialized_records = serialized_records.take(spec.limit) if spec.limit?
         | 
| 115 | 
            +
                  serialized_records = serialized_records.select { |sr| Time.iso8601(sr.timestamp) < spec.older_than } if spec.older_than
         | 
| 116 | 
            +
                  serialized_records = serialized_records.select { |sr| Time.iso8601(sr.timestamp) <= spec.older_than_or_equal } if spec.older_than_or_equal
         | 
| 117 | 
            +
                  serialized_records = serialized_records.select { |sr| Time.iso8601(sr.timestamp) > spec.newer_than } if spec.newer_than
         | 
| 118 | 
            +
                  serialized_records = serialized_records.select { |sr| Time.iso8601(sr.timestamp) >= spec.newer_than_or_equal } if spec.newer_than_or_equal
         | 
| 119 | 
            +
                  serialized_records
         | 
| 80 120 | 
             
                end
         | 
| 81 121 |  | 
| 82 122 | 
             
                def read_event(event_id)
         | 
| 83 | 
            -
                   | 
| 123 | 
            +
                  storage.fetch(event_id) { raise EventNotFound.new(event_id) }
         | 
| 84 124 | 
             
                end
         | 
| 85 125 |  | 
| 86 | 
            -
                def  | 
| 87 | 
            -
                  streams.fetch(name, Array.new)
         | 
| 126 | 
            +
                def event_ids_of_stream(stream)
         | 
| 127 | 
            +
                  streams.fetch(stream.name, Array.new)
         | 
| 88 128 | 
             
                end
         | 
| 89 129 |  | 
| 90 | 
            -
                def  | 
| 91 | 
            -
                   | 
| 130 | 
            +
                def serialized_records_of_stream(stream)
         | 
| 131 | 
            +
                  stream.global? ? storage.values : storage.fetch_values(*event_ids_of_stream(stream))
         | 
| 132 | 
            +
                end
         | 
| 133 | 
            +
             | 
| 134 | 
            +
                def ordered(serialized_records, spec)
         | 
| 135 | 
            +
                  case spec.time_sort_by
         | 
| 136 | 
            +
                  when :as_at
         | 
| 137 | 
            +
                    serialized_records.sort_by(&:timestamp)
         | 
| 138 | 
            +
                  when :as_of
         | 
| 139 | 
            +
                    serialized_records.sort_by(&:valid_at)
         | 
| 140 | 
            +
                  else
         | 
| 141 | 
            +
                    serialized_records
         | 
| 142 | 
            +
                  end
         | 
| 92 143 | 
             
                end
         | 
| 93 144 |  | 
| 94 145 | 
             
                def last_stream_version(stream)
         | 
| 95 | 
            -
                   | 
| 146 | 
            +
                  event_ids_of_stream(stream).size - 1
         | 
| 96 147 | 
             
                end
         | 
| 97 148 |  | 
| 98 | 
            -
                def  | 
| 149 | 
            +
                def with_synchronize(expected_version, stream, &block)
         | 
| 99 150 | 
             
                  resolved_version = expected_version.resolve_for(stream, method(:last_stream_version))
         | 
| 100 151 |  | 
| 101 152 | 
             
                  # expected_version :auto assumes external lock is used
         | 
| @@ -108,30 +159,18 @@ module RubyEventStore | |
| 108 159 | 
             
                  Thread.pass
         | 
| 109 160 | 
             
                  mutex.synchronize do
         | 
| 110 161 | 
             
                    resolved_version = last_stream_version(stream) if expected_version.any?
         | 
| 111 | 
            -
                     | 
| 162 | 
            +
                    block.call(resolved_version)
         | 
| 112 163 | 
             
                  end
         | 
| 113 164 | 
             
                end
         | 
| 114 165 |  | 
| 115 | 
            -
                def  | 
| 116 | 
            -
                   | 
| 117 | 
            -
                  raise WrongExpectedEventVersion unless last_stream_version(stream).equal?(resolved_version)
         | 
| 118 | 
            -
             | 
| 119 | 
            -
                  events.each do |event|
         | 
| 120 | 
            -
                    raise EventDuplicatedInStream if stream_events.any? {|ev| ev.event_id.eql?(event.event_id)}
         | 
| 121 | 
            -
                    if include_global
         | 
| 122 | 
            -
                      raise EventDuplicatedInStream if has_event?(event.event_id)
         | 
| 123 | 
            -
                      global.push(event)
         | 
| 124 | 
            -
                    end
         | 
| 125 | 
            -
                    stream_events.push(event)
         | 
| 126 | 
            -
                  end
         | 
| 127 | 
            -
                  streams[stream.name] = stream_events
         | 
| 128 | 
            -
                  self
         | 
| 166 | 
            +
                def has_event_in_stream?(event_id, stream_name)
         | 
| 167 | 
            +
                  streams.fetch(stream_name, Array.new).any? { |id| id.eql?(event_id) }
         | 
| 129 168 | 
             
                end
         | 
| 130 169 |  | 
| 131 170 | 
             
                def index_of(source, event_id)
         | 
| 132 171 | 
             
                  source.index {|item| item.event_id.eql?(event_id)}
         | 
| 133 172 | 
             
                end
         | 
| 134 173 |  | 
| 135 | 
            -
                attr_reader :streams, :mutex, : | 
| 174 | 
            +
                attr_reader :streams, :mutex, :storage, :serializer
         | 
| 136 175 | 
             
              end
         | 
| 137 176 | 
             
            end
         |