event_sourced_record 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +25 -0
- data/Appraisals +8 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +131 -0
- data/Rakefile +10 -0
- data/event_sourced_record.gemspec +37 -0
- data/lib/event_sourced_record/calculator.rb +101 -0
- data/lib/event_sourced_record/event/event_type_config.rb +30 -0
- data/lib/event_sourced_record/event.rb +94 -0
- data/lib/event_sourced_record/version.rb +3 -0
- data/lib/event_sourced_record.rb +7 -0
- data/lib/generators/event_sourced_record/USAGE +8 -0
- data/lib/generators/event_sourced_record/calculator_generator.rb +19 -0
- data/lib/generators/event_sourced_record/event_generator.rb +40 -0
- data/lib/generators/event_sourced_record/event_sourced_record_generator.rb +41 -0
- data/lib/generators/event_sourced_record/observer_generator.rb +34 -0
- data/lib/generators/event_sourced_record/projection_generator.rb +50 -0
- data/lib/generators/event_sourced_record/templates/calculator.rb +7 -0
- data/lib/generators/event_sourced_record/templates/event_model.rb +13 -0
- data/lib/generators/event_sourced_record/templates/observer.rb +8 -0
- data/lib/generators/event_sourced_record/templates/projection_model.rb +15 -0
- data/lib/generators/rspec/service_generator.rb +15 -0
- data/lib/generators/rspec/templates/service_spec.rb +6 -0
- data/lib/generators/test_unit/service_generator.rb +15 -0
- data/lib/generators/test_unit/templates/service_test.rb +9 -0
- data/test/event_sourced_record/calculator_test.rb +111 -0
- data/test/event_sourced_record/event_test.rb +112 -0
- data/test/generators/calculator_generator_test.rb +25 -0
- data/test/generators/event_generator_test.rb +35 -0
- data/test/generators/event_sourced_record_generator_test.rb +38 -0
- data/test/generators/observer_generator_test.rb +19 -0
- data/test/generators/projection_generator_test.rb +36 -0
- data/test/generators/templates/application.rb +12 -0
- data/test/test_helper.rb +82 -0
- metadata +217 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
<% module_namespacing do -%>
|
2
|
+
class <%= projection_class_name %> < <%= projection_parent_class_name.classify %>
|
3
|
+
<% attributes.select(&:reference?).each do |attribute| -%>
|
4
|
+
belongs_to :<%= attribute.name %><%= ', polymorphic: true' if attribute.polymorphic? %>
|
5
|
+
<% end -%>
|
6
|
+
has_many :<%= file_name %>_events
|
7
|
+
<% if attributes.any?(&:password_digest?) -%>
|
8
|
+
has_secure_password
|
9
|
+
<% end -%>
|
10
|
+
|
11
|
+
validates :uuid, uniqueness: true
|
12
|
+
end
|
13
|
+
<% end -%>
|
14
|
+
|
15
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'generators/rspec'
|
2
|
+
|
3
|
+
module Rspec
|
4
|
+
module Generators # :nodoc:
|
5
|
+
class ServiceGenerator < Base # :nodoc:
|
6
|
+
source_root File.expand_path('../templates', __FILE__)
|
7
|
+
check_class_collision suffix: "ServiceTest"
|
8
|
+
|
9
|
+
def create_service_files
|
10
|
+
template 'service_spec.rb', File.join('spec/services', class_path, "#{file_name}_spec.rb")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rails/generators/test_unit'
|
2
|
+
|
3
|
+
module TestUnit # :nodoc:
|
4
|
+
module Generators # :nodoc:
|
5
|
+
class ServiceGenerator < Base # :nodoc:
|
6
|
+
source_root File.expand_path('../templates', __FILE__)
|
7
|
+
check_class_collision suffix: "ServiceTest"
|
8
|
+
|
9
|
+
def create_service_files
|
10
|
+
template 'service_test.rb', File.join('test/services', class_path, "#{file_name}_test.rb")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class EventSourcedRecord::CalculatorTest < MiniTest::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@event = SubscriptionEvent.creation.create!(
|
6
|
+
bottles_per_shipment: 1, bottles_purchased: 6, user_id: 12345
|
7
|
+
)
|
8
|
+
assert @event.subscription_uuid
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_run_when_the_sourced_record_doesnt_exist
|
12
|
+
calculator = SubscriptionCalculator.new(@event.subscription_uuid)
|
13
|
+
subscription = calculator.run
|
14
|
+
assert_equal(1, subscription.bottles_per_shipment)
|
15
|
+
assert_equal(6, subscription.bottles_left)
|
16
|
+
assert_equal(@event.subscription_uuid, subscription.uuid)
|
17
|
+
assert !subscription.persisted?
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_run_when_the_sourced_record_already_exists
|
21
|
+
subscription = Subscription.create!(uuid: @event.subscription_uuid)
|
22
|
+
calculator = SubscriptionCalculator.new(@event.subscription_uuid)
|
23
|
+
subscription_prime = calculator.run
|
24
|
+
assert_equal(1, subscription_prime.bottles_per_shipment)
|
25
|
+
assert_equal(6, subscription_prime.bottles_left)
|
26
|
+
assert_equal(@event.subscription_uuid, subscription.uuid)
|
27
|
+
assert_equal(subscription.id, subscription_prime.id)
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_run_and_save_when_the_sourced_record_doesnt_exist
|
31
|
+
calculator = SubscriptionCalculator.new(@event.subscription_uuid)
|
32
|
+
subscription = calculator.run.tap(&:save!)
|
33
|
+
assert_equal(1, subscription.bottles_per_shipment)
|
34
|
+
assert_equal(6, subscription.bottles_left)
|
35
|
+
assert_equal(@event.subscription_uuid, subscription.uuid)
|
36
|
+
assert subscription.persisted?
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_run_and_save_when_the_sourced_record_already_exists
|
40
|
+
subscription = Subscription.create!(uuid: @event.subscription_uuid)
|
41
|
+
subscription_count = Subscription.count
|
42
|
+
calculator = SubscriptionCalculator.new(@event.subscription_uuid)
|
43
|
+
subscription_prime = calculator.run.tap(&:save!)
|
44
|
+
assert_equal(subscription_count, Subscription.count)
|
45
|
+
assert_equal(1, subscription_prime.bottles_per_shipment)
|
46
|
+
assert_equal(6, subscription_prime.bottles_left)
|
47
|
+
assert_equal(@event.subscription_uuid, subscription.uuid)
|
48
|
+
assert_equal(subscription.id, subscription_prime.id)
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_run_with_a_different_event_class
|
52
|
+
event = SubscriptionEvent.creation.create!(
|
53
|
+
bottles_per_shipment: 1, bottles_purchased: 6, user_id: 99999
|
54
|
+
)
|
55
|
+
subscription = SubscriptionCalculator.new(event.subscription_uuid).run.tap(&:save!)
|
56
|
+
assert_equal(6, subscription.bottles_left)
|
57
|
+
Shipment.create!(subscription_id: subscription.id, num_bottles: 3)
|
58
|
+
SubscriptionCalculator.new(event.subscription_uuid).run.tap(&:save!)
|
59
|
+
subscription.reload
|
60
|
+
assert_equal(3, subscription.bottles_left)
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_initialize_by_projection_or_id_or_event_or_associated_event
|
64
|
+
event = SubscriptionEvent.creation.create!(
|
65
|
+
bottles_per_shipment: 1, bottles_purchased: 6, user_id: 99999
|
66
|
+
)
|
67
|
+
subscription = SubscriptionCalculator.new(event).run.tap(&:save!)
|
68
|
+
shipment = Shipment.create!(
|
69
|
+
subscription_id: subscription.id, num_bottles: 3
|
70
|
+
)
|
71
|
+
lookups = [subscription, subscription.id, event, shipment]
|
72
|
+
lookups.each do |lookup|
|
73
|
+
calculator = SubscriptionCalculator.new(lookup)
|
74
|
+
assert_equal(
|
75
|
+
subscription, calculator.run,
|
76
|
+
"Can't find subscription with lookup #{lookup.inspect}"
|
77
|
+
)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_run_modifies_a_different_instance
|
82
|
+
event = SubscriptionEvent.creation.create!(
|
83
|
+
bottles_per_shipment: 1, bottles_purchased: 6, user_id: 99999
|
84
|
+
)
|
85
|
+
subscription = SubscriptionCalculator.new(event).run.tap(&:save!)
|
86
|
+
subscription.bottles_left = 999
|
87
|
+
SubscriptionCalculator.new(subscription).run
|
88
|
+
assert_equal(999, subscription.bottles_left)
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_last_event_time
|
92
|
+
event = SubscriptionEvent.creation.create!(
|
93
|
+
bottles_per_shipment: 1, bottles_purchased: 6, user_id: 99999,
|
94
|
+
created_at: Time.utc(2015,1,1)
|
95
|
+
)
|
96
|
+
subscription = SubscriptionCalculator.new(event).run.tap(&:save!)
|
97
|
+
Shipment.create!(
|
98
|
+
subscription_id: subscription.id, num_bottles: 3,
|
99
|
+
created_at: Time.utc(2015,1,4,12)
|
100
|
+
)
|
101
|
+
calculator = SubscriptionCalculator.new(subscription)
|
102
|
+
result1 = calculator.run(last_event_time: Date.new(2015,1,1))
|
103
|
+
assert_equal(6, result1.bottles_left)
|
104
|
+
result2 = calculator.run(last_event_time: Time.utc(2015,1,4))
|
105
|
+
assert_equal(6, result2.bottles_left)
|
106
|
+
result3 = calculator.run(last_event_time: Time.utc(2015,1,5))
|
107
|
+
assert_equal(3, result3.bottles_left)
|
108
|
+
result4 = calculator.run(last_event_time: Date.new(2015,1,5))
|
109
|
+
assert_equal(3, result4.bottles_left)
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class EventSourcedRecord::EventTest < MiniTest::Unit::TestCase
|
4
|
+
def test_creation_auto_generates_uuid
|
5
|
+
event = SubscriptionEvent.creation.new
|
6
|
+
assert event.subscription_uuid
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_creation_data_assignment
|
10
|
+
event = SubscriptionEvent.creation.new(
|
11
|
+
bottles_per_shipment: 1, bottles_purchased: 6, user_id: 999
|
12
|
+
)
|
13
|
+
assert_equal(999, event.data['user_id'])
|
14
|
+
assert_equal(999, event.user_id)
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_creation_accessors_on_reload
|
18
|
+
event = SubscriptionEvent.creation.new(
|
19
|
+
bottles_per_shipment: 1, bottles_purchased: 6, user_id: 999
|
20
|
+
)
|
21
|
+
event.save!
|
22
|
+
event_prime = SubscriptionEvent.find(event.id)
|
23
|
+
assert_equal(999, event_prime.user_id)
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_creation_reserved_attributes
|
27
|
+
event = SubscriptionEvent.creation.new(
|
28
|
+
subscription_uuid: 'asdf'
|
29
|
+
)
|
30
|
+
assert_equal('asdf', event.subscription_uuid)
|
31
|
+
assert_nil event.data['subscription_uuid']
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_creation_dont_accept_random_attribute
|
35
|
+
assert_raises(ActiveRecord::UnknownAttributeError) do
|
36
|
+
SubscriptionEvent.creation.new(foo: 'bar')
|
37
|
+
end
|
38
|
+
assert_raises(ActiveRecord::UnknownAttributeError) do
|
39
|
+
SubscriptionEvent.change_settings.new(user_id: 123)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_creation_validation_errors
|
44
|
+
event = SubscriptionEvent.creation.new
|
45
|
+
assert !event.valid?
|
46
|
+
assert event.errors[:bottles_per_shipment].include?("can't be blank")
|
47
|
+
assert event.errors[:bottles_per_shipment].include?('is not a number')
|
48
|
+
assert event.errors[:bottles_purchased].include?("can't be blank")
|
49
|
+
assert event.errors[:bottles_purchased].include?('is not a number')
|
50
|
+
assert event.errors[:user_id].include?("can't be blank")
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_creation_valid
|
54
|
+
event = SubscriptionEvent.creation.new(
|
55
|
+
bottles_per_shipment: 1, bottles_purchased: 6, user_id: 999
|
56
|
+
)
|
57
|
+
assert_equal(6, event.bottles_purchased)
|
58
|
+
assert event.valid?
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_creation_create
|
62
|
+
events_before = SubscriptionEvent.count
|
63
|
+
SubscriptionEvent.creation.create!(
|
64
|
+
bottles_per_shipment: 1, bottles_purchased: 6, user_id: 999
|
65
|
+
)
|
66
|
+
assert_equal(events_before + 1, SubscriptionEvent.count)
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_creation_settable_attributes
|
70
|
+
event = SubscriptionEvent.creation.new
|
71
|
+
event.bottles_per_shipment = 1
|
72
|
+
assert_equal(1, event.bottles_per_shipment)
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_change_settings_validation_errors
|
76
|
+
event = SubscriptionEvent.change_settings.new
|
77
|
+
assert !event.valid?
|
78
|
+
assert event.errors[:bottles_per_shipment].include?('is not a number')
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_change_settings_valid
|
82
|
+
event = SubscriptionEvent.change_settings.new(:bottles_per_shipment => 2)
|
83
|
+
assert event.valid?
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_new_without_scope
|
87
|
+
event = SubscriptionEvent.new(
|
88
|
+
event_type: 'creation', bottles_per_shipment: 1, bottles_purchased: 6,
|
89
|
+
user_id: 999
|
90
|
+
)
|
91
|
+
assert event.valid?
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_event_type_required
|
95
|
+
event = SubscriptionEvent.new
|
96
|
+
assert !event.valid?
|
97
|
+
assert event.errors[:event_type].include?("can't be blank")
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_event_type_inclusion
|
101
|
+
event = SubscriptionEvent.new(event_type: 'wrong')
|
102
|
+
assert !event.valid?
|
103
|
+
assert event.errors[:event_type].include?("is not a valid event type")
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_event_type_unsettable
|
107
|
+
event = SubscriptionEvent.creation.new
|
108
|
+
assert_raises(EventSourcedRecord::Event::EventTypeImmutableError) do
|
109
|
+
event.event_type = 'change_settings'
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class EventSourcedRecord::CalculatorGeneratorTest < Rails::Generators::TestCase
|
4
|
+
destination 'tmp/calculator_generator_test'
|
5
|
+
setup :prepare_destination
|
6
|
+
tests EventSourcedRecord::CalculatorGenerator
|
7
|
+
|
8
|
+
setup do
|
9
|
+
@generate_calls = Hash.new { |h,k| h[k] = [] }
|
10
|
+
EventSourcedRecord::CalculatorGenerator.any_instance.stubs(:generate).with { |name, arg_string|
|
11
|
+
@generate_calls[name] << arg_string
|
12
|
+
}
|
13
|
+
run_generator %w(subscription_calculator)
|
14
|
+
end
|
15
|
+
|
16
|
+
test "creates a calculator" do
|
17
|
+
assert_file("app/services/subscription_calculator.rb") do |contents|
|
18
|
+
assert_match(
|
19
|
+
/class SubscriptionCalculator < EventSourcedRecord::Calculator/,
|
20
|
+
contents
|
21
|
+
)
|
22
|
+
assert_match(/def advance_creation\(event\)/, contents)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class EventSourcedRecord::EventGeneratorTest < Rails::Generators::TestCase
|
4
|
+
destination 'tmp/event_generator_test'
|
5
|
+
setup :prepare_destination
|
6
|
+
tests EventSourcedRecord::EventGenerator
|
7
|
+
|
8
|
+
setup do
|
9
|
+
@generate_calls = Hash.new { |h,k| h[k] = [] }
|
10
|
+
EventSourcedRecord::EventGenerator.any_instance.stubs(:generate).with { |name, arg_string|
|
11
|
+
@generate_calls[name] << arg_string
|
12
|
+
}
|
13
|
+
run_generator %w(
|
14
|
+
subscription_event
|
15
|
+
subscription_uuid:string:index
|
16
|
+
event_type:string
|
17
|
+
data:text
|
18
|
+
created_at:datetime
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
test "creates a migration for the event class" do
|
23
|
+
assert @generate_calls['migration'].include?(
|
24
|
+
"create_subscription_events subscription_uuid:string:index event_type:string data:text created_at:datetime"
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
test "creates a model for the event class" do
|
29
|
+
assert_file("app/models/subscription_event.rb") do |contents|
|
30
|
+
assert_match(/class SubscriptionEvent < ActiveRecord::Base/, contents)
|
31
|
+
assert_match(/include EventSourcedRecord::Event/, contents)
|
32
|
+
assert_match(/event_type :creation do/, contents)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class EventSourcedRecord::EventSourcedRecordGeneratorTest < Rails::Generators::TestCase
|
4
|
+
destination 'tmp/event_sourced_record_generator_test'
|
5
|
+
setup :prepare_destination
|
6
|
+
tests EventSourcedRecord::EventSourcedRecordGenerator
|
7
|
+
|
8
|
+
setup do
|
9
|
+
@generate_calls = Hash.new { |h,k| h[k] = [] }
|
10
|
+
EventSourcedRecord::EventSourcedRecordGenerator.any_instance.stubs(:generate).with { |name, arg_string|
|
11
|
+
@generate_calls[name] << arg_string
|
12
|
+
}
|
13
|
+
run_generator %w(
|
14
|
+
ShampooSubscription
|
15
|
+
user_id:integer
|
16
|
+
bottles_per_shipment:integer
|
17
|
+
bottles_left:integer
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
test "calls the event generator" do
|
22
|
+
assert @generate_calls['event_sourced_record:event'].include?(
|
23
|
+
"shampoo_subscription_event shampoo_subscription_uuid:string:index event_type:string data:text created_at:datetime"
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
test "calls the projection generator" do
|
28
|
+
assert @generate_calls['event_sourced_record:projection'].include?(
|
29
|
+
"shampoo_subscription user_id:integer bottles_per_shipment:integer bottles_left:integer"
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
test "calls the calculator generator" do
|
34
|
+
assert @generate_calls['event_sourced_record:calculator'].include?(
|
35
|
+
"shampoo_subscription_calculator"
|
36
|
+
)
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class EventSourcedRecord::ObserverGeneratorTest < Rails::Generators::TestCase
|
4
|
+
Destination = 'tmp/observer_generator_test'
|
5
|
+
destination Destination
|
6
|
+
setup :prepare_destination
|
7
|
+
tests EventSourcedRecord::ObserverGenerator
|
8
|
+
|
9
|
+
setup do
|
10
|
+
config_path = File.join(Destination, 'config')
|
11
|
+
FileUtils.mkdir(config_path)
|
12
|
+
FileUtils.cp("test/generators/templates/application.rb", config_path)
|
13
|
+
run_generator %w(subscription_event_observer)
|
14
|
+
end
|
15
|
+
|
16
|
+
test "creates a file for the observer" do
|
17
|
+
assert_file("app/observers/subscription_event_observer.rb")
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class EventSourcedRecord::ProjectionGeneratorTest < Rails::Generators::TestCase
|
4
|
+
destination 'tmp/projection_generator_test'
|
5
|
+
setup :prepare_destination
|
6
|
+
tests EventSourcedRecord::ProjectionGenerator
|
7
|
+
|
8
|
+
setup do
|
9
|
+
@generate_calls = Hash.new { |h,k| h[k] = [] }
|
10
|
+
EventSourcedRecord::ProjectionGenerator.any_instance.stubs(:generate).with { |name, arg_string|
|
11
|
+
@generate_calls[name] << arg_string
|
12
|
+
}
|
13
|
+
run_generator %w(
|
14
|
+
subscription
|
15
|
+
user_id:integer
|
16
|
+
bottles_per_shipment:integer
|
17
|
+
bottles_left:integer
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
test "creates a migration for the projection class" do
|
22
|
+
assert(
|
23
|
+
@generate_calls['migration'].include?(
|
24
|
+
"create_subscriptions user_id:integer bottles_per_shipment:integer bottles_left:integer uuid:string:uniq"
|
25
|
+
),
|
26
|
+
@generate_calls.inspect
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
test "creates a model for the projection class" do
|
31
|
+
assert_file("app/models/subscription.rb") do |contents|
|
32
|
+
assert_match(/class Subscription < ActiveRecord::Base/, contents)
|
33
|
+
assert_match(/validates :uuid, uniqueness: true/, contents)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require File.expand_path('../boot', __FILE__)
|
2
|
+
|
3
|
+
require 'rails/all'
|
4
|
+
|
5
|
+
# Require the gems listed in Gemfile, including any gems
|
6
|
+
# you've limited to :test, :development, or :production.
|
7
|
+
Bundler.require(*Rails.groups)
|
8
|
+
|
9
|
+
module ShampooExpress
|
10
|
+
class Application < Rails::Application
|
11
|
+
end
|
12
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'rails'
|
2
|
+
require 'rails/test_help'
|
3
|
+
require 'rails/generators/test_case'
|
4
|
+
require 'pry'
|
5
|
+
require 'mocha/test_unit'
|
6
|
+
$: << 'lib'
|
7
|
+
require 'event_sourced_record'
|
8
|
+
require 'generators/event_sourced_record/event_sourced_record_generator'
|
9
|
+
require 'generators/event_sourced_record/calculator_generator'
|
10
|
+
require 'generators/event_sourced_record/event_generator'
|
11
|
+
require 'generators/event_sourced_record/observer_generator'
|
12
|
+
require 'generators/event_sourced_record/projection_generator'
|
13
|
+
require 'active_record'
|
14
|
+
|
15
|
+
ActiveRecord::Base.establish_connection(
|
16
|
+
:adapter => 'sqlite3', :database => 'tmp/test.sqlite3'
|
17
|
+
)
|
18
|
+
|
19
|
+
silence_stream(STDOUT) do
|
20
|
+
ActiveRecord::Schema.define do
|
21
|
+
create_table "shipments", force: true do |t|
|
22
|
+
t.integer "subscription_id"
|
23
|
+
t.integer "num_bottles"
|
24
|
+
t.datetime "created_at"
|
25
|
+
t.datetime "updated_at"
|
26
|
+
end
|
27
|
+
|
28
|
+
create_table 'subscription_events', :force => true do |t|
|
29
|
+
t.string "subscription_uuid"
|
30
|
+
t.string "event_type"
|
31
|
+
t.text "data"
|
32
|
+
t.datetime "created_at"
|
33
|
+
end
|
34
|
+
|
35
|
+
create_table "subscriptions", force: true do |t|
|
36
|
+
t.integer "user_id"
|
37
|
+
t.integer "bottles_per_shipment"
|
38
|
+
t.integer "bottles_left"
|
39
|
+
t.string "uuid"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class Shipment < ActiveRecord::Base
|
45
|
+
end
|
46
|
+
|
47
|
+
class SubscriptionEvent < ActiveRecord::Base
|
48
|
+
include EventSourcedRecord::Event
|
49
|
+
|
50
|
+
event_type :creation do
|
51
|
+
attributes :bottles_per_shipment, :bottles_purchased, :user_id
|
52
|
+
|
53
|
+
validates :bottles_per_shipment, presence: true, numericality: true
|
54
|
+
validates :bottles_purchased, presence: true, numericality: true
|
55
|
+
validates :user_id, presence: true
|
56
|
+
end
|
57
|
+
|
58
|
+
event_type :change_settings do
|
59
|
+
attributes :bottles_per_shipment
|
60
|
+
|
61
|
+
validates :bottles_per_shipment, numericality: true
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class Subscription < ActiveRecord::Base
|
66
|
+
has_many :subscription_events
|
67
|
+
|
68
|
+
validates :uuid, uniqueness: true
|
69
|
+
end
|
70
|
+
|
71
|
+
class SubscriptionCalculator < EventSourcedRecord::Calculator
|
72
|
+
events :subscription_events, :shipments
|
73
|
+
|
74
|
+
def advance_creation(event)
|
75
|
+
@subscription.bottles_per_shipment = event.bottles_per_shipment
|
76
|
+
@subscription.bottles_left = event.bottles_purchased
|
77
|
+
end
|
78
|
+
|
79
|
+
def advance_shipment(shipment)
|
80
|
+
@subscription.bottles_left -= shipment.num_bottles
|
81
|
+
end
|
82
|
+
end
|