/
change.ex
102 lines (77 loc) · 3.04 KB
/
change.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
defmodule Versioning.Change do
@moduledoc """
Defines a versioning change.
A versioning change is used to make small changes to data of a certain type.
They are used within a `Versioning.Schema`. Changes should attempt to be as
focused as possible to ensure complexity is kept to a minimum.
## Example
defmodule MyApp.Cheanges.PostStatusChange do
use Versioning.Change
@desc "The 'active' attribute has been changed in favour of the 'status' attribute"
@impl Versioning.Change
def down(versioning, _opts) do
case Versioning.pop_data(versioning, "status") do
{:active, versioning} -> Versioning.put_data(versioning, "active", true)
{_, versioning} -> Versioning.put_data(versioning, "active", false)
end
end
@impl Versioning.Change
def up(versioning, _opts) do
case Versioning.pop_data(versioning, "active") do
{true, versioning} -> Versioning.put_data(versioning, "status", "active")
{false, versioning} -> Versioning.put_data(versioning, "status", "hidden")
{_, versioning} -> versioning
end
end
end
The above change module represents us modifying our `Post` data to support a
new attribute - `status` - which replaces the previous `active` attribute.
When changing data "down", we must remove the `status` attribte, and replace it
with a value that represents the previous `active` attribute. When changing
data "up", we must remove the `active` attribute and replace it with a value that
represents the new `status` attribute.
## Descriptions
Change modules can optionally include a `@desc` module attribute. This will be
used to describe the changes made in the change module when constructing changelogs.
Please see the `Versioning.Changelog` documentation for more information on changelogs.
"""
@doc """
Accepts a `Versioning` struct, and applies changes upward.
## Examples
MyApp.Change.up(versioning)
"""
@callback up(versioning :: Versioning.t(), opts :: any()) :: Versioning.t()
@doc """
Accepts a `Versioning` struct and applies changes downward.
## Examples
MyApp.Change.down(versioning)
"""
@callback down(versioning :: Versioning.t(), opts :: any()) :: Versioning.t()
defmacro __using__(_opts) do
quote do
@behaviour Versioning.Change
@desc "No Description"
@before_compile Versioning.Change
end
end
defmacro __before_compile__(_env) do
quote do
def __change__(:desc) do
@desc
end
end
end
@doc false
@spec up(Versioning.t(), atom(), any()) :: Versioning.t()
def up(versioning, change, opts) do
versioning |> change.up(opts) |> put_change(change)
end
@doc false
@spec down(Versioning.t(), atom(), any()) :: Versioning.t()
def down(versioning, change, opts) do
versioning |> change.down(opts) |> put_change(change)
end
defp put_change(versioning, change) do
%{versioning | changed: true, changes: [change | versioning.changes]}
end
end