event_sourcery-postgres 0.9.1 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 824d15b46de51809119f1adec5708cab3e6e252dabeedc5257cda2b1c934a7bf
4
- data.tar.gz: deea46e08d13e42d46d37ac7379ccc9782a87e5137710004ce1c922ad283f40d
3
+ metadata.gz: 05b4e104f8ead624e85b64116db8a9347ff6fd4b6b0af4abc8b4c60c0d49d926
4
+ data.tar.gz: c019944e4b6d194088945d8e7c9fe9cfd7a494fc6d8cba8f90df56cc839bfc24
5
5
  SHA512:
6
- metadata.gz: a9cf1a6d3aad1270378fa68855ca339a3a0bca8aa13c8c06c82da634b340a93822d73254da780fbc6ef7420f9901836ebd81d68cfe0c8c506584b1be3c50c028
7
- data.tar.gz: 520be11bd4e97b6ecd07fcc995c613c4978dcb97509569d15fda3d28206acd41696db718d54bc54861f72a38e59bdaf61a18369aa09c60cc748991700cb5dc90
6
+ metadata.gz: 76861f96df82c5ebe3de33f29de17ab6a86e9c5fd45fb72bb092469567eb8961d32e3fcf848e646023f5b12a5a1e9d5d2e6c8b292d15181ed2ea4d05e1b2b645
7
+ data.tar.gz: c59050c981cc4dac1ec32d5695a872351ed8bdc45ba5cb8a7d903c15fb06ea83ca13ce924db2095b62d6dda9d335302811522eed84ec8b568e116fac6a802706
data/CHANGELOG.md CHANGED
@@ -6,6 +6,24 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
6
6
  and this project adheres to [Semantic Versioning](http://semver.org/).
7
7
 
8
8
  ## [Unreleased]
9
+
10
+ [Unreleased]: https://github.com/envato/event_sourcery-postgres/compare/v1.0.0...HEAD
11
+
12
+ ## [1.0.0] - 2025-12-28
13
+
14
+ ### Changed
15
+
16
+ - Resolve issues as identified by RuboCop ([#78], [#82], [#83]).
17
+ - Minor fixups in gem metadata ([#79]).
18
+ - Remove support for older Ruby versions: Ruby 2.6 or greater is now required ([#80]).
19
+
20
+ [1.0.0]: https://github.com/envato/event_sourcery-postgres/compare/v0.9.1...v1.0.0
21
+ [#78]: https://github.com/envato/event_sourcery-postgres/pull/78
22
+ [#79]: https://github.com/envato/event_sourcery-postgres/pull/79
23
+ [#80]: https://github.com/envato/event_sourcery-postgres/pull/80
24
+ [#82]: https://github.com/envato/event_sourcery-postgres/pull/82
25
+ [#83]: https://github.com/envato/event_sourcery-postgres/pull/83
26
+
9
27
  ## [0.9.1] - 2022-01-20
10
28
 
11
29
  ### Changed
@@ -117,7 +135,6 @@ or when the loop stops
117
135
  - Postgres related configuration is through `EventSourcery::Postgres.configure`
118
136
  instead of `EventSourcery.configure`.
119
137
 
120
- [Unreleased]: https://github.com/envato/event_sourcery-postgres/compare/v0.9.1...HEAD
121
138
  [0.9.1]: https://github.com/envato/event_sourcery-postgres/compare/v0.9.0...v0.9.1
122
139
  [0.9.0]: https://github.com/envato/event_sourcery-postgres/compare/v0.8.1...v0.9.0
123
140
  [0.8.1]: https://github.com/envato/event_sourcery-postgres/compare/v0.8.0...v0.8.1
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # EventSourcery::Postgres
2
2
 
3
- [![Build Status](https://github.com/envato/event_sourcery-postgres/workflows/tests/badge.svg?branch=main)](https://github.com/envato/event_sourcery-postgres/actions?query=workflow%3Atests+branch%3Amain)
3
+ [![Build Status](https://github.com/envato/event_sourcery-postgres/actions/workflows/test.yml/badge.svg)](https://github.com/envato/event_sourcery-postgres/actions/workflows/test.yml)
4
4
 
5
5
  ## Development Status
6
6
 
@@ -1,5 +1,6 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
3
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
5
  require 'event_sourcery/postgres/version'
5
6
 
@@ -12,27 +13,32 @@ Gem::Specification.new do |spec|
12
13
 
13
14
  spec.summary = 'Postgres event store for use with EventSourcery'
14
15
  spec.homepage = 'https://github.com/envato/event_sourcery-postgres'
16
+ spec.license = 'MIT'
17
+
15
18
  spec.metadata = {
16
- 'bug_tracker_uri' => 'https://github.com/envato/event_sourcery-postgres/issues',
17
- 'changelog_uri' => 'https://github.com/envato/event_sourcery-postgres/blob/HEAD/CHANGELOG.md',
18
- 'source_code_uri' => 'https://github.com/envato/event_sourcery-postgres',
19
- }
19
+ 'allowed_push_host' => 'https://rubygems.org',
20
+ 'bug_tracker_uri' => "#{spec.homepage}/issues",
21
+ 'changelog_uri' => "#{spec.homepage}/blob/HEAD/CHANGELOG.md",
22
+ 'documentation_uri' => "https://www.rubydoc.info/gems/event_sourcery-postgres/#{spec.version}",
23
+ 'source_code_uri' => "#{spec.homepage}/tree/v#{spec.version}"
24
+ }
20
25
 
21
- spec.files = `git ls-files -z`.split("\x0").reject do |f|
26
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
22
27
  f.match(%r{^(\.|bin/|Gemfile|Rakefile|script/|spec/)})
23
28
  end
24
29
  spec.bindir = 'exe'
25
30
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
31
  spec.require_paths = ['lib']
27
32
 
28
- spec.required_ruby_version = '>= 2.2.0'
33
+ spec.required_ruby_version = '>= 2.6.0'
29
34
 
30
- spec.add_dependency 'sequel', '>= 4.38'
31
- spec.add_dependency 'pg'
32
35
  spec.add_dependency 'event_sourcery', '>= 0.14.0'
36
+ spec.add_dependency 'pg'
37
+ spec.add_dependency 'sequel', '>= 4.38'
38
+ spec.add_development_dependency 'benchmark-ips'
33
39
  spec.add_development_dependency 'bundler'
40
+ spec.add_development_dependency 'pry'
34
41
  spec.add_development_dependency 'rake', '~> 13'
35
42
  spec.add_development_dependency 'rspec', '~> 3.0'
36
- spec.add_development_dependency 'pry'
37
- spec.add_development_dependency 'benchmark-ips'
43
+ spec.add_development_dependency 'rubocop', '~> 1'
38
44
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module EventSourcery
2
4
  module Postgres
3
5
  class Config
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module EventSourcery
2
4
  module Postgres
3
5
  class EventStore
@@ -32,6 +34,7 @@ module EventSourcery
32
34
  events = Array(event_or_events)
33
35
  aggregate_ids = events.map(&:aggregate_id).uniq
34
36
  raise AtomicWriteToMultipleAggregatesNotSupported unless aggregate_ids.count == 1
37
+
35
38
  sql = write_events_sql(aggregate_ids.first, events, expected_version)
36
39
  @db_connection.run(sql)
37
40
  log_events_saved(events)
@@ -40,9 +43,9 @@ module EventSourcery
40
43
  rescue Sequel::DatabaseError => e
41
44
  if e.message =~ /Concurrency conflict/
42
45
  raise ConcurrencyError, "expected version was not #{expected_version}. Error: #{e.message}"
43
- else
44
- raise
45
46
  end
47
+
48
+ raise
46
49
  end
47
50
 
48
51
  # Get the next set of events from the given event id. You can
@@ -55,10 +58,11 @@ module EventSourcery
55
58
  #
56
59
  # @return [Array] array of found events
57
60
  def get_next_from(id, event_types: nil, limit: 1000)
58
- query = events_table.
59
- order(:id).
60
- where(Sequel.lit('id >= ?', id)).
61
- limit(limit)
61
+ query =
62
+ events_table
63
+ .order(:id)
64
+ .where(Sequel.lit('id >= ?', id))
65
+ .limit(limit)
62
66
  query = query.where(type: event_types) if event_types
63
67
  query.map { |event_row| build_event(event_row) }
64
68
  end
@@ -96,7 +100,7 @@ module EventSourcery
96
100
  # @param event_types the event_types to subscribe to, default all.
97
101
  # @param after_listen the after listen call back block. default nil.
98
102
  # @param subscription_master the subscription master block
99
- def subscribe(from_id:, event_types: nil, after_listen: nil, subscription_master:, &block)
103
+ def subscribe(from_id:, subscription_master:, event_types: nil, after_listen: nil, &block)
100
104
  poll_waiter = OptimisedEventPollWaiter.new(db_connection: @db_connection, after_listen: after_listen)
101
105
  args = {
102
106
  poll_waiter: poll_waiter,
@@ -157,9 +161,10 @@ module EventSourcery
157
161
 
158
162
  def to_sql_literal(value)
159
163
  return 'null' unless value
160
- wrapped_value = if Time === value
164
+
165
+ wrapped_value = if value.is_a?(Time)
161
166
  value.iso8601(6)
162
- elsif Hash === value
167
+ elsif value.is_a?(Hash)
163
168
  Sequel.pg_json(value)
164
169
  else
165
170
  value
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module EventSourcery
2
4
  module Postgres
3
5
  # Optimise poll interval with Postgres listen/notify
@@ -11,7 +13,7 @@ module EventSourcery
11
13
  @after_listen = after_listen
12
14
  end
13
15
 
14
- def poll(after_listen: proc { }, &block)
16
+ def poll(after_listen: proc {}, &block)
15
17
  @events_queue.callback = proc do
16
18
  ensure_listen_thread_alive!
17
19
  block.call
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module EventSourcery
2
4
  module Postgres
3
5
  module Projector
@@ -1,9 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module EventSourcery
2
4
  module Postgres
3
5
  class QueueWithIntervalCallback < ::Queue
4
6
  attr_accessor :callback
5
7
 
6
- def initialize(callback: proc {}, callback_interval: EventSourcery::Postgres.config.callback_interval_if_no_new_events, poll_interval: 0.1)
8
+ def initialize(
9
+ callback: proc {},
10
+ callback_interval: EventSourcery::Postgres.config.callback_interval_if_no_new_events,
11
+ poll_interval: 0.1
12
+ )
7
13
  @callback = callback
8
14
  @callback_interval = callback_interval
9
15
  @poll_interval = poll_interval
@@ -12,6 +18,7 @@ module EventSourcery
12
18
 
13
19
  def pop(non_block_without_callback = false)
14
20
  return super if non_block_without_callback
21
+
15
22
  pop_with_interval_callback
16
23
  end
17
24
 
@@ -21,6 +28,7 @@ module EventSourcery
21
28
  time = Time.now
22
29
  loop do
23
30
  return pop(true) unless empty?
31
+
24
32
  if @callback_interval && Time.now > time + @callback_interval
25
33
  @callback.call
26
34
  time = Time.now
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module EventSourcery
2
4
  module Postgres
3
5
  module Reactor
@@ -48,11 +50,10 @@ module EventSourcery
48
50
  @event_source = event_source
49
51
  @event_sink = event_sink
50
52
  @db_connection = db_connection
51
- if self.class.emits_events?
52
- if event_sink.nil? || event_source.nil?
53
- raise ArgumentError, 'An event sink and source is required for processors that emit events'
54
- end
55
- end
53
+ return unless self.class.emits_events?
54
+ return unless event_sink.nil? || event_source.nil?
55
+
56
+ raise ArgumentError, 'An event sink and source is required for processors that emit events'
56
57
  end
57
58
  end
58
59
 
@@ -61,15 +62,16 @@ module EventSourcery
61
62
  attr_reader :event_sink, :event_source
62
63
 
63
64
  def emit_event(event_or_hash, &block)
64
- event = if Event === event_or_hash
65
+ event = if event_or_hash.is_a?(Event)
65
66
  event_or_hash
66
67
  else
67
68
  Event.new(event_or_hash)
68
69
  end
69
70
  raise UndeclaredEventEmissionError unless self.class.emits_event?(event.class)
71
+
70
72
  event = event.with(causation_id: _event.uuid, correlation_id: _event.correlation_id)
71
73
  invoke_action_and_emit_event(event, block)
72
- EventSourcery.logger.debug { "[#{self.processor_name}] Emitted event: #{event.inspect}" }
74
+ EventSourcery.logger.debug { "[#{processor_name}] Emitted event: #{event.inspect}" }
73
75
  end
74
76
 
75
77
  def invoke_action_and_emit_event(event, action)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module EventSourcery
2
4
  module Postgres
3
5
  module Schema
@@ -15,7 +17,12 @@ module EventSourcery
15
17
  write_events_function_name: EventSourcery::Postgres.config.write_events_function_name)
16
18
  create_events(db: db, table_name: events_table_name)
17
19
  create_aggregates(db: db, table_name: aggregates_table_name)
18
- create_or_update_functions(db: db, events_table_name: events_table_name, function_name: write_events_function_name, aggregates_table_name: aggregates_table_name)
20
+ create_or_update_functions(
21
+ db: db,
22
+ events_table_name: events_table_name,
23
+ function_name: write_events_function_name,
24
+ aggregates_table_name: aggregates_table_name
25
+ )
19
26
  end
20
27
 
21
28
  # Create the events table. Needs the database and the table name.
@@ -35,8 +42,9 @@ module EventSourcery
35
42
  column :version, :bigint, null: false
36
43
  column :correlation_id, :uuid
37
44
  column :causation_id, :uuid
38
- column :created_at, :'timestamp without time zone', null: false, default: Sequel.lit("(now() at time zone 'utc')")
39
- index [:aggregate_id, :version], unique: true
45
+ column :created_at, :'timestamp without time zone', null: false,
46
+ default: Sequel.lit("(now() at time zone 'utc')")
47
+ index %i[aggregate_id version], unique: true
40
48
  index :uuid, unique: true
41
49
  index :type
42
50
  index :correlation_id
@@ -70,96 +78,96 @@ module EventSourcery
70
78
  function_name: EventSourcery::Postgres.config.write_events_function_name,
71
79
  events_table_name: EventSourcery::Postgres.config.events_table_name,
72
80
  aggregates_table_name: EventSourcery::Postgres.config.aggregates_table_name)
73
- db.run <<-SQL
74
- create or replace function #{function_name}(_aggregateId uuid,
75
- _eventTypes varchar[],
76
- _expectedVersion int,
77
- _bodies json[],
78
- _createdAtTimes timestamp without time zone[],
79
- _eventUUIDs uuid[],
80
- _correlationIds uuid[],
81
- _causationIds uuid[],
82
- _lockTable boolean) returns void as $$
83
- declare
84
- currentVersion int;
85
- body json;
86
- eventVersion int;
87
- eventId text;
88
- index int;
89
- newVersion int;
90
- numEvents int;
91
- createdAt timestamp without time zone;
92
- begin
93
- numEvents := array_length(_bodies, 1);
94
- select version into currentVersion from #{aggregates_table_name} where aggregate_id = _aggregateId;
95
- if not found then
96
- -- when we have no existing version for this aggregate
97
- if _expectedVersion = 0 or _expectedVersion is null then
98
- -- set the version to 1 if expected version is null or 0
99
- insert into #{aggregates_table_name}(aggregate_id, version) values(_aggregateId, numEvents);
100
- currentVersion := 0;
101
- else
102
- raise 'Concurrency conflict. Current version: 0, expected version: %', _expectedVersion;
103
- end if;
104
- else
105
- if _expectedVersion is null then
106
- -- automatically increment the version
107
- update #{aggregates_table_name} set version = version + numEvents where aggregate_id = _aggregateId returning version into newVersion;
108
- currentVersion := newVersion - numEvents;
109
- else
110
- -- increment the version if it's at our expected version
111
- update #{aggregates_table_name} set version = version + numEvents where aggregate_id = _aggregateId and version = _expectedVersion;
112
- if not found then
113
- -- version was not at expected_version, raise an error.
114
- -- currentVersion may not equal what it did in the database when the
115
- -- above update statement is executed (it may have been incremented by another
116
- -- process)
117
- raise 'Concurrency conflict. Last known current version: %, expected version: %', currentVersion, _expectedVersion;
118
- end if;
119
- end if;
120
- end if;
121
- index := 1;
122
- eventVersion := currentVersion + 1;
123
- if _lockTable then
124
- -- Ensure this transaction is the only one writing events to guarantee
125
- -- linear growth of sequence IDs.
126
- -- Any value that won't conflict with other advisory locks will work.
127
- -- The Postgres tracker currently obtains an advisory lock using it's
128
- -- integer row ID, so values 1 to the number of ESP's in the system would
129
- -- be taken if the tracker is running in the same database as your
130
- -- projections.
131
- perform pg_advisory_xact_lock(-1);
132
- end if;
133
- foreach body IN ARRAY(_bodies)
134
- loop
135
- if _createdAtTimes[index] is not null then
136
- createdAt := _createdAtTimes[index];
137
- else
138
- createdAt := now() at time zone 'utc';
139
- end if;
81
+ db.run <<~SQL
82
+ create or replace function #{function_name}(_aggregateId uuid,
83
+ _eventTypes varchar[],
84
+ _expectedVersion int,
85
+ _bodies json[],
86
+ _createdAtTimes timestamp without time zone[],
87
+ _eventUUIDs uuid[],
88
+ _correlationIds uuid[],
89
+ _causationIds uuid[],
90
+ _lockTable boolean) returns void as $$
91
+ declare
92
+ currentVersion int;
93
+ body json;
94
+ eventVersion int;
95
+ eventId text;
96
+ index int;
97
+ newVersion int;
98
+ numEvents int;
99
+ createdAt timestamp without time zone;
100
+ begin
101
+ numEvents := array_length(_bodies, 1);
102
+ select version into currentVersion from #{aggregates_table_name} where aggregate_id = _aggregateId;
103
+ if not found then
104
+ -- when we have no existing version for this aggregate
105
+ if _expectedVersion = 0 or _expectedVersion is null then
106
+ -- set the version to 1 if expected version is null or 0
107
+ insert into #{aggregates_table_name}(aggregate_id, version) values(_aggregateId, numEvents);
108
+ currentVersion := 0;
109
+ else
110
+ raise 'Concurrency conflict. Current version: 0, expected version: %', _expectedVersion;
111
+ end if;
112
+ else
113
+ if _expectedVersion is null then
114
+ -- automatically increment the version
115
+ update #{aggregates_table_name} set version = version + numEvents where aggregate_id = _aggregateId returning version into newVersion;
116
+ currentVersion := newVersion - numEvents;
117
+ else
118
+ -- increment the version if it's at our expected version
119
+ update #{aggregates_table_name} set version = version + numEvents where aggregate_id = _aggregateId and version = _expectedVersion;
120
+ if not found then
121
+ -- version was not at expected_version, raise an error.
122
+ -- currentVersion may not equal what it did in the database when the
123
+ -- above update statement is executed (it may have been incremented by another
124
+ -- process)
125
+ raise 'Concurrency conflict. Last known current version: %, expected version: %', currentVersion, _expectedVersion;
126
+ end if;
127
+ end if;
128
+ end if;
129
+ index := 1;
130
+ eventVersion := currentVersion + 1;
131
+ if _lockTable then
132
+ -- Ensure this transaction is the only one writing events to guarantee
133
+ -- linear growth of sequence IDs.
134
+ -- Any value that won't conflict with other advisory locks will work.
135
+ -- The Postgres tracker currently obtains an advisory lock using it's
136
+ -- integer row ID, so values 1 to the number of ESP's in the system would
137
+ -- be taken if the tracker is running in the same database as your
138
+ -- projections.
139
+ perform pg_advisory_xact_lock(-1);
140
+ end if;
141
+ foreach body IN ARRAY(_bodies)
142
+ loop
143
+ if _createdAtTimes[index] is not null then
144
+ createdAt := _createdAtTimes[index];
145
+ else
146
+ createdAt := now() at time zone 'utc';
147
+ end if;
140
148
 
141
- insert into #{events_table_name}
142
- (uuid, aggregate_id, type, body, version, correlation_id, causation_id, created_at)
143
- values
144
- (
145
- _eventUUIDs[index],
146
- _aggregateId,
147
- _eventTypes[index],
148
- body,
149
- eventVersion,
150
- _correlationIds[index],
151
- _causationIds[index],
152
- createdAt
153
- )
154
- returning id into eventId;
149
+ insert into #{events_table_name}
150
+ (uuid, aggregate_id, type, body, version, correlation_id, causation_id, created_at)
151
+ values
152
+ (
153
+ _eventUUIDs[index],
154
+ _aggregateId,
155
+ _eventTypes[index],
156
+ body,
157
+ eventVersion,
158
+ _correlationIds[index],
159
+ _causationIds[index],
160
+ createdAt
161
+ )
162
+ returning id into eventId;
155
163
 
156
- eventVersion := eventVersion + 1;
157
- index := index + 1;
158
- end loop;
159
- perform pg_notify('new_event', eventId);
160
- end;
161
- $$ language plpgsql;
162
- SQL
164
+ eventVersion := eventVersion + 1;
165
+ index := index + 1;
166
+ end loop;
167
+ perform pg_notify('new_event', eventId);
168
+ end;
169
+ $$ language plpgsql;
170
+ SQL
163
171
  end
164
172
 
165
173
  # Create the projector tracker table. Needs the database and the table name.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module EventSourcery
2
4
  module Postgres
3
5
  module TableOwner
@@ -38,9 +40,7 @@ module EventSourcery
38
40
  def reset
39
41
  self.class.tables.keys.each do |table_name|
40
42
  prefixed_name = table_name_prefixed(table_name)
41
- if @db_connection.table_exists?(prefixed_name)
42
- @db_connection.drop_table(prefixed_name, cascade: true)
43
- end
43
+ @db_connection.drop_table(prefixed_name, cascade: true) if @db_connection.table_exists?(prefixed_name)
44
44
  end
45
45
  super if defined?(super)
46
46
  setup
@@ -1,8 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module EventSourcery
2
4
  module Postgres
3
5
  # This will set up a persisted event id tracker for processors.
4
6
  class Tracker
5
-
6
7
  def initialize(db_connection = EventSourcery::Postgres.config.projections_database,
7
8
  table_name: EventSourcery::Postgres.config.tracker_table_name,
8
9
  obtain_processor_lock: true)
@@ -19,16 +20,14 @@ module EventSourcery
19
20
  def setup(processor_name = nil)
20
21
  create_table_if_not_exists if EventSourcery::Postgres.config.auto_create_projector_tracker
21
22
 
22
- unless tracker_table_exists?
23
- raise UnableToLockProcessorError, 'Projector tracker table does not exist'
24
- end
23
+ raise UnableToLockProcessorError, 'Projector tracker table does not exist' unless tracker_table_exists?
25
24
 
26
- if processor_name
27
- create_track_entry_if_not_exists(processor_name)
28
- if @obtain_processor_lock
29
- obtain_global_lock_on_processor(processor_name)
30
- end
31
- end
25
+ return unless processor_name
26
+
27
+ create_track_entry_if_not_exists(processor_name)
28
+ return unless @obtain_processor_lock
29
+
30
+ obtain_global_lock_on_processor(processor_name)
32
31
  end
33
32
 
34
33
  # This will updated the tracker table to the given event id value
@@ -37,9 +36,9 @@ module EventSourcery
37
36
  # @param processor_name the name of the processor to update
38
37
  # @param event_id the event id number to update to
39
38
  def processed_event(processor_name, event_id)
40
- table.
41
- where(name: processor_name.to_s).
42
- update(last_processed_event_id: event_id)
39
+ table
40
+ .where(name: processor_name.to_s)
41
+ .update(last_processed_event_id: event_id)
43
42
  true
44
43
  end
45
44
 
@@ -82,17 +81,18 @@ module EventSourcery
82
81
  private
83
82
 
84
83
  def obtain_global_lock_on_processor(processor_name)
85
- lock_obtained = @db_connection.fetch("select pg_try_advisory_lock(#{@track_entry_id})").to_a.first[:pg_try_advisory_lock]
86
- if lock_obtained == false
87
- raise UnableToLockProcessorError, "Unable to get a lock on #{processor_name} #{@track_entry_id}"
88
- end
84
+ lock_obtained = @db_connection.fetch("select pg_try_advisory_lock(#{@track_entry_id})")
85
+ .to_a.first[:pg_try_advisory_lock]
86
+ return unless lock_obtained == false
87
+
88
+ raise UnableToLockProcessorError, "Unable to get a lock on #{processor_name} #{@track_entry_id}"
89
89
  end
90
90
 
91
91
  def create_table_if_not_exists
92
- unless tracker_table_exists?
93
- EventSourcery.logger.info { "Projector tracker missing - attempting to create 'projector_tracker' table" }
94
- EventSourcery::Postgres::Schema.create_projector_tracker(db: @db_connection, table_name: @table_name)
95
- end
92
+ return if tracker_table_exists?
93
+
94
+ EventSourcery.logger.info { "Projector tracker missing - attempting to create 'projector_tracker' table" }
95
+ EventSourcery::Postgres::Schema.create_projector_tracker(db: @db_connection, table_name: @table_name)
96
96
  end
97
97
 
98
98
  def create_track_entry_if_not_exists(processor_name)
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module EventSourcery
2
4
  module Postgres
3
- VERSION = '0.9.1'.freeze
5
+ VERSION = '1.0.0'
4
6
  end
5
7
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'sequel'
2
4
 
3
5
  Sequel.default_timezone = :utc
metadata CHANGED
@@ -1,29 +1,28 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: event_sourcery-postgres
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Envato
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2022-01-20 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
- name: sequel
13
+ name: event_sourcery
15
14
  requirement: !ruby/object:Gem::Requirement
16
15
  requirements:
17
16
  - - ">="
18
17
  - !ruby/object:Gem::Version
19
- version: '4.38'
18
+ version: 0.14.0
20
19
  type: :runtime
21
20
  prerelease: false
22
21
  version_requirements: !ruby/object:Gem::Requirement
23
22
  requirements:
24
23
  - - ">="
25
24
  - !ruby/object:Gem::Version
26
- version: '4.38'
25
+ version: 0.14.0
27
26
  - !ruby/object:Gem::Dependency
28
27
  name: pg
29
28
  requirement: !ruby/object:Gem::Requirement
@@ -39,19 +38,33 @@ dependencies:
39
38
  - !ruby/object:Gem::Version
40
39
  version: '0'
41
40
  - !ruby/object:Gem::Dependency
42
- name: event_sourcery
41
+ name: sequel
43
42
  requirement: !ruby/object:Gem::Requirement
44
43
  requirements:
45
44
  - - ">="
46
45
  - !ruby/object:Gem::Version
47
- version: 0.14.0
46
+ version: '4.38'
48
47
  type: :runtime
49
48
  prerelease: false
50
49
  version_requirements: !ruby/object:Gem::Requirement
51
50
  requirements:
52
51
  - - ">="
53
52
  - !ruby/object:Gem::Version
54
- version: 0.14.0
53
+ version: '4.38'
54
+ - !ruby/object:Gem::Dependency
55
+ name: benchmark-ips
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
55
68
  - !ruby/object:Gem::Dependency
56
69
  name: bundler
57
70
  requirement: !ruby/object:Gem::Requirement
@@ -67,62 +80,61 @@ dependencies:
67
80
  - !ruby/object:Gem::Version
68
81
  version: '0'
69
82
  - !ruby/object:Gem::Dependency
70
- name: rake
83
+ name: pry
71
84
  requirement: !ruby/object:Gem::Requirement
72
85
  requirements:
73
- - - "~>"
86
+ - - ">="
74
87
  - !ruby/object:Gem::Version
75
- version: '13'
88
+ version: '0'
76
89
  type: :development
77
90
  prerelease: false
78
91
  version_requirements: !ruby/object:Gem::Requirement
79
92
  requirements:
80
- - - "~>"
93
+ - - ">="
81
94
  - !ruby/object:Gem::Version
82
- version: '13'
95
+ version: '0'
83
96
  - !ruby/object:Gem::Dependency
84
- name: rspec
97
+ name: rake
85
98
  requirement: !ruby/object:Gem::Requirement
86
99
  requirements:
87
100
  - - "~>"
88
101
  - !ruby/object:Gem::Version
89
- version: '3.0'
102
+ version: '13'
90
103
  type: :development
91
104
  prerelease: false
92
105
  version_requirements: !ruby/object:Gem::Requirement
93
106
  requirements:
94
107
  - - "~>"
95
108
  - !ruby/object:Gem::Version
96
- version: '3.0'
109
+ version: '13'
97
110
  - !ruby/object:Gem::Dependency
98
- name: pry
111
+ name: rspec
99
112
  requirement: !ruby/object:Gem::Requirement
100
113
  requirements:
101
- - - ">="
114
+ - - "~>"
102
115
  - !ruby/object:Gem::Version
103
- version: '0'
116
+ version: '3.0'
104
117
  type: :development
105
118
  prerelease: false
106
119
  version_requirements: !ruby/object:Gem::Requirement
107
120
  requirements:
108
- - - ">="
121
+ - - "~>"
109
122
  - !ruby/object:Gem::Version
110
- version: '0'
123
+ version: '3.0'
111
124
  - !ruby/object:Gem::Dependency
112
- name: benchmark-ips
125
+ name: rubocop
113
126
  requirement: !ruby/object:Gem::Requirement
114
127
  requirements:
115
- - - ">="
128
+ - - "~>"
116
129
  - !ruby/object:Gem::Version
117
- version: '0'
130
+ version: '1'
118
131
  type: :development
119
132
  prerelease: false
120
133
  version_requirements: !ruby/object:Gem::Requirement
121
134
  requirements:
122
- - - ">="
135
+ - - "~>"
123
136
  - !ruby/object:Gem::Version
124
- version: '0'
125
- description:
137
+ version: '1'
126
138
  email:
127
139
  - rubygems@envato.com
128
140
  executables: []
@@ -146,12 +158,14 @@ files:
146
158
  - lib/event_sourcery/postgres/tracker.rb
147
159
  - lib/event_sourcery/postgres/version.rb
148
160
  homepage: https://github.com/envato/event_sourcery-postgres
149
- licenses: []
161
+ licenses:
162
+ - MIT
150
163
  metadata:
164
+ allowed_push_host: https://rubygems.org
151
165
  bug_tracker_uri: https://github.com/envato/event_sourcery-postgres/issues
152
166
  changelog_uri: https://github.com/envato/event_sourcery-postgres/blob/HEAD/CHANGELOG.md
153
- source_code_uri: https://github.com/envato/event_sourcery-postgres
154
- post_install_message:
167
+ documentation_uri: https://www.rubydoc.info/gems/event_sourcery-postgres/1.0.0
168
+ source_code_uri: https://github.com/envato/event_sourcery-postgres/tree/v1.0.0
155
169
  rdoc_options: []
156
170
  require_paths:
157
171
  - lib
@@ -159,15 +173,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
159
173
  requirements:
160
174
  - - ">="
161
175
  - !ruby/object:Gem::Version
162
- version: 2.2.0
176
+ version: 2.6.0
163
177
  required_rubygems_version: !ruby/object:Gem::Requirement
164
178
  requirements:
165
179
  - - ">="
166
180
  - !ruby/object:Gem::Version
167
181
  version: '0'
168
182
  requirements: []
169
- rubygems_version: 3.2.22
170
- signing_key:
183
+ rubygems_version: 4.0.3
171
184
  specification_version: 4
172
185
  summary: Postgres event store for use with EventSourcery
173
186
  test_files: []