event_sourcery-postgres 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|