-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #8 from Omerlo-Technologies/feat/excluded-dates
Add excluded dates
- Loading branch information
Showing
8 changed files
with
263 additions
and
15 deletions.
There are no files selected for viewing
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
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
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
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,58 @@ | ||
defmodule ExCycle.Validations.DateExclusion do | ||
@moduledoc """ | ||
DateExclusion defines a list of date or datetime to exclude from generated datetimes. | ||
## Examples | ||
iex> %DateExclusion{dates: [~D[2024-01-01], ~N[2024-01-02 10:00:00]]} | ||
Will exclude the date 2024-01-01 and the datetime 2024-01-02 10:00:00. | ||
""" | ||
|
||
@behaviour ExCycle.Validations | ||
|
||
alias __MODULE__ | ||
|
||
@enforce_keys [:dates] | ||
defstruct dates: [] | ||
|
||
@type t :: %DateExclusion{dates: list(Date.t() | NaiveDateTime.t())} | ||
|
||
@spec new(list(Date.t() | NaiveDateTime.t())) :: t() | ||
def new(dates) do | ||
%DateExclusion{ | ||
dates: Enum.map(dates, &parse_datetime/1) | ||
} | ||
end | ||
|
||
defp parse_datetime(%Date{} = date), do: date | ||
defp parse_datetime(%NaiveDateTime{} = datetime), do: datetime | ||
|
||
@impl ExCycle.Validations | ||
@spec valid?(ExCycle.State.t(), t()) :: boolean() | ||
def valid?(datetime_state, %DateExclusion{dates: excluded_dates}) do | ||
!Enum.any?(excluded_dates, &datetimes_equal?(&1, datetime_state.next)) | ||
end | ||
|
||
@impl ExCycle.Validations | ||
@spec next(ExCycle.State.t(), t()) :: ExCycle.State.t() | ||
def next(datetime_state, %DateExclusion{dates: excluded_dates}) do | ||
excluded_date = Enum.find(excluded_dates, &datetimes_equal?(&1, datetime_state.next)) | ||
|
||
shift = | ||
case excluded_date do | ||
%Date{} -> &(&1 |> Date.add(1) |> NaiveDateTime.new!(~T[00:00:00])) | ||
%NaiveDateTime{} -> &NaiveDateTime.add(&1, 1, :second) | ||
end | ||
|
||
ExCycle.State.update_next(datetime_state, shift) | ||
end | ||
|
||
defp datetimes_equal?(datetime, next_datetime) do | ||
case datetime do | ||
%Date{} -> Date.compare(next_datetime, datetime) == :eq | ||
%NaiveDateTime{} -> NaiveDateTime.compare(next_datetime, datetime) == :eq | ||
end | ||
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
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
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,39 @@ | ||
defmodule ExCycle.Validations.DateExclusionTest do | ||
use ExUnit.Case, async: true | ||
alias ExCycle.Validations.DateExclusion | ||
|
||
setup do | ||
%{state: ExCycle.State.new(~N[2024-04-04 10:00:00])} | ||
end | ||
|
||
describe "valid?/2" do | ||
test "for valid state", %{state: state} do | ||
validation = DateExclusion.new([]) | ||
assert DateExclusion.valid?(state, validation) | ||
end | ||
|
||
test "for excluded date", %{state: state} do | ||
validation = DateExclusion.new([~D[2024-04-04]]) | ||
refute DateExclusion.valid?(state, validation) | ||
end | ||
|
||
test "for excluded datetime", %{state: state} do | ||
validation = DateExclusion.new([~N[2024-04-04 10:00:00]]) | ||
refute DateExclusion.valid?(state, validation) | ||
end | ||
end | ||
|
||
describe "next/2" do | ||
test "for date", %{state: state} do | ||
validation = DateExclusion.new([~D[2024-04-04]]) | ||
new_state = DateExclusion.next(state, validation) | ||
assert new_state.next == ~N[2024-04-05 00:00:00] | ||
end | ||
|
||
test "for datetime", %{state: state} do | ||
validation = DateExclusion.new([~N[2024-04-04 10:00:00]]) | ||
new_state = DateExclusion.next(state, validation) | ||
assert new_state.next == ~N[2024-04-04 10:00:01] | ||
end | ||
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