sandthorn_driver_sequel 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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: