sandthorn_driver_sequel 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ea2f0e2d9a31debe7bd55f2e109e1ca2bacf952d
4
+ data.tar.gz: 1eb940ef766f8a4d0ee00dd493b25a625987234c
5
+ SHA512:
6
+ metadata.gz: dbe827666513d4a09c9ae9893d5242083030ac198237381cdfc7d60582712343efc6696da32e096b0727df3b8bff0d87d09344717ef0c84cc02656d3da91d405
7
+ data.tar.gz: 3e86d8133f06049141abfbca327c3530bc68ee05462ad4bea92cce9401e9a53dc08f1fb0f24e47ae9b7472bcfa1b655be61ff3579a21f488d0142e1f85e89ee7
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format d
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ sandthorn_driver_sequel
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.1
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in sandthorn_driver_sequel.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Morgan Hallgren
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # SandthornDriverSequel
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'sandthorn_driver_sequel'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install sandthorn_driver_sequel
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task default: :spec
@@ -0,0 +1,7 @@
1
+ module SandthornDriverSequel::Errors
2
+ class Error < StandardError; end
3
+ class ConcurrencyError < Error; end
4
+ class InternalError < Error; end
5
+ class NoAggregateError < Error; end
6
+ class WrongAggregateVersionError < Error; end
7
+ end
@@ -0,0 +1,187 @@
1
+ require 'sandthorn_driver_sequel/sequel_driver'
2
+
3
+ module SandthornDriverSequel
4
+ class EventStore
5
+ include EventStoreContext
6
+ attr_reader :driver, :context, :url
7
+ def initialize url: nil, context: nil
8
+ @driver = SequelDriver.new url: url
9
+ @context = context
10
+ @url = url
11
+ end
12
+
13
+ def save_events aggregate_events, originating_aggregate_version, aggregate_id, *class_name
14
+ current_aggregate_version = originating_aggregate_version
15
+ aggregate_type = class_name.first.to_s
16
+ driver.execute_in_transaction do |db|
17
+ if current_aggregate_version == 0
18
+ to_insert = {aggregate_id: aggregate_id, aggregate_type: aggregate_type, aggregate_version: 0}
19
+ pk_id = db[aggregates_table_name].insert(to_insert)
20
+ else
21
+ current_aggregate = get_current_aggregate_from_aggregates_table aggregate_id, aggregate_type, db
22
+ pk_id = current_aggregate[:id]
23
+ if current_aggregate[:aggregate_version] != current_aggregate_version
24
+ error_message = "#{aggregate_type} with id #{aggregate_id} should be att version #{current_aggregate_version} but was #{current_aggregate[:aggregate_version]} in the event store."
25
+ raise SandthornDriverSequel::Errors::WrongAggregateVersionError.new(error_message)
26
+ end
27
+ end
28
+ timestamp = Time.now.utc
29
+ aggregate_events.each do |event|
30
+ current_aggregate_version += 1
31
+ if current_aggregate_version != event[:aggregate_version]
32
+ error_message = "#{aggregate_type} with id #{aggregate_id}: expected event with version #{current_aggregate_version}, but got #{event[:aggregate_version]}"
33
+ raise SandthornDriverSequel::Errors::ConcurrencyError.new(error_message)
34
+ end
35
+ to_insert = {aggregate_table_id: pk_id, aggregate_version: event[:aggregate_version], event_name: event[:event_name], event_data: event[:event_data], timestamp: timestamp}
36
+ db[events_table_name].insert(to_insert)
37
+ end
38
+ db[aggregates_table_name].where(id: pk_id).update(aggregate_version: current_aggregate_version)
39
+ end
40
+ end
41
+
42
+ def save_snapshot aggregate_snapshot, aggregate_id, class_name
43
+ #ar_snapshot.event_name = snapshot[:event_name]
44
+ #ar_snapshot.event_data = snapshot[:event_data]
45
+ #ar_snapshot.aggregate_version = snapshot[:aggregate_version]
46
+ #ar_snapshot.aggregate_id = aggregate_id
47
+ driver.execute_in_transaction do |db|
48
+ current_aggregate = get_current_aggregate_from_aggregates_table aggregate_id, class_name, db
49
+ pk_id = current_aggregate[:id]
50
+ current_snapshot = get_current_snapshot pk_id, db
51
+ aggregate_version = aggregate_snapshot[:aggregate_version]
52
+ return if !current_snapshot.nil? && current_snapshot[:aggregate_version] == aggregate_version
53
+ if current_aggregate[:aggregate_version] < aggregate_version
54
+ error_message = "#{class_name} with id #{aggregate_id}: tried to save snapshot with version #{aggregate_version}, but current version is at #{current_aggregate[:aggregate_version]}"
55
+ raise SandthornDriverSequel::Errors::WrongAggregateVersionError.new error_message
56
+ end
57
+ if current_snapshot.nil?
58
+ to_insert = {aggregate_version: aggregate_version, snapshot_data: aggregate_snapshot[:event_data], aggregate_table_id: pk_id}
59
+ db[snapshots_table_name].insert(to_insert)
60
+ else
61
+ to_update = {aggregate_version: aggregate_version, snapshot_data: aggregate_snapshot[:event_data] }
62
+ db[snapshots_table_name].where(aggregate_table_id: pk_id).update(to_update)
63
+ end
64
+ end
65
+ end
66
+
67
+ def get_aggregate_events aggregate_id, *class_name
68
+ #aggregate_type = class_name.to_s unless class_name.nil?
69
+ return aggregate_events aggregate_id: aggregate_id
70
+ end
71
+
72
+ def get_aggregate aggregate_id, *class_name
73
+ snapshot = get_snapshot aggregate_id, class_name
74
+ after_aggregate_version = 0
75
+ after_aggregate_version = snapshot[:aggregate_version] unless snapshot.nil?
76
+ events = aggregate_events after_aggregate_version: after_aggregate_version, aggregate_id: aggregate_id
77
+ unless snapshot.nil?
78
+ snap_event = snapshot
79
+ snap_event[:event_name] = "aggregate_set_from_snapshot"
80
+ events = events.unshift(snap_event)
81
+ end
82
+ events
83
+ end
84
+ def get_aggregate_list_by_typename class_name
85
+ aggregate_type = class_name.to_s
86
+ driver.execute do |db|
87
+ db[aggregates_table_name].where(aggregate_type: aggregate_type).select(:aggregate_id).map { |e| e[:aggregate_id] }
88
+ end
89
+ end
90
+
91
+ def get_all_typenames
92
+ driver.execute do |db|
93
+ db[aggregates_table_name].select(:aggregate_type).distinct.order(:aggregate_type).map{|e| e[:aggregate_type]}
94
+ end
95
+ end
96
+
97
+ def get_snapshot aggregate_id, *class_name
98
+ aggregate_type = class_name.first.to_s
99
+ driver.execute do |db|
100
+ current_aggregate = get_current_aggregate_from_aggregates_table aggregate_id, aggregate_type, db
101
+ snap = get_current_snapshot current_aggregate[:id], db
102
+ return nil if snap.nil?
103
+ return {aggregate_version: snap[:aggregate_version], event_data: snap[:snapshot_data]}
104
+ end
105
+ end
106
+
107
+ def get_new_events_after_event_id_matching_classname event_id, class_name, args = {}
108
+ take = args.fetch(:take, 0)
109
+ aggregate_type = class_name.to_s
110
+ driver.execute do |db|
111
+ query = db[events_table_name].join(aggregates_table_name, id: :aggregate_table_id, aggregate_type: aggregate_type)
112
+ query = query.where{sequence_number > event_id}
113
+ rel = "#{events_table_name}__aggregate_version".to_sym
114
+ query = query.select(:aggregate_type, rel, :aggregate_id, :sequence_number, :event_name, :event_data, :timestamp)
115
+ query = query.limit(take) if take > 0
116
+ return query.order(:sequence_number).all
117
+ end
118
+ end
119
+ def get_events args = {}
120
+ classes = args.fetch(:classes, [])
121
+ after_sequence_number = args.fetch(:after_sequence_number) { raise ArgumentError.new "Must provide a :after_sequence_number-argument. 1 is first sequence_number, so use 0 if starting over." }
122
+ take = args.fetch(:take, 0)
123
+ include_events = args.fetch(:include_events, []).collect { |e| e.to_s }
124
+ exclude_events = args.fetch(:exclude_events, []).collect { |e| e.to_s }
125
+ aggregate_types = classes.collect { |e| e.to_s }
126
+ driver.execute do |db|
127
+ if aggregate_types.empty?
128
+ query = db[events_table_name].join(aggregates_table_name, id: :aggregate_table_id)
129
+ else
130
+ query = db[events_table_name].join(aggregates_table_name, id: :aggregate_table_id, aggregate_type: aggregate_types)
131
+ end
132
+ query = query.where{sequence_number > after_sequence_number}
133
+ unless include_events.empty?
134
+ query = query.where(event_name: include_events)
135
+ end
136
+ unless exclude_events.empty?
137
+ query = query.exclude(event_name: exclude_events)
138
+ end
139
+ rel = "#{events_table_name}__aggregate_version".to_sym
140
+ query = query.select(:aggregate_type, rel, :aggregate_id, :sequence_number, :event_name, :event_data, :timestamp)
141
+ query = query.limit(take) if take > 0
142
+ return query.order(:sequence_number).all
143
+ end
144
+ end
145
+ def obsolete_snapshots class_names: [], max_event_distance: 100
146
+ driver.execute do |db|
147
+ rel = "#{snapshots_table_name}__aggregate_version".to_sym
148
+ aggr_rel = "#{aggregates_table_name}__aggregate_version".to_sym
149
+ query_select = eval("lambda{(#{aggr_rel} - coalesce(#{rel},0)).as(distance)}")
150
+ query = db[aggregates_table_name].left_outer_join(snapshots_table_name, aggregate_table_id: :id)
151
+ query = query.select &query_select
152
+ query = query.select_append(:aggregate_id, :aggregate_type)
153
+ query_where = eval("lambda{(#{aggr_rel} - coalesce(#{rel},0)) > max_event_distance}")
154
+ query = query.where &query_where
155
+ unless class_names.empty?
156
+ class_names.map! {|c|c.to_s}
157
+ query = query.where(aggregate_type: class_names)
158
+ end
159
+ query.all
160
+ end
161
+ end
162
+ private
163
+ def aggregate_events after_aggregate_version: 0, aggregate_id: nil
164
+ rel = "#{events_table_name}__aggregate_version".to_sym
165
+ where_proc = eval("lambda{ #{rel} > after_aggregate_version }")
166
+ driver.execute do |db|
167
+ query = db[events_table_name].join(aggregates_table_name, id: :aggregate_table_id, aggregate_id: aggregate_id)
168
+ query = query.where &where_proc
169
+ return query.select(rel, :aggregate_id, :sequence_number, :event_name, :event_data, :timestamp).order(:sequence_number).all
170
+ end
171
+ end
172
+ def get_current_aggregate_from_aggregates_table aggregate_id, aggregate_type, db
173
+ aggregate_type = aggregate_type.to_s
174
+ current_aggregate = db[aggregates_table_name].where(aggregate_id: aggregate_id)
175
+ if current_aggregate.empty?
176
+ error_message = "#{aggregate_type} with id #{aggregate_id} was not found in the eventstore."
177
+ raise SandthornDriverSequel::Errors::NoAggregateError.new(error_message)
178
+ end
179
+ current_aggregate.first
180
+ end
181
+ def get_current_snapshot aggregate_table_id, db
182
+ snap = db[snapshots_table_name].where(aggregate_table_id: aggregate_table_id)
183
+ return nil if snap.empty?
184
+ snap.first
185
+ end
186
+ end
187
+ end
@@ -0,0 +1,17 @@
1
+ module SandthornDriverSequel
2
+ module EventStoreContext
3
+ def events_table_name
4
+ with_context_if_exists :events
5
+ end
6
+ def aggregates_table_name
7
+ with_context_if_exists :aggregates
8
+ end
9
+ def snapshots_table_name
10
+ with_context_if_exists :snapshots
11
+ end
12
+ def with_context_if_exists name
13
+ name = "#{context}_#{name}".to_sym if context
14
+ name
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,109 @@
1
+ require 'sandthorn_driver_sequel/sequel_driver'
2
+ module SandthornDriverSequel
3
+ class Migration
4
+ include EventStoreContext
5
+ attr_reader :driver, :context
6
+ def initialize url: nil, context: nil
7
+ @driver = SequelDriver.new url: url
8
+ @context = context
9
+ end
10
+ def migrate!
11
+ ensure_migration_table!
12
+ aggregates
13
+ events
14
+ snapshots
15
+ end
16
+ private
17
+ def clear_for_test
18
+ driver.execute do |db|
19
+ db[snapshots_table_name].truncate
20
+ db[events_table_name].truncate
21
+ db[aggregates_table_name].truncate
22
+ end
23
+ end
24
+ def aggregates
25
+ aggr_migration_0 = "#{aggregates_table_name}-20130308"
26
+ unless has_been_migrated?(aggr_migration_0)
27
+ driver.execute_in_transaction do |db|
28
+ db.create_table(aggregates_table_name) do
29
+ primary_key :id
30
+ String :aggregate_id, fixed: true, size: 36, null: false
31
+ Integer :aggregate_version, null: false
32
+ String :aggregate_type, size: 255, null: false
33
+ index [:aggregate_type]
34
+ index [:aggregate_type, :aggregate_id], unique: true
35
+ index [:aggregate_id], unique: true
36
+ end
37
+ was_migrated aggr_migration_0, db
38
+ end
39
+ end
40
+ end
41
+ def events
42
+ events_migration_0 = "#{events_table_name}-20130308"
43
+ unless has_been_migrated?(events_migration_0)
44
+ driver.execute_in_transaction do |db|
45
+ aggr_table = aggregates_table_name
46
+ db.create_table(events_table_name) do
47
+ primary_key :sequence_number
48
+ foreign_key :aggregate_table_id, aggr_table, on_update: :cascade
49
+ Integer :aggregate_version, null: false
50
+ String :event_name, size: 255, null: false
51
+ String :event_data, text: true, null: true
52
+ DateTime :timestamp, null: false
53
+
54
+ index [:event_name]
55
+ end
56
+ was_migrated events_migration_0, db
57
+ end
58
+ end
59
+
60
+ events_migration_1 = "#{events_table_name}-20131004"
61
+ unless has_been_migrated?(events_migration_1)
62
+ driver.execute_in_transaction do |db|
63
+ db.alter_table events_table_name do
64
+ add_index [:aggregate_table_id]
65
+ add_index [:aggregate_table_id,:aggregate_version], unique: true
66
+ end
67
+ was_migrated events_migration_1, db
68
+ end
69
+ end
70
+ end
71
+ def snapshots
72
+ snapshot_migration_0 = "#{snapshots_table_name}-20130312"
73
+ unless has_been_migrated?(snapshot_migration_0)
74
+ driver.execute_in_transaction do |db|
75
+ aggr_table = aggregates_table_name
76
+ db.create_table(snapshots_table_name) do
77
+ primary_key :id
78
+ Integer :aggregate_version, null: false
79
+ String :snapshot_data, text: true, null: false
80
+ foreign_key :aggregate_table_id, aggr_table, on_delete: :cascade, on_update: :cascade
81
+ index [:aggregate_table_id], unique: true
82
+ end
83
+ was_migrated snapshot_migration_0, db
84
+ end
85
+ end
86
+ end
87
+
88
+ def migration_table_name
89
+ :event_store_sequel_migrations
90
+ end
91
+ def ensure_migration_table!
92
+ driver.execute do |db|
93
+ db.create_table?(migration_table_name) do
94
+ primary_key :id
95
+ String :migration_name, null: false
96
+ index [:migration_name], unique: true
97
+ DateTime :timestamp, :null=>false
98
+ index [:migration_name], unique: true
99
+ end
100
+ end
101
+ end
102
+ def has_been_migrated? migration_name
103
+ driver.execute {|db| db[migration_table_name].all.any? { |e| e[:migration_name]==migration_name } }
104
+ end
105
+ def was_migrated migration_name, db
106
+ db[migration_table_name].insert timestamp: Time.now.utc, migration_name: migration_name
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,20 @@
1
+ require 'sequel'
2
+
3
+ module SandthornDriverSequel
4
+ class SequelDriver
5
+ def initialize args = {}
6
+ @url = args.fetch(:url)
7
+ Sequel.default_timezone = :utc
8
+ end
9
+ def execute &block
10
+ Sequel.connect(@url) { |db| return block.call db}
11
+ end
12
+ def execute_in_transaction &block
13
+ Sequel.connect(@url) do |db|
14
+ db.transaction do
15
+ return block.call db
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ module SandthornDriverSequel
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,17 @@
1
+ require "sandthorn_driver_sequel/version"
2
+ require "sandthorn_driver_sequel/event_store_context"
3
+ require 'sandthorn_driver_sequel/event_store'
4
+ require 'sandthorn_driver_sequel/errors'
5
+ require 'sandthorn_driver_sequel/migration'
6
+
7
+ module SandthornDriverSequel
8
+ class << self
9
+ def driver_from_url url: nil, context: nil
10
+ EventStore.new url: url, context: context
11
+ end
12
+ def migrate_db url: nil, context: nil
13
+ migrator = Migration.new url: url, context: context
14
+ migrator.migrate!
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,36 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'sandthorn_driver_sequel/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "sandthorn_driver_sequel"
8
+ spec.version = SandthornDriverSequel::VERSION
9
+ spec.authors = ["Lars Krantz", "Morgan Hallgren"]
10
+ spec.email = ["lars.krantz@alaz.se", "morgan.hallgren@gmail.com"]
11
+ spec.description = %q{sequel driver for sandthorn}
12
+ spec.summary = %q{sequel driver for sandthorn}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+
24
+ spec.add_development_dependency "rspec"
25
+ spec.add_development_dependency "gem-release"
26
+ spec.add_development_dependency "sqlite3"
27
+ spec.add_development_dependency "pry"
28
+ spec.add_development_dependency "pry-doc"
29
+ spec.add_development_dependency "awesome_print"
30
+ spec.add_development_dependency "autotest-standalone"
31
+ spec.add_development_dependency "uuidtools"
32
+ spec.add_development_dependency "ruby-beautify"
33
+
34
+ spec.add_runtime_dependency "sequel"
35
+ spec.add_runtime_dependency "pg"
36
+ end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ class Foo; end
4
+ class Bar; end
5
+
6
+ module SandthornDriverSequel
7
+
8
+ describe EventStore do
9
+ before(:each) { prepare_for_test }
10
+ context "when asking for aggregates to snapshot" do
11
+ let(:aggregates) {
12
+ [{id: "1", class_name: Foo}, {id: "2", class_name: Bar},{id: "3", class_name: Foo}]}
13
+
14
+ before(:each) {save_test_events}
15
+
16
+ context "when asking for type 'Bar' and max event count 5" do
17
+ let(:needs_snapshot) { event_store.obsolete_snapshots class_names: [Bar], max_event_distance: 5 }
18
+ context "and no snapshots exist" do
19
+ it "should return that id 2 with class Bar need to be snapshotted" do
20
+ expect(needs_snapshot.length).to eql 1
21
+ expect(needs_snapshot.first[:aggregate_id]).to eql aggregates[1][:id]
22
+ expect(needs_snapshot.first[:aggregate_type]).to eql "Bar"
23
+ end
24
+ end
25
+ context "and a recent snapshot exists" do
26
+ before(:each) { event_store.save_snapshot({ event_data: "YO MAN", aggregate_version: 11 }, aggregates[1][:id], aggregates[1][:class_name])}
27
+ it "should return empty array" do
28
+ expect(needs_snapshot).to be_empty
29
+ end
30
+ end
31
+ end
32
+
33
+
34
+ def save_test_events
35
+ for_1 = event_generator count: 4, start_at: 1
36
+ for_2 = event_generator count: 3, start_at: 1
37
+ for_3 = event_generator count: 6, start_at: 1
38
+ for_2_2 = event_generator count: 10, start_at: 4
39
+ for_1_2 = event_generator count: 1, start_at: 5
40
+ save_events for_1, 0
41
+ save_events for_2, 1
42
+ save_events for_3, 2
43
+ save_events for_1_2, 0
44
+ save_events for_2_2, 1
45
+ end
46
+ def save_events events, aggregate_index
47
+ event_store.save_events events, events.first[:aggregate_version]-1, aggregates[aggregate_index][:id], aggregates[aggregate_index][:class_name]
48
+ end
49
+
50
+ def event_generator count: 1, start_at: 1
51
+ events = []
52
+ i = 0
53
+ while i < count do
54
+ events << { aggregate_version: i+start_at, event_data: nil, event_name: "event_foo_#{i}" }
55
+ i += 1
56
+ end
57
+ events
58
+ end
59
+ end
60
+ end
61
+ end
Binary file
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+
3
+ module SandthornDriverSequel
4
+ describe EventStore do
5
+ before(:each) { prepare_for_test }
6
+ context "interface structure" do
7
+ let(:subject) {event_store}
8
+ it "should respond to save_events" do
9
+ subject.should respond_to("save_events")
10
+ end
11
+
12
+ it "should respond to save_snapshot" do
13
+ subject.should respond_to("save_snapshot")
14
+ end
15
+
16
+ it "should respond to get_aggregate" do
17
+ subject.should respond_to("get_aggregate")
18
+ end
19
+
20
+ it "should respond to get_aggregate_events" do
21
+ subject.should respond_to("get_aggregate_events")
22
+ end
23
+
24
+ it "should respond to get_aggregate_list_by_typename" do
25
+ subject.should respond_to("get_aggregate_list_by_typename")
26
+ end
27
+
28
+ it "should respond to get_all_typenames" do
29
+ subject.should respond_to("get_all_typenames")
30
+ end
31
+
32
+ it "should respond to get_snapshot" do
33
+ subject.should respond_to("get_snapshot")
34
+ end
35
+
36
+ it "should respond to get_new_events_after_event_id_matching_classname" do
37
+ subject.should respond_to("get_new_events_after_event_id_matching_classname")
38
+ end
39
+
40
+ it "should respond to get_events_after_sequence_id" do
41
+ subject.should respond_to(:get_events)
42
+ end
43
+ it("should respond to url"){ expect(subject).to respond_to :url }
44
+ it("should respond to context"){ expect(subject).to respond_to :context }
45
+ it("should respond to driver"){ expect(subject).to respond_to :driver }
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+ module SandthornDriverSequel
3
+ describe EventStore do
4
+ let(:context) { :event_store_spec }
5
+ before(:each) { prepare_for_test context: context; prepare_for_test context: nil; }
6
+ let(:event_store_with_context) { EventStore.new url: event_store_url, context: context }
7
+ let(:event_store_without_context) { EventStore.new url: event_store_url }
8
+ context("when saving in one context and retreiving in another") do
9
+ let(:test_events) do
10
+ e = []
11
+ e << {aggregate_version: 1, event_name: "new", event_args: nil, event_data: "---\n:method_name: new\n:method_args: []\n:attribute_deltas:\n- :attribute_name: :@aggregate_id\n :old_value: \n :new_value: 0a74e545-be84-4506-8b0a-73e947856327\n"}
12
+ e << {aggregate_version: 2, event_name: "foo", event_args: ["bar"], event_data: "noop"}
13
+ e << {aggregate_version: 3, event_name: "flubber", event_args: ["bar"] , event_data: "noop"}
14
+ end
15
+ let(:aggregate_id) {"c0456e26-e29a-4f67-92fa-130b3a31a39b"}
16
+ it "should not find them" do
17
+ event_store_without_context.save_events test_events, 0, aggregate_id, String
18
+ events = event_store_without_context.get_aggregate_events aggregate_id, String
19
+ expect(events.length).to eql test_events.length
20
+ events_2 = event_store_with_context.get_aggregate_events aggregate_id, String
21
+ expect(events_2.length).to eql 0
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,150 @@
1
+ require 'spec_helper'
2
+
3
+ module SandthornDriverSequel
4
+ describe EventStore do
5
+ before(:each) { prepare_for_test }
6
+ let(:test_events_a) do
7
+ e = []
8
+ e << {aggregate_version: 1, event_name: "new", event_data: "---\n:method_name: new\n:method_args: []\n:attribute_deltas:\n- :attribute_name: :@aggregate_id\n :old_value: \n :new_value: 0a74e545-be84-4506-8b0a-73e947856327\n"}
9
+ e << {aggregate_version: 2, event_name: "foo", event_data: "A2"}
10
+ e << {aggregate_version: 3, event_name: "bard", event_data: "A3"}
11
+ end
12
+ let(:aggregate_id_a) {"c0456e26-e29a-4f67-92fa-130b3a31a39a"}
13
+ let(:test_events_b) do
14
+ e = []
15
+ e << {aggregate_version: 1, event_name: "new", event_data: "B1" }
16
+ e << {aggregate_version: 2, event_name: "foo", event_data: "B2"}
17
+ e << {aggregate_version: 3, event_name: "bar", event_data: "B3"}
18
+ end
19
+ let(:aggregate_id_b) {"c0456e26-1234-4f67-92fa-130b3a31a39a"}
20
+ let(:test_events_c) do
21
+ e = []
22
+ e << {aggregate_version: 1, event_name: "new", event_data: "C1" }
23
+ end
24
+ let(:test_events_c_2) do
25
+ e = []
26
+ e << {aggregate_version: 2, event_name: "flubber", event_data: "C2" }
27
+ end
28
+ let(:aggregate_id_c) {"c0456e26-2345-4f67-92fa-130b3a31a39a"}
29
+ before(:each) do
30
+ event_store.save_events test_events_a, 0, aggregate_id_a, SandthornDriverSequel::EventStore
31
+ event_store.save_events test_events_c, 0, aggregate_id_c, String
32
+ event_store.save_events test_events_b, 0, aggregate_id_b, SandthornDriverSequel::SequelDriver
33
+ event_store.save_events test_events_c_2, 1, aggregate_id_c, String
34
+ end
35
+ context "when using get_events" do
36
+ context "and using take" do
37
+ let(:events) {event_store.get_events after_sequence_number: 0, include_events: [:new], take: 2}
38
+ it "should find 2 events" do
39
+ events.length.should eql 2
40
+ end
41
+ end
42
+ context "and getting events of type :new" do
43
+ let(:events) {event_store.get_events after_sequence_number: 0, include_events: [:new]}
44
+ it "should find 3 events" do
45
+ events.length.should eql 3
46
+ end
47
+ it "should only be new-events" do
48
+ events.all? { |e| e[:event_name] == "new" }
49
+ end
50
+ end
51
+ context "and combining args" do
52
+ let(:events) do
53
+ all = event_store.get_events after_sequence_number: 0
54
+ first_seq_number = all[0][:sequence_number]
55
+ event_store.get_events after_sequence_number: first_seq_number , exclude_events: [:foo], include_events: [:new, :foo, "bar", :flubber], take: 100
56
+ end
57
+ it "should find 4 events" do
58
+ events.length.should eql 4
59
+ end
60
+ it "should not be any foo-events" do
61
+ events.all? { |e| e[:event_name] != "foo" }
62
+ end
63
+ end
64
+ context "and getting all events but excluding new" do
65
+ let(:events) {event_store.get_events after_sequence_number: 0, exclude_events: [:new] }
66
+ it "should find 5 events" do
67
+ events.length.should eql 5
68
+ end
69
+ it "should only be new and foo-events" do
70
+ events.all? { |e| e[:event_name] != "new" }
71
+ end
72
+ end
73
+ context "and getting events of type :new and foo" do
74
+ let(:events) {event_store.get_events after_sequence_number: 0, classes: ["String", SandthornDriverSequel::EventStore], include_events: [:new, "foo"]}
75
+ it "should find 3 events" do
76
+ events.length.should eql 3
77
+ end
78
+ it "should only be new and foo-events" do
79
+ events.all? { |e| e[:event_name] == "new" || e[:event_name] == "foo" }
80
+ end
81
+ end
82
+ context "and getting events for SandthornDriverSequel::EventStore, and String after 0" do
83
+ let(:events) {event_store.get_events after_sequence_number: 0, classes: [SandthornDriverSequel::EventStore, String]}
84
+ it "should find 5 events" do
85
+ events.length.should eql 5
86
+ end
87
+ it "should be in sequence_number order" do
88
+ check = 0
89
+ events.each { |e| e[:sequence_number].should be > check; check = e[:sequence_number] }
90
+ end
91
+ it "should contain only events for aggregate_id_a and aggregate_id_c" do
92
+ events.each { |e| [aggregate_id_a, aggregate_id_c].include?(e[:aggregate_id]).should be_true }
93
+ end
94
+ end
95
+ context "and getting events for SandthornDriverSequel::EventStore after 0" do
96
+ let(:events) {event_store.get_events after_sequence_number: 0, classes: [SandthornDriverSequel::EventStore]}
97
+ it "should find 3 events" do
98
+ events.length.should eql 3
99
+ end
100
+ it "should be in sequence_number order" do
101
+ check = 0
102
+ events.each { |e| e[:sequence_number].should be > check; check = e[:sequence_number] }
103
+ end
104
+ it "should contain only events for aggregate_id_a" do
105
+ events.each { |e| e[:aggregate_id].should eql aggregate_id_a }
106
+ end
107
+ end
108
+ end
109
+ context "when using :get_new_events_after_event_id_matching_classname to get events" do
110
+ context "and getting events for SandthornDriverSequel::EventStore after 0" do
111
+ let(:events) {event_store.get_new_events_after_event_id_matching_classname 0, SandthornDriverSequel::EventStore}
112
+ it "should find 3 events" do
113
+ events.length.should eql 3
114
+ end
115
+ it "should be in sequence_number order" do
116
+ check = 0
117
+ events.each { |e| e[:sequence_number].should be > check; check = e[:sequence_number] }
118
+ end
119
+ it "should contain only events for aggregate_id_a" do
120
+ events.each { |e| e[:aggregate_id].should eql aggregate_id_a }
121
+ end
122
+ it "should be able to get events after a sequence number" do
123
+ new_from = events[1][:sequence_number]
124
+ ev = event_store.get_new_events_after_event_id_matching_classname new_from, SandthornDriverSequel::EventStore
125
+ ev.last[:aggregate_version].should eql 3
126
+ ev.length.should eql 1
127
+ end
128
+ it "should be able to limit the number of results" do
129
+ ev = event_store.get_new_events_after_event_id_matching_classname 0, SandthornDriverSequel::EventStore, take: 2
130
+ ev.length.should eql 2
131
+ ev.last[:aggregate_version].should eql 2
132
+ end
133
+ end
134
+ context "and getting events for String after 0" do
135
+ let(:events) {event_store.get_new_events_after_event_id_matching_classname 0, "String"}
136
+ it "should find 3 events" do
137
+ events.length.should eql 2
138
+ end
139
+ it "should be in sequence_number order" do
140
+ check = 0
141
+ events.each { |e| e[:sequence_number].should be > check; check = e[:sequence_number] }
142
+ end
143
+ it "should contain only events for aggregate_id_c" do
144
+ events.each { |e| e[:aggregate_id].should eql aggregate_id_c }
145
+ end
146
+ end
147
+ end
148
+
149
+ end
150
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ module SandthornDriverSequel
4
+ describe Migration do
5
+ def check_tables context = nil
6
+ events = :events
7
+ aggregates = :aggregates
8
+ snapshots = :snapshots
9
+ if context
10
+ events = "#{context}_#{events}".to_sym
11
+ aggregates = "#{context}_#{aggregates}".to_sym
12
+ snapshots = "#{context}_#{snapshots}".to_sym
13
+ end
14
+ migration.driver.execute do |db|
15
+ expect(db.table_exists? events).to be_true, "expected table :#{events} to exist, but it didn't"
16
+ expect(db.table_exists? aggregates).to be_true, "expected table :#{aggregates} to exist, but it didn't"
17
+ expect(db.table_exists? snapshots).to be_true, "expected table :#{snapshots} to exist, but it didn't"
18
+ end
19
+ end
20
+ let(:migration) { Migration.new url: event_store_url, context: context }
21
+ before(:each) { migration.migrate! }
22
+ context "when default (nil) eventstore contex" do
23
+ let(:context) { nil }
24
+ it "should create the tables events, aggregates and snapshots" do
25
+ check_tables
26
+ end
27
+ end
28
+ context "when specifying context" do
29
+ let(:context) { :another_domain }
30
+ it "should create the tables events, aggregates and snapshots" do
31
+ check_tables context
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+
3
+ module SandthornDriverSequel
4
+ describe EventStore do
5
+ before(:each) { prepare_for_test }
6
+ context "when saving a prefectly sane event stream" do
7
+ let(:test_events) do
8
+ e = []
9
+ e << {aggregate_version: 1, event_name: "new", event_args: nil, event_data: "---\n:method_name: new\n:method_args: []\n:attribute_deltas:\n- :attribute_name: :@aggregate_id\n :old_value: \n :new_value: 0a74e545-be84-4506-8b0a-73e947856327\n"}
10
+ e << {aggregate_version: 2, event_name: "foo", event_args: ["bar"], event_data: "noop"}
11
+ e << {aggregate_version: 3, event_name: "flubber", event_args: ["bar"] , event_data: "noop"}
12
+ end
13
+ let(:aggregate_id) {"c0456e26-e29a-4f67-92fa-130b3a31a39a"}
14
+ it "should be able to save and retreive events on the aggregate" do
15
+ event_store.save_events test_events, 0, aggregate_id, String
16
+ events = event_store.get_aggregate_events aggregate_id, String
17
+ events.length.should eql test_events.length
18
+ end
19
+ it "should fail if aggregate does not exist and version is above 0" do
20
+ expect { event_store.save_events test_events, 1, aggregate_id, String }.to raise_error SandthornDriverSequel::Errors::NoAggregateError
21
+ end
22
+ it "should fail if originating version is wrong" do
23
+ event_store.save_events test_events, 0, aggregate_id, String
24
+ expect { event_store.save_events test_events, 102, aggregate_id, String }.to raise_error SandthornDriverSequel::Errors::WrongAggregateVersionError
25
+ end
26
+ it "should have correct keys when asking for events" do
27
+ event_store.save_events test_events, 0, aggregate_id, String
28
+ events = event_store.get_aggregate aggregate_id, String
29
+ event = events.first
30
+ event[:event_data].should eql(test_events.first[:event_data])
31
+ event[:event_name].should eql("new")
32
+ event[:aggregate_id].should eql aggregate_id
33
+ event[:aggregate_version].should eql 1
34
+ event[:sequence_number].should be_a(Fixnum)
35
+ event[:timestamp].should be_a(Time)
36
+ end
37
+ end
38
+ context "when saving two aggregate types" do
39
+ let(:test_events_1) do
40
+ e = []
41
+ e << {aggregate_version: 1, event_name: "new", event_args: nil, event_data: "---\n:method_name: new\n:method_args: []\n:attribute_deltas:\n- :attribute_name: :@aggregate_id\n :old_value: \n :new_value: 0a74e545-be84-4506-8b0a-73e947856327\n"}
42
+ e << {aggregate_version: 2, event_name: "foo", event_args: ["bar", event_data: "noop"]}
43
+ e << {aggregate_version: 3, event_name: "flubber", event_args: ["bar", event_data: "noop"]}
44
+ end
45
+ let(:test_events_2) do
46
+ e = []
47
+ e << {aggregate_version: 1, event_name: "new", event_args: nil, event_data: "---\n:method_name: new\n:method_args: []\n:attribute_deltas:\n- :attribute_name: :@aggregate_id\n :old_value: \n :new_value: 0a74e545-be84-4506-8b0a-73e947856327\n"}
48
+ end
49
+ let(:aggregate_id_1) {"c0456e26-e29a-4f67-92fa-130b3a31a39a"}
50
+ let(:aggregate_id_2) {"c0456e26-e92b-4f67-92fa-130b3a31b93b"}
51
+ let(:aggregate_id_3) {"c0456e26-e92b-1234-92fa-130b3a31b93b"}
52
+ before(:each) do
53
+ event_store.save_events test_events_1, 0, aggregate_id_1, String
54
+ event_store.save_events test_events_2, 0, aggregate_id_2, Hash
55
+ event_store.save_events test_events_2, 0, aggregate_id_3, String
56
+ end
57
+ it "both types should exist in get_all_typenames in alphabetical order" do
58
+ names = event_store.get_all_typenames
59
+ names.length.should eql 2
60
+ names.first.should eql "Hash"
61
+ names.last.should eql "String"
62
+ end
63
+ it "should list the aggregate ids when asking for get_aggregate_list_by_typename" do
64
+ ids = event_store.get_aggregate_list_by_typename String
65
+ ids.length.should eql 2
66
+ ids.any? { |e| e == aggregate_id_1 }.should be_true
67
+ ids.any? { |e| e == aggregate_id_3 }.should be_true
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,76 @@
1
+ require 'spec_helper'
2
+
3
+ module SandthornDriverSequel
4
+ describe EventStore do
5
+ before(:each) { prepare_for_test }
6
+ let(:aggregate_id) { @id ||= UUIDTools::UUID.random_create.to_s }
7
+ let(:test_events) { [{aggregate_version: 1, event_data: nil, event_name: "new"},{aggregate_version: 2, event_data: nil, event_name: "foo"}] }
8
+ let(:additional_events) { [{aggregate_version: 3, event_data: nil, event_name: "klopp"},{aggregate_version: 4, event_data: nil, event_name: "flipp"}] }
9
+ let(:snapshot_data) { { event_data: "YO MAN", aggregate_version: 2 } }
10
+ let(:save_snapshot) {event_store.save_snapshot snapshot_data, aggregate_id, SandthornDriverSequel::EventStore}
11
+ let(:save_events) {event_store.save_events test_events, 0, aggregate_id, SandthornDriverSequel::EventStore}
12
+ let(:save_additional_events) {event_store.save_events additional_events, 2, aggregate_id, SandthornDriverSequel::EventStore}
13
+ context "when loading an aggregate using get_aggregate" do
14
+ context "and it has a snapshot" do
15
+ before(:each) do
16
+ save_events
17
+ save_snapshot
18
+ save_additional_events
19
+ end
20
+ let(:events) { event_store.get_aggregate aggregate_id, SandthornDriverSequel::EventStore }
21
+ it "should have the first event as :aggregate_set_from_snapshot" do
22
+ expect(events.first[:event_name]).to eql "aggregate_set_from_snapshot"
23
+ end
24
+ it "should have additional events after first snapshot-event" do
25
+ expect(events.length).to eql 1+additional_events.length
26
+ expect(events[1][:aggregate_version]).to eql additional_events[0][:aggregate_version]
27
+ expect(events.last[:aggregate_version]).to eql additional_events.last[:aggregate_version]
28
+ end
29
+ end
30
+
31
+ end
32
+ context "when saving a snapshot" do
33
+
34
+ context "and events are saved beforehand" do
35
+ before(:each) { save_events }
36
+ it "should be able to save snapshot" do
37
+ expect { save_snapshot }.to_not raise_error
38
+ end
39
+ it "should be able to save and get snapshot" do
40
+ save_snapshot
41
+ snap = event_store.get_snapshot aggregate_id, SandthornDriverSequel::EventStore
42
+ snap.should eql snapshot_data
43
+ end
44
+ end
45
+ context "when trying to save a snapshot on a non-existing aggregate" do
46
+ it "should raise a NonAggregateError" do
47
+ expect { save_snapshot }.to raise_error SandthornDriverSequel::Errors::NoAggregateError
48
+ end
49
+ end
50
+ context "when trying to save a snapshot with a non-existing aggregate_version" do
51
+ before(:each) { save_events }
52
+ it "should raise a WrongAggregateVersion error" do
53
+ data = snapshot_data
54
+ data[:aggregate_version] = 100
55
+ expect {event_store.save_snapshot data, aggregate_id, SandthornDriverSequel::EventStore}.to raise_error SandthornDriverSequel::Errors::WrongAggregateVersionError
56
+ end
57
+ end
58
+ context "when saving a snapshot twice" do
59
+ before(:each) { save_events; save_snapshot }
60
+ it "should not raise error" do
61
+ expect { save_snapshot }.to_not raise_error
62
+ end
63
+ end
64
+ context "when saving a snapshot on a version less than current version" do
65
+ before(:each) { save_events; }
66
+ it "should save without protesting" do
67
+ data = snapshot_data
68
+ data[:aggregate_version] = 1
69
+ event_store.save_snapshot data, aggregate_id, SandthornDriverSequel::EventStore
70
+ snap = event_store.get_snapshot aggregate_id, SandthornDriverSequel::EventStore
71
+ snap.should eql data
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,29 @@
1
+ require 'sandthorn_driver_sequel'
2
+ require 'sandthorn_driver_sequel/migration'
3
+ require 'ap'
4
+ require 'uuidtools'
5
+ # This file was generated by the `rspec --init` command. Conventionally, all
6
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
7
+ # Require this file using `require "spec_helper"` to ensure that it is only
8
+ # loaded once.
9
+ #
10
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
11
+ RSpec.configure do |config|
12
+ config.treat_symbols_as_metadata_keys_with_true_values = true
13
+ config.run_all_when_everything_filtered = true
14
+ config.filter_run :focus
15
+ config.order = 'random'
16
+ end
17
+ def prepare_for_test context: :test
18
+ migrator = SandthornDriverSequel::Migration.new url: event_store_url, context: context
19
+ migrator.migrate!
20
+ migrator.send(:clear_for_test)
21
+ end
22
+
23
+ def event_store_url
24
+ "sqlite://spec/db/event_store.sqlite3"
25
+ end
26
+
27
+ def event_store context: :test
28
+ SandthornDriverSequel::EventStore.new url: event_store_url, context: context
29
+ end
metadata ADDED
@@ -0,0 +1,263 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sandthorn_driver_sequel
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Lars Krantz
8
+ - Morgan Hallgren
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-02-28 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '1.3'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '1.3'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rake
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rspec
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: gem-release
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: sqlite3
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: pry
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: pry-doc
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ - !ruby/object:Gem::Dependency
113
+ name: awesome_print
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: autotest-standalone
128
+ requirement: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ type: :development
134
+ prerelease: false
135
+ version_requirements: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ - !ruby/object:Gem::Dependency
141
+ name: uuidtools
142
+ requirement: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ type: :development
148
+ prerelease: false
149
+ version_requirements: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
154
+ - !ruby/object:Gem::Dependency
155
+ name: ruby-beautify
156
+ requirement: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ version: '0'
161
+ type: :development
162
+ prerelease: false
163
+ version_requirements: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ version: '0'
168
+ - !ruby/object:Gem::Dependency
169
+ name: sequel
170
+ requirement: !ruby/object:Gem::Requirement
171
+ requirements:
172
+ - - ">="
173
+ - !ruby/object:Gem::Version
174
+ version: '0'
175
+ type: :runtime
176
+ prerelease: false
177
+ version_requirements: !ruby/object:Gem::Requirement
178
+ requirements:
179
+ - - ">="
180
+ - !ruby/object:Gem::Version
181
+ version: '0'
182
+ - !ruby/object:Gem::Dependency
183
+ name: pg
184
+ requirement: !ruby/object:Gem::Requirement
185
+ requirements:
186
+ - - ">="
187
+ - !ruby/object:Gem::Version
188
+ version: '0'
189
+ type: :runtime
190
+ prerelease: false
191
+ version_requirements: !ruby/object:Gem::Requirement
192
+ requirements:
193
+ - - ">="
194
+ - !ruby/object:Gem::Version
195
+ version: '0'
196
+ description: sequel driver for sandthorn
197
+ email:
198
+ - lars.krantz@alaz.se
199
+ - morgan.hallgren@gmail.com
200
+ executables: []
201
+ extensions: []
202
+ extra_rdoc_files: []
203
+ files:
204
+ - ".gitignore"
205
+ - ".rspec"
206
+ - ".ruby-gemset"
207
+ - ".ruby-version"
208
+ - Gemfile
209
+ - LICENSE.txt
210
+ - README.md
211
+ - Rakefile
212
+ - lib/sandthorn_driver_sequel.rb
213
+ - lib/sandthorn_driver_sequel/errors.rb
214
+ - lib/sandthorn_driver_sequel/event_store.rb
215
+ - lib/sandthorn_driver_sequel/event_store_context.rb
216
+ - lib/sandthorn_driver_sequel/migration.rb
217
+ - lib/sandthorn_driver_sequel/sequel_driver.rb
218
+ - lib/sandthorn_driver_sequel/version.rb
219
+ - sandthorn_driver_sequel.gemspec
220
+ - spec/asking_for_aggregates_to_snapshot_spec.rb
221
+ - spec/db/event_store.sqlite3
222
+ - spec/driver_interface_spec.rb
223
+ - spec/event_store_with_context_spec.rb
224
+ - spec/get_events_spec.rb
225
+ - spec/migration_specifying_domain_spec.rb
226
+ - spec/saving_events_spec.rb
227
+ - spec/saving_snapshot_spec.rb
228
+ - spec/spec_helper.rb
229
+ homepage: ''
230
+ licenses:
231
+ - MIT
232
+ metadata: {}
233
+ post_install_message:
234
+ rdoc_options: []
235
+ require_paths:
236
+ - lib
237
+ required_ruby_version: !ruby/object:Gem::Requirement
238
+ requirements:
239
+ - - ">="
240
+ - !ruby/object:Gem::Version
241
+ version: '0'
242
+ required_rubygems_version: !ruby/object:Gem::Requirement
243
+ requirements:
244
+ - - ">="
245
+ - !ruby/object:Gem::Version
246
+ version: '0'
247
+ requirements: []
248
+ rubyforge_project:
249
+ rubygems_version: 2.2.2
250
+ signing_key:
251
+ specification_version: 4
252
+ summary: sequel driver for sandthorn
253
+ test_files:
254
+ - spec/asking_for_aggregates_to_snapshot_spec.rb
255
+ - spec/db/event_store.sqlite3
256
+ - spec/driver_interface_spec.rb
257
+ - spec/event_store_with_context_spec.rb
258
+ - spec/get_events_spec.rb
259
+ - spec/migration_specifying_domain_spec.rb
260
+ - spec/saving_events_spec.rb
261
+ - spec/saving_snapshot_spec.rb
262
+ - spec/spec_helper.rb
263
+ has_rdoc: