-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f59b82a
commit 9041591
Showing
11 changed files
with
374 additions
and
1 deletion.
There are no files selected for viewing
28 changes: 28 additions & 0 deletions
28
heroesofddd_rails_application/lib/heroes/calendar/configuration.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
require "building_blocks/infrastructure/event_sourcing_application_service" | ||
require_relative "write/start_day/command_start_day" | ||
require_relative "write/finish_day/command_finish_day" | ||
require_relative "write/calendar" | ||
|
||
module Heroes | ||
module Calendar | ||
class Configuration | ||
def call(event_store, command_bus, event_registry) | ||
application_service = ::BuildingBlocks::Infrastructure::EventSourcingApplicationService.new( | ||
Calendar, | ||
event_store, | ||
event_registry | ||
) { |_, metadata| "Game::$#{metadata[:game_id]}::Calendar" } | ||
|
||
command_bus.register( | ||
StartDay, | ||
StartDayCommandHandler.new(application_service, event_registry) | ||
) | ||
|
||
command_bus.register( | ||
FinishDay, | ||
FinishDayCommandHandler.new(application_service, event_registry) | ||
) | ||
end | ||
end | ||
end | ||
end |
85 changes: 85 additions & 0 deletions
85
heroesofddd_rails_application/lib/heroes/calendar/write/calendar.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
module Heroes | ||
module Calendar | ||
module Calendar | ||
State = Data.define(:current_day, :current_week, :current_month) | ||
|
||
class << self | ||
def decide(command, state) | ||
case command | ||
when StartDay | ||
handle_start_day(command, state) | ||
when FinishDay | ||
handle_finish_day(command, state) | ||
else | ||
raise "Unknown command" | ||
end | ||
end | ||
|
||
def evolve(state, event) | ||
case event | ||
when DayStarted | ||
State.new( | ||
current_day: event.day, | ||
current_week: event.week, | ||
current_month: event.month | ||
) | ||
when DayFinished | ||
state | ||
else | ||
raise "Unknown event" | ||
end | ||
end | ||
|
||
def initial_state | ||
State.new(current_day: 0, current_week: 0, current_month: 0) | ||
end | ||
|
||
private | ||
|
||
def handle_start_day(command, state) | ||
validate_start_day(command, state) | ||
[ DayStarted.new(month: command.month, week: command.week, day: command.day) ] | ||
end | ||
|
||
def handle_finish_day(command, state) | ||
validate_finish_day(command, state) | ||
[ DayFinished.new(month: command.month, week: command.week, day: command.day) ] | ||
end | ||
|
||
def validate_start_day(command, state) | ||
raise CannotSkipDays unless next_day?(command, state) | ||
end | ||
|
||
def validate_finish_day(command, state) | ||
raise CanOnlyFinishCurrentDay unless current_day?(command, state) | ||
end | ||
|
||
def next_day?(command, state) | ||
return true if state.current_day == 0 # First day | ||
|
||
next_day = state.current_day + 1 | ||
next_week = state.current_week | ||
next_month = state.current_month | ||
|
||
if next_day > 7 | ||
next_day = 1 | ||
next_week += 1 | ||
end | ||
|
||
if next_week > 4 | ||
next_week = 1 | ||
next_month += 1 | ||
end | ||
|
||
command.day == next_day && command.week == next_week && command.month == next_month | ||
end | ||
|
||
def current_day?(command, state) | ||
command.day == state.current_day && | ||
command.week == state.current_week && | ||
command.month == state.current_month | ||
end | ||
end | ||
end | ||
end | ||
end |
49 changes: 49 additions & 0 deletions
49
heroesofddd_rails_application/lib/heroes/calendar/write/finish_day/command_finish_day.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
require_relative "../calendar" | ||
require_relative "./event_day_finished" | ||
|
||
module Heroes | ||
module Calendar | ||
FinishDay = Data.define(:month, :week, :day) | ||
|
||
class FinishDayCommandHandler | ||
def initialize(application_service, event_registry) | ||
@application_service = application_service | ||
event_registry.map_event_type( | ||
Heroes::Calendar::DayFinished, | ||
EventStore::Heroes::Calendar::DayFinished, | ||
EventStore::Heroes::Calendar::DayFinished.method(:from_domain), | ||
EventStore::Heroes::Calendar::DayFinished.method(:to_domain) | ||
) | ||
end | ||
|
||
def call(command) | ||
@application_service.call(command) | ||
end | ||
end | ||
end | ||
end | ||
|
||
module EventStore | ||
module Heroes | ||
module Calendar | ||
DayFinished = Class.new(RubyEventStore::Event) do | ||
def self.from_domain(domain_event) | ||
new(data: { | ||
month: domain_event.month, | ||
week: domain_event.week, | ||
day: domain_event.day | ||
}) | ||
end | ||
|
||
def self.to_domain(store_event) | ||
data = store_event.data.deep_symbolize_keys | ||
::Heroes::Calendar::DayFinished.new( | ||
month: data[:month], | ||
week: data[:week], | ||
day: data[:day] | ||
) | ||
end | ||
end | ||
end | ||
end | ||
end |
5 changes: 5 additions & 0 deletions
5
heroesofddd_rails_application/lib/heroes/calendar/write/finish_day/event_day_finished.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
module Heroes | ||
module Calendar | ||
DayFinished = Data.define(:month, :week, :day) | ||
end | ||
end |
5 changes: 5 additions & 0 deletions
5
..._application/lib/heroes/calendar/write/finish_day/rule_can_only_finish_the_current_day.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
module Heroes | ||
module Calendar | ||
CanOnlyFinishCurrentDay = Class.new(StandardError) | ||
end | ||
end |
49 changes: 49 additions & 0 deletions
49
heroesofddd_rails_application/lib/heroes/calendar/write/start_day/command_start_day.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
require_relative "../calendar" | ||
require_relative "./event_day_started" | ||
|
||
module Heroes | ||
module Calendar | ||
StartDay = Data.define(:month, :week, :day) | ||
|
||
class StartDayCommandHandler | ||
def initialize(application_service, event_registry) | ||
@application_service = application_service | ||
event_registry.map_event_type( | ||
Heroes::Calendar::DayStarted, | ||
EventStore::Heroes::Calendar::DayStarted, | ||
EventStore::Heroes::Calendar::DayStarted.method(:from_domain), | ||
EventStore::Heroes::Calendar::DayStarted.method(:to_domain) | ||
) | ||
end | ||
|
||
def call(command) | ||
@application_service.call(command) | ||
end | ||
end | ||
end | ||
end | ||
|
||
module EventStore | ||
module Heroes | ||
module Calendar | ||
DayStarted = Class.new(RubyEventStore::Event) do | ||
def self.from_domain(domain_event) | ||
new(data: { | ||
month: domain_event.month, | ||
week: domain_event.week, | ||
day: domain_event.day | ||
}) | ||
end | ||
|
||
def self.to_domain(store_event) | ||
data = store_event.data.deep_symbolize_keys | ||
::Heroes::Calendar::DayStarted.new( | ||
month: data[:month], | ||
week: data[:week], | ||
day: data[:day] | ||
) | ||
end | ||
end | ||
end | ||
end | ||
end |
5 changes: 5 additions & 0 deletions
5
heroesofddd_rails_application/lib/heroes/calendar/write/start_day/event_day_started.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
module Heroes | ||
module Calendar | ||
DayStarted = Data.define(:month, :week, :day) | ||
end | ||
end |
5 changes: 5 additions & 0 deletions
5
heroesofddd_rails_application/lib/heroes/calendar/write/start_day/rule_cannot_skip_days.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
module Heroes | ||
module Calendar | ||
CannotSkipDays = Class.new(StandardError) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
46 changes: 46 additions & 0 deletions
46
heroesofddd_rails_application/test/lib/heroes/calendar/write/finish_day_application_test.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
require "real_event_store_integration_test_case" | ||
require "heroes/calendar/write/start_day/command_start_day" | ||
require "heroes/calendar/write/finish_day/rule_can_only_finish_the_current_day" | ||
require "heroes/calendar/write/finish_day/command_finish_day" | ||
require "building_blocks/application/app_context" | ||
|
||
module Heroes | ||
module Calendar | ||
class FinishDayApplicationTest < RealEventStoreIntegrationTestCase | ||
def setup | ||
super | ||
@game_id = SecureRandom.uuid | ||
@stream_name = "Game::$#{@game_id}::Calendar" | ||
@app_context = ::BuildingBlocks::Application::AppContext.for_game(@game_id) | ||
end | ||
|
||
def test_given_day_started_when_finish_current_day_then_day_finished | ||
# given | ||
given_domain_event(@stream_name, DayStarted.new(month: 1, week: 1, day: 1)) | ||
|
||
# when | ||
finish_day = FinishDay.new(month: 1, week: 1, day: 1) | ||
execute_command(finish_day) | ||
|
||
# then | ||
expected_event = DayFinished.new(month: 1, week: 1, day: 1) | ||
then_domain_event(@stream_name, expected_event) | ||
end | ||
|
||
def test_given_day_started_when_finish_non_current_day_then_fails | ||
# given | ||
given_domain_event(@stream_name, DayStarted.new(month: 1, week: 1, day: 1)) | ||
|
||
# when/then | ||
finish_day = FinishDay.new(month: 1, week: 1, day: 2) | ||
assert_raises(CanOnlyFinishCurrentDay) do | ||
execute_command(finish_day) | ||
end | ||
end | ||
|
||
def default_app_context | ||
@app_context | ||
end | ||
end | ||
end | ||
end |
94 changes: 94 additions & 0 deletions
94
heroesofddd_rails_application/test/lib/heroes/calendar/write/start_day_application_test.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
require "real_event_store_integration_test_case" | ||
require "heroes/calendar/write/start_day/command_start_day" | ||
require "heroes/calendar/write/start_day/rule_cannot_skip_days" | ||
require "heroes/calendar/write/start_day/event_day_started" | ||
require "heroes/calendar/write/finish_day/command_finish_day" | ||
require "heroes/calendar/write/finish_day/event_day_finished" | ||
require "building_blocks/application/app_context" | ||
|
||
module Heroes | ||
module Calendar | ||
class StartDayApplicationTest < RealEventStoreIntegrationTestCase | ||
def setup | ||
super | ||
@game_id = SecureRandom.uuid | ||
@stream_name = "Game::$#{@game_id}::Calendar" | ||
@app_context = ::BuildingBlocks::Application::AppContext.for_game(@game_id) | ||
end | ||
|
||
def test_given_no_previous_day_when_start_day_then_day_started | ||
# when | ||
start_day = StartDay.new(month: 1, week: 1, day: 1) | ||
execute_command(start_day) | ||
|
||
# then | ||
expected_event = DayStarted.new(month: 1, week: 1, day: 1) | ||
then_domain_event(@stream_name, expected_event) | ||
end | ||
|
||
def test_given_previous_day_finished_when_start_next_day_then_next_day_started | ||
# given | ||
given_domain_event(@stream_name, DayStarted.new(month: 1, week: 1, day: 1)) | ||
given_domain_event(@stream_name, DayFinished.new(month: 1, week: 1, day: 1)) | ||
|
||
# when | ||
start_day = StartDay.new(month: 1, week: 1, day: 2) | ||
execute_command(start_day) | ||
|
||
# then | ||
expected_event = DayStarted.new(month: 1, week: 1, day: 2) | ||
then_domain_event(@stream_name, expected_event) | ||
end | ||
|
||
def test_given_previous_day_finished_when_start_day_skipping_one_then_fails | ||
# given | ||
given_domain_event(@stream_name, DayStarted.new(month: 1, week: 1, day: 1)) | ||
given_domain_event(@stream_name, DayFinished.new(month: 1, week: 1, day: 1)) | ||
|
||
# when/then | ||
start_day = StartDay.new(month: 1, week: 1, day: 3) | ||
assert_raises(CannotSkipDays) do | ||
execute_command(start_day) | ||
end | ||
end | ||
|
||
def test_given_last_day_of_week_finished_when_start_first_day_of_next_week_then_new_week_started | ||
# given | ||
(1..7).each do |day| | ||
given_domain_event(@stream_name, DayStarted.new(month: 1, week: 1, day: day)) | ||
given_domain_event(@stream_name, DayFinished.new(month: 1, week: 1, day: day)) | ||
end | ||
|
||
# when | ||
start_day = StartDay.new(month: 1, week: 2, day: 1) | ||
execute_command(start_day) | ||
|
||
# then | ||
expected_event = DayStarted.new(month: 1, week: 2, day: 1) | ||
then_domain_event(@stream_name, expected_event) | ||
end | ||
|
||
def test_given_last_day_of_month_finished_when_start_first_day_of_next_month_then_new_month_started | ||
# given | ||
(1..4).each do |week| | ||
(1..7).each do |day| | ||
given_domain_event(@stream_name, DayStarted.new(month: 1, week: week, day: day)) | ||
given_domain_event(@stream_name, DayFinished.new(month: 1, week: week, day: day)) | ||
end | ||
end | ||
|
||
# when | ||
start_day = StartDay.new(month: 2, week: 1, day: 1) | ||
execute_command(start_day) | ||
|
||
# then | ||
expected_event = DayStarted.new(month: 2, week: 1, day: 1) | ||
then_domain_event(@stream_name, expected_event) | ||
end | ||
|
||
def default_app_context | ||
@app_context | ||
end | ||
end | ||
end | ||
end |