eventsimple 1.2.0 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c32b996ad44adbf1ae144adaa855a70d23c68286ff64e3bc633f8af98517c1f6
4
- data.tar.gz: 8de726b86bb3fcd0b30c1f580168abfa069f7a9910fc72ce1a5f943da624fb6c
3
+ metadata.gz: 73a860de275fa7998ed8048ee53ac70ec2b7b5872456bd1c03422cb4218847cb
4
+ data.tar.gz: 0aee5f6d22f2630d1a513f3847441fb8e1f28399512f9046be161c65c4cb49f2
5
5
  SHA512:
6
- metadata.gz: d85d69406ceb52536ee95b74449fcca0fcb592b58dd8497288c60072945550df3824e5c2ef9e4ffd2b7ae7d32cbd00a023c6a5d7314b5fd55ca6132b5dde9904
7
- data.tar.gz: 8ccffafa78b30f253e1e47e90f747bfa3ddd240aba2269dd7952e48016fa58750f976b13afe7624318c2146e9447fe32c85516daca371d4b5d127a92dd896890
6
+ metadata.gz: a92575ecbabbbf572beb4c61c7f46fff241e339b737d224ee93bf78b24df6dbedeab28a8fa7721d3a213b833e5f799b0a31e76234b41f7c903ea208ff04db2f9
7
+ data.tar.gz: 358feb4234563044b7609e46130913c161cdd2fa555cbfba7be4faea1e5e3bf3e26b83f546da72ab46142b1de5097976e13dfec56b44105077e80e33609e1f8e
data/CHANGELOG.md CHANGED
@@ -6,6 +6,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## Unreleased
8
8
 
9
+ ## 1.2.2 - 2023-11-29
10
+ ### Changed
11
+ - Add support for filtering events by aggregate model attributes.
12
+
13
+ ## 1.2.1 - 2023-11-18
14
+ ### Changed
15
+ - Allow timestamp data in events to override default timestamps update.
16
+ - This allows us to create temporal events for example in the case of snapshots.
17
+
9
18
  ## 1.2.0 - 2023-09-26
10
19
  ### Changed
11
20
  - Fix issue where the reactor worker might not work correctly for models not inheriting from ApplicationRecord.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- eventsimple (1.2.0)
4
+ eventsimple (1.2.2)
5
5
  dry-struct (~> 1.6)
6
6
  dry-types (~> 1.7)
7
7
  pg (~> 1.4)
@@ -89,7 +89,7 @@ GEM
89
89
  coderay (1.1.3)
90
90
  concurrent-ruby (1.2.2)
91
91
  crass (1.0.6)
92
- date (3.3.3)
92
+ date (3.3.4)
93
93
  diff-lcs (1.5.0)
94
94
  dry-core (1.0.1)
95
95
  concurrent-ruby (~> 1.0)
@@ -158,12 +158,12 @@ GEM
158
158
  mini_mime (1.1.5)
159
159
  minitest (5.20.0)
160
160
  nenv (0.3.0)
161
- net-imap (0.3.7)
161
+ net-imap (0.4.7)
162
162
  date
163
163
  net-protocol
164
164
  net-pop (0.1.2)
165
165
  net-protocol
166
- net-protocol (0.2.1)
166
+ net-protocol (0.2.2)
167
167
  timeout
168
168
  net-smtp (0.4.0)
169
169
  net-protocol
@@ -300,7 +300,7 @@ GEM
300
300
  lint_roller (~> 1.0)
301
301
  rubocop-rails (~> 2.20.2)
302
302
  thor (1.2.2)
303
- timeout (0.4.0)
303
+ timeout (0.4.1)
304
304
  treetop (1.6.12)
305
305
  polyglot (~> 0.3)
306
306
  tzinfo (2.0.6)
data/README.md CHANGED
@@ -176,8 +176,6 @@ module UserComponent
176
176
  def apply(user)
177
177
  user.canonical_id = data.canonical_id
178
178
  user.email = data.email
179
-
180
- user
181
179
  end
182
180
  end
183
181
  end
@@ -8,6 +8,10 @@ module Eventsimple
8
8
  @event_id = params[:e] || -1
9
9
  @tab_id = (params[:t] == 'event') ? 'event' : 'entity'
10
10
 
11
+ filter_columns = @model_class._filter_attributes
12
+ params_filters = params.permit(filters: {})[:filters] || {}
13
+ @filters = filter_columns.to_h { |column| [column, params_filters[column]] }
14
+
11
15
  primary_key = @model_class.event_class._aggregate_id
12
16
  @entity = @model_class.find_by!(primary_key => @aggregate_id)
13
17
  @entity_event_history = @entity.events.reverse
@@ -2,9 +2,44 @@ module Eventsimple
2
2
  class ModelsController < ApplicationController
3
3
  def show
4
4
  @model_name = params[:name]
5
+ model_class = event_classes.find { |d| d.name == @model_name }
5
6
 
6
- model_event_class = event_classes.find { |d| d.name == @model_name }.event_class
7
- @latest_entities = model_event_class.last(20).reverse
7
+ scope = apply_filter(model_class, model_class.event_class)
8
+
9
+ @latest_entities = scope.last(20).reverse
10
+
11
+ check_redirect_to_entity
12
+ end
13
+
14
+ private
15
+
16
+ def apply_filter(model_class, model_event_class)
17
+ filter_columns = model_class._filter_attributes
18
+
19
+ params_filters = params.permit(filters: {})[:filters] || {}
20
+ @filters = filter_columns.to_h { |column| [column, params_filters[column]] }
21
+
22
+ return model_event_class unless @filters.any?
23
+
24
+ aggregate_class_symbol = model_event_class._aggregate_klass.model_name.element.to_sym
25
+ model_event_class = model_event_class.joins(aggregate_class_symbol)
26
+ @filters.each do |key, value|
27
+ next if value.blank?
28
+ key = model_event_class._aggregate_id if key == :aggregate_id
29
+ model_event_class = model_event_class.where({ aggregate_class_symbol => { key => value } })
30
+ end
31
+
32
+ model_event_class
33
+ end
34
+
35
+ def check_redirect_to_entity
36
+ return unless @latest_entities.any?
37
+
38
+ first_aggregate_id = @latest_entities.first.aggregate_id
39
+
40
+ return unless @latest_entities.all? { |entity| entity.aggregate_id == first_aggregate_id }
41
+
42
+ redirect_to model_entity_path(@model_name, first_aggregate_id, filters: @filters)
8
43
  end
9
44
  end
10
45
  end
@@ -1,26 +1,20 @@
1
1
  <!-- Header Search Start -->
2
2
  <header class="container mb-4">
3
- <div class="row">
4
- <div class="col col-sm-3">
5
- <select id="form-search-model-name" class="form-select" aria-label="Model select" onchange="document.location.href=this.value" required>
6
- <option value="">Choose event source model</option>
7
- <% event_class_names.each do |klass| %>
8
- <% is_active = klass === @model_name ? 'selected' : '' %>
9
- <option value="<%= model_path(klass) %>" <%= is_active %>><%= klass %></option>
10
- <% end %>
11
- </select>
12
- </div>
13
-
14
- <% if @model_name %>
15
- <div class="col col-sm-7">
16
- <%= form_with url: model_entity_path(@model_name, ''), id: 'model-search' do |f| %>
17
- <%= f.search_field :event_id, class: 'form-control', placeholder: 'Canonical identifier', value: @aggregate_id, required: true, aria: { label: 'Entity canonical identifier' } %>
3
+ <% if @model_name %>
4
+ <%= form_with scope: :filters, url: model_path(@model_name), method: :get, id: 'model-filter' do |f| %>
5
+ <div class="row">
6
+ <label for="filters_keys[keys]" class="col-sm-2 col-form-label">Filter attribute</label>
7
+ <div class="form-group col-sm-3">
8
+ <%= select :filters_keys, :keys, @filters.keys, { selected: @filters.compact.keys&.first }, { class:"form-select", onchange: "document.getElementById('model-filter-value').name=`filters[${this.value}]`" } %>
18
9
  </div>
19
- <div class="col col-sm-2">
10
+ <div class="form-group col-sm-5">
11
+ <%= f.search_field @filters.compact.keys&.first || @filters.keys.first, id: 'model-filter-value', value: @filters.compact.values&.first, class:"form-control", placeholder: "Filter value" %>
12
+ </div>
13
+ <div class="form-group col-sm-2">
20
14
  <%= f.submit 'Search', class: 'btn btn-primary' %>
21
- <% end %>
15
+ </div>
22
16
  </div>
23
17
  <% end %>
24
- </div>
18
+ <% end %>
25
19
  </header>
26
20
  <!-- Header Search End -->
@@ -62,12 +62,6 @@
62
62
  query.set(param, value);
63
63
  link.attr("href",window.location.pathname + '?' + query.toString());
64
64
  });
65
-
66
- $('#model-search').on('submit', (event) => {
67
- event.preventDefault();
68
- const form = $(event.currentTarget);
69
- window.location = form.attr('action') + form.children('#event_id').val();
70
- });
71
65
  });
72
66
  </script>
73
67
 
@@ -2,7 +2,7 @@ module Eventsimple
2
2
  module Entity
3
3
  DEFAULT_IGNORE_PROPS = %w[id lock_version].freeze
4
4
 
5
- def event_driven_by(event_klass, aggregate_id:)
5
+ def event_driven_by(event_klass, aggregate_id:, filter_attributes: [])
6
6
  has_many :events, class_name: event_klass.name.to_s,
7
7
  foreign_key: :aggregate_id,
8
8
  primary_key: aggregate_id,
@@ -13,6 +13,9 @@ module Eventsimple
13
13
 
14
14
  class_attribute :ignored_for_projection, default: []
15
15
 
16
+ class_attribute :_filter_attributes
17
+ self._filter_attributes = [aggregate_id] | Array.wrap(filter_attributes)
18
+
16
19
  # disable automatic timestamp updates
17
20
  self.record_timestamps = false
18
21
 
@@ -35,8 +38,8 @@ module Eventsimple
35
38
  assign_attributes(self.class.column_defaults.except(*ignore_props))
36
39
 
37
40
  event_history.each do |event|
38
- event.apply(self)
39
41
  event.apply_timestamps(self)
42
+ event.apply(self)
40
43
  end
41
44
 
42
45
  self
@@ -86,8 +86,8 @@ module Eventsimple
86
86
 
87
87
  # Apply the transformation to the aggregate and save it.
88
88
  def apply_and_persist
89
- apply(aggregate)
90
89
  apply_timestamps(aggregate)
90
+ apply(aggregate)
91
91
 
92
92
  # Persist!
93
93
  aggregate.save!
@@ -45,3 +45,5 @@ RSpec.shared_examples 'an event in invalid state that is rescued' do
45
45
  end
46
46
  end
47
47
  end
48
+
49
+ RSpec::Matchers.define_negated_matcher(:not_change, :change)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Eventsimple
4
- VERSION = '1.2.0'
4
+ VERSION = '1.2.2'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eventsimple
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zulfiqar Ali
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-09-26 00:00:00.000000000 Z
11
+ date: 2023-12-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-struct