event_sourcery-postgres 0.4.0 → 0.5.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/CHANGELOG.md +7 -2
- data/README.md +2 -5
- data/lib/event_sourcery/postgres.rb +0 -1
- data/lib/event_sourcery/postgres/config.rb +16 -0
- data/lib/event_sourcery/postgres/event_store.rb +36 -0
- data/lib/event_sourcery/postgres/reactor.rb +11 -0
- data/lib/event_sourcery/postgres/schema.rb +29 -0
- data/lib/event_sourcery/postgres/table_owner.rb +11 -0
- data/lib/event_sourcery/postgres/tracker.rb +28 -0
- data/lib/event_sourcery/postgres/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 54611962fa99a62b63f2a97d432614e43aa2b10e
|
4
|
+
data.tar.gz: d4b6413ce323e94e950fb1d3276eaebacdb6dedd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 55e76d3c6300f678ddfefe9c4dc9be6cd1fa365ace92ebce6cc6be432e2d19553cc9313da54923307fc264bb6b4582fc23022349dfc3e70df56261756a021c6d
|
7
|
+
data.tar.gz: 12e02831936b8fe0203ba1f0c7908a00fbff4e74308d5a879f22f0a02e311f1a2aac1b3b068df80ad81f68a4029b0b31436362a9a815d10cba32b290dfeb9f01
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
8
|
|
9
|
+
|
10
|
+
## [0.5.0] - 2017-7-27
|
11
|
+
- First Version of YARD documentation.
|
12
|
+
- Fix Sequel deprecation by globally loading pg extensions
|
13
|
+
|
9
14
|
## [0.4.0] - 2017-6-21
|
10
15
|
### Changed
|
11
16
|
- Reactors store the UUID of the event being processed in the `causation_id`
|
@@ -26,14 +31,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|
26
31
|
added to the `events` table and the `write_events` function has been
|
27
32
|
altered. Event Sourcery apps will need to ensure these DB changes have
|
28
33
|
been applied to use this version of Event Sourcery.
|
34
|
+
- The emit_events method now accepts typed events instead of symbols
|
35
|
+
- Remove dynamic emit events methods from reactors (e.g. emit_item_added)
|
29
36
|
|
30
37
|
## [0.2.0] - 2017-6-1
|
31
38
|
### Changed
|
32
39
|
- Make `EventSourcery::Postgres::OptimisedEventPollWaiter#shutdown` private
|
33
40
|
- Updated `EventSourcery::Postgres::OptimisedEventPollWaiter#poll` to ensure that `#shutdown!` is run when an error is raised
|
34
41
|
or when the loop stops
|
35
|
-
- Remove dynamic emit events methods from reactors (e.g. emit_item_added)
|
36
|
-
- The emit_events method now accepts typed events instead of symbols
|
37
42
|
|
38
43
|
### Added
|
39
44
|
- Configure projector tracker table name via `EventSourcery::Postgres.configure`
|
data/README.md
CHANGED
@@ -91,11 +91,8 @@ To release a new version:
|
|
91
91
|
|
92
92
|
1. Update the version number in `lib/event_sourcery/postgres/version.rb`
|
93
93
|
2. Get this change onto master via the normal PR process
|
94
|
-
3. Run `
|
95
|
-
|
96
|
-
push tags up to GitHub, and package the code in a `.gem` file.
|
97
|
-
4. Manually upload the generated gem file (`pkg/event_sourcery-postgres-#{version}.gem`) to
|
98
|
-
[rubygems.envato.com](https://rubygems.envato.com).
|
94
|
+
3. Run `bundle exec rake release`, this will create a git tag for the
|
95
|
+
version, push tags up to GitHub, and upload the gem to rubygems.org.
|
99
96
|
|
100
97
|
## Contributing
|
101
98
|
|
@@ -38,10 +38,26 @@ module EventSourcery
|
|
38
38
|
@event_sink ||= ::EventSourcery::EventStore::EventSink.new(event_store)
|
39
39
|
end
|
40
40
|
|
41
|
+
def event_store_database=(sequel_connection)
|
42
|
+
setup_connection(sequel_connection)
|
43
|
+
|
44
|
+
@event_store_database = sequel_connection
|
45
|
+
end
|
46
|
+
|
41
47
|
def projections_database=(sequel_connection)
|
48
|
+
setup_connection(sequel_connection)
|
49
|
+
|
42
50
|
@projections_database = sequel_connection
|
43
51
|
@event_tracker = Postgres::Tracker.new(sequel_connection)
|
44
52
|
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def setup_connection(sequel_connection)
|
57
|
+
return unless sequel_connection
|
58
|
+
|
59
|
+
sequel_connection.extension :pg_json
|
60
|
+
end
|
45
61
|
end
|
46
62
|
end
|
47
63
|
end
|
@@ -15,6 +15,17 @@ module EventSourcery
|
|
15
15
|
@event_builder = event_builder
|
16
16
|
end
|
17
17
|
|
18
|
+
# Like water flowing into a sink evenually it will go down the drain
|
19
|
+
# into the goodness of the plumbing system.
|
20
|
+
# So to will the given events you put in this 'sink'. Except the plumbing
|
21
|
+
# system is the data base events table.
|
22
|
+
# This can raise db connection errors.
|
23
|
+
#
|
24
|
+
# @param event_or_events the event or events to save
|
25
|
+
# @param expected_version the version to save with the event, default nil
|
26
|
+
#
|
27
|
+
# @raise [DatabaseError] if something goes wrong with the database
|
28
|
+
# @raise [ConcurrencyError] if there was a concurrency conflict
|
18
29
|
def sink(event_or_events, expected_version: nil)
|
19
30
|
events = Array(event_or_events)
|
20
31
|
aggregate_ids = events.map(&:aggregate_id).uniq
|
@@ -31,6 +42,15 @@ module EventSourcery
|
|
31
42
|
end
|
32
43
|
end
|
33
44
|
|
45
|
+
# Get the next set of events from the given event id. You can
|
46
|
+
# specify event typs and a limit.
|
47
|
+
# Default limit is 1000 and the default event types will be all.
|
48
|
+
#
|
49
|
+
# @param id the event id to get next envents from
|
50
|
+
# @param event_types the event types to filter, default nil = all
|
51
|
+
# @param limit the limit to the results, default 1000
|
52
|
+
#
|
53
|
+
# @return [Array] array of found events
|
34
54
|
def get_next_from(id, event_types: nil, limit: 1000)
|
35
55
|
query = events_table.
|
36
56
|
order(:id).
|
@@ -40,6 +60,11 @@ module EventSourcery
|
|
40
60
|
query.map { |event_row| build_event(event_row) }
|
41
61
|
end
|
42
62
|
|
63
|
+
# Get last event id for a given event types.
|
64
|
+
#
|
65
|
+
# @param event_types the type of event(s) to filter
|
66
|
+
#
|
67
|
+
# @return the latest event id
|
43
68
|
def latest_event_id(event_types: nil)
|
44
69
|
latest_event = events_table
|
45
70
|
latest_event = latest_event.where(type: event_types) if event_types
|
@@ -51,12 +76,23 @@ module EventSourcery
|
|
51
76
|
end
|
52
77
|
end
|
53
78
|
|
79
|
+
# Get the events for a given aggregate id.
|
80
|
+
#
|
81
|
+
# @param aggregate_id the aggregate id to filter for
|
82
|
+
#
|
83
|
+
# @return [Array] of found events
|
54
84
|
def get_events_for_aggregate_id(aggregate_id)
|
55
85
|
events_table.where(aggregate_id: aggregate_id.to_str).order(:version).map do |event_hash|
|
56
86
|
build_event(event_hash)
|
57
87
|
end
|
58
88
|
end
|
59
89
|
|
90
|
+
# Subscribe to events.
|
91
|
+
#
|
92
|
+
# @param from_id subscribe from a starting event id. default will be from the start.
|
93
|
+
# @param event_types the event_types to subscribe to, default all.
|
94
|
+
# @param after_listen the after listen call back block. default nil.
|
95
|
+
# @param subscription_master the subscription master block
|
60
96
|
def subscribe(from_id:, event_types: nil, after_listen: nil, subscription_master:, &block)
|
61
97
|
poll_waiter = OptimisedEventPollWaiter.new(pg_connection: @pg_connection, after_listen: after_listen)
|
62
98
|
args = {
|
@@ -11,18 +11,29 @@ module EventSourcery
|
|
11
11
|
end
|
12
12
|
|
13
13
|
module ClassMethods
|
14
|
+
# Assign the types of events this reactor can emit.
|
15
|
+
#
|
16
|
+
# @param event_types the types of events this reactor can emit
|
14
17
|
def emits_events(*event_types)
|
15
18
|
@emits_event_types = event_types
|
16
19
|
end
|
17
20
|
|
21
|
+
# @return [Array] an array of the types of events this reactor can emit
|
18
22
|
def emit_events
|
19
23
|
@emits_event_types ||= []
|
20
24
|
end
|
21
25
|
|
26
|
+
# This will tell you if this reactor emits any type of event.
|
27
|
+
#
|
28
|
+
# @return [true, false] true if this emits events, false if not
|
22
29
|
def emits_events?
|
23
30
|
!emit_events.empty?
|
24
31
|
end
|
25
32
|
|
33
|
+
# Will check if this reactor emits the given type of event.
|
34
|
+
#
|
35
|
+
# @param event_type the event type to check
|
36
|
+
# @return [true, false] true if it does emit the given event false if not
|
26
37
|
def emits_event?(event_type)
|
27
38
|
emit_events.include?(event_type)
|
28
39
|
end
|
@@ -3,6 +3,12 @@ module EventSourcery
|
|
3
3
|
module Schema
|
4
4
|
module_function
|
5
5
|
|
6
|
+
# This will create the event store tables and functions
|
7
|
+
# (event, aggregates, tracker and create or update functions)
|
8
|
+
# for the given Postgres database.
|
9
|
+
# The default will be the one specified in the config.
|
10
|
+
#
|
11
|
+
# @param db the Postgres database to use
|
6
12
|
def create_event_store(db: EventSourcery::Postgres.config.event_store_database,
|
7
13
|
events_table_name: EventSourcery::Postgres.config.events_table_name,
|
8
14
|
aggregates_table_name: EventSourcery::Postgres.config.aggregates_table_name,
|
@@ -12,6 +18,11 @@ module EventSourcery
|
|
12
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)
|
13
19
|
end
|
14
20
|
|
21
|
+
# Create the events table. Needs the database and the table name.
|
22
|
+
# The defaults will be whats specified in config.
|
23
|
+
#
|
24
|
+
# @param db the Postgres database to use
|
25
|
+
# @param table_name the name of the events table
|
15
26
|
def create_events(db: EventSourcery::Postgres.config.event_store_database,
|
16
27
|
table_name: EventSourcery::Postgres.config.events_table_name)
|
17
28
|
db.run 'CREATE EXTENSION IF NOT EXISTS "uuid-ossp"'
|
@@ -34,6 +45,11 @@ module EventSourcery
|
|
34
45
|
end
|
35
46
|
end
|
36
47
|
|
48
|
+
# Create the aggregates table. Needs the database and the table name.
|
49
|
+
# The defaults will be whats specified in config.
|
50
|
+
#
|
51
|
+
# @param db the Postgres database to use
|
52
|
+
# @param table_name the name of the aggregates table
|
37
53
|
def create_aggregates(db: EventSourcery::Postgres.config.event_store_database,
|
38
54
|
table_name: EventSourcery::Postgres.config.aggregates_table_name)
|
39
55
|
db.create_table(table_name) do
|
@@ -42,6 +58,14 @@ module EventSourcery
|
|
42
58
|
end
|
43
59
|
end
|
44
60
|
|
61
|
+
# Create the 'create or update' fucntions.
|
62
|
+
# Needs the database, table name, function name and aggregates table name.
|
63
|
+
# The defaults will be whats specified in config.
|
64
|
+
#
|
65
|
+
# @param db the Postgres database to use
|
66
|
+
# @param function_name the name of the write events function
|
67
|
+
# @param events_table_name the name of the events table
|
68
|
+
# @param aggregates_table_name the name of the aggregates table
|
45
69
|
def create_or_update_functions(db: EventSourcery::Postgres.config.event_store_database,
|
46
70
|
function_name: EventSourcery::Postgres.config.write_events_function_name,
|
47
71
|
events_table_name: EventSourcery::Postgres.config.events_table_name,
|
@@ -138,6 +162,11 @@ $$ language plpgsql;
|
|
138
162
|
SQL
|
139
163
|
end
|
140
164
|
|
165
|
+
# Create the projector tracker table. Needs the database and the table name.
|
166
|
+
# The defaults will be whats specified in config.
|
167
|
+
#
|
168
|
+
# @param db the Postgres database to use
|
169
|
+
# @param table_name the name of the aggregates table
|
141
170
|
def create_projector_tracker(db: EventSourcery::Postgres.config.projections_database,
|
142
171
|
table_name: EventSourcery::Postgres.config.tracker_table_name)
|
143
172
|
db.create_table(table_name) do
|
@@ -9,15 +9,23 @@ module EventSourcery
|
|
9
9
|
end
|
10
10
|
|
11
11
|
module ClassMethods
|
12
|
+
# Hash of the tables and thier corresponding blocks.
|
13
|
+
#
|
14
|
+
# @return [Hash] hash keyed by table names and block values
|
12
15
|
def tables
|
13
16
|
@tables ||= {}
|
14
17
|
end
|
15
18
|
|
19
|
+
# For the givent table name assign to give block as the value.
|
20
|
+
#
|
21
|
+
# @param name the name of the table
|
22
|
+
# @param block the block of code to assign for the table
|
16
23
|
def table(name, &block)
|
17
24
|
tables[name] = block
|
18
25
|
end
|
19
26
|
end
|
20
27
|
|
28
|
+
# Create each table.
|
21
29
|
def setup
|
22
30
|
self.class.tables.each do |table_name, schema_block|
|
23
31
|
prefixed_name = table_name_prefixed(table_name)
|
@@ -26,6 +34,7 @@ module EventSourcery
|
|
26
34
|
super if defined?(super)
|
27
35
|
end
|
28
36
|
|
37
|
+
# Reset by dropping each table.
|
29
38
|
def reset
|
30
39
|
self.class.tables.keys.each do |table_name|
|
31
40
|
prefixed_name = table_name_prefixed(table_name)
|
@@ -37,6 +46,8 @@ module EventSourcery
|
|
37
46
|
setup
|
38
47
|
end
|
39
48
|
|
49
|
+
# This will truncate all the tables and reset the tracker back to 0,
|
50
|
+
# done as a transaction.
|
40
51
|
def truncate
|
41
52
|
self.class.tables.each do |table_name, _|
|
42
53
|
@db_connection.transaction do
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module EventSourcery
|
2
2
|
module Postgres
|
3
|
+
# This will set up a persisted event id tracker for processors.
|
3
4
|
class Tracker
|
5
|
+
|
4
6
|
def initialize(connection = EventSourcery::Postgres.config.projections_database,
|
5
7
|
table_name: EventSourcery::Postgres.config.tracker_table_name,
|
6
8
|
obtain_processor_lock: true)
|
@@ -9,6 +11,11 @@ module EventSourcery
|
|
9
11
|
@obtain_processor_lock = obtain_processor_lock
|
10
12
|
end
|
11
13
|
|
14
|
+
# Set up the given processor.
|
15
|
+
# This will create the projector tracker table if it does not exits.
|
16
|
+
# If given a processor_name it will then attempt to get a lock on the db.
|
17
|
+
#
|
18
|
+
# @param processor_name the name of the procerror
|
12
19
|
def setup(processor_name = nil)
|
13
20
|
create_table_if_not_exists if EventSourcery::Postgres.config.auto_create_projector_tracker
|
14
21
|
|
@@ -24,6 +31,11 @@ module EventSourcery
|
|
24
31
|
end
|
25
32
|
end
|
26
33
|
|
34
|
+
# This will updated the tracker table to the given event id value
|
35
|
+
# for the given processor name.
|
36
|
+
#
|
37
|
+
# @param processor_name the name of the processor to udpate
|
38
|
+
# @param event_id the event id number to update to
|
27
39
|
def processed_event(processor_name, event_id)
|
28
40
|
table.
|
29
41
|
where(name: processor_name.to_s).
|
@@ -31,6 +43,12 @@ module EventSourcery
|
|
31
43
|
true
|
32
44
|
end
|
33
45
|
|
46
|
+
# This allows you to process an event and update the tracker table in
|
47
|
+
# a single transaction. Will yeild the given block first then update the
|
48
|
+
# the tracker table to the give event id for the given processor name.
|
49
|
+
#
|
50
|
+
# @param processor_name the name of the processor to update
|
51
|
+
# @param event_id the event id number to update to
|
34
52
|
def processing_event(processor_name, event_id)
|
35
53
|
@connection.transaction do
|
36
54
|
yield
|
@@ -38,15 +56,25 @@ module EventSourcery
|
|
38
56
|
end
|
39
57
|
end
|
40
58
|
|
59
|
+
# This will reset the tracker to the start (0) for the given processor name.
|
60
|
+
#
|
61
|
+
# @param processor_name the name of the processor to reset to 0
|
41
62
|
def reset_last_processed_event_id(processor_name)
|
42
63
|
table.where(name: processor_name.to_s).update(last_processed_event_id: 0)
|
43
64
|
end
|
44
65
|
|
66
|
+
# This will return the last processed event id for the given processor name.
|
67
|
+
#
|
68
|
+
# @param processor_name the name of the processor you want to look up
|
69
|
+
# @return [Int, nil] the value of the last event_id processed
|
45
70
|
def last_processed_event_id(processor_name)
|
46
71
|
track_entry = table.where(name: processor_name.to_s).first
|
47
72
|
track_entry[:last_processed_event_id] if track_entry
|
48
73
|
end
|
49
74
|
|
75
|
+
# Will return an array of all known tracked processors.
|
76
|
+
#
|
77
|
+
# @return [Array] array of all known tracked processors
|
50
78
|
def tracked_processors
|
51
79
|
table.select_map(:name)
|
52
80
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: event_sourcery-postgres
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Envato
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-07-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sequel
|
@@ -164,7 +164,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
164
164
|
version: '0'
|
165
165
|
requirements: []
|
166
166
|
rubyforge_project:
|
167
|
-
rubygems_version: 2.
|
167
|
+
rubygems_version: 2.5.2
|
168
168
|
signing_key:
|
169
169
|
specification_version: 4
|
170
170
|
summary: Postgres event store for use with EventSourcery
|