You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The signs the value may have, compared against zero by `Ash.Type.Duration.compare/2`. Any combination is permitted: `:positive` or `[:positive]` requires a positive duration, `[:positive, :zero]` a non-negative one, and `[:positive, :negative]` a non-zero one. Omit the constraint to allow any sign. This is the sign of the duration as a whole, not of each unit — `%Duration{day: 1, hour: -5}` is positive, being nineteen hours. Only where the year/month and week/day sides carry opposite signs does the comparison depend on `compare/2`'s 30-day month.
The units the value may be expressed in. A duration is always re-expressed in the largest of these units that will hold it, on the way in and on the way out, so `[:week, :hour]` turns `1 week 1 day 5 hours` into `1 week 29 hours`. A value that no combination of the permitted units expresses exactly is rejected — including anything that would have to cross the year/month to week/day boundary, which no conversion can. This applies on the way out as well as in: a stored duration the permitted units cannot express is refused rather than quietly rewritten. Either an explicit list of units, or a shorthand for one side of that boundary: `:year_month` (`[:year, :month]`) or `:day_time` (`[:week, :day, :hour, :minute, :second, :microsecond]`). Confining an attribute to a single side keeps its values comparable (see `Ash.Type.Duration.compare/2`). With no constraint every unit is permitted, so the same normalization applies and nothing is ever lost.
23
+
The units the value may be expressed in. A duration is always re-expressed in the largest of these units that will hold it, on the way in and on the way out, so `[:week, :hour]` turns `1 week 1 day 5 hours` into `1 week 29 hours`. A value that no combination of the permitted units expresses exactly is rejected — including anything that would have to cross the year/month to week/day boundary, which no conversion can. This applies on the way out as well as in: a stored duration the permitted units cannot express is refused rather than quietly rewritten. Either a single unit, an explicit list of them, or a shorthand for one side of that boundary: `:year_month` (`[:year, :month]`) or `:day_time` (`[:week, :day, :hour, :minute, :second, :microsecond]`). Confining an attribute to a single side keeps its values comparable (see `Ash.Type.Duration.compare/2`). With no constraint every unit is permitted, so the same normalization applies and nothing is ever lost.
15
24
"""
16
25
]
17
26
]
@@ -79,7 +88,7 @@ defmodule Ash.Type.Duration do
79
88
80
89
casedisallowed_units(normalized,allowed)do
81
90
[]->
82
-
{:ok,normalized}
91
+
check_sign(normalized,constraints[:signs])
83
92
84
93
disallowed->
85
94
{:error,
@@ -93,12 +102,43 @@ defmodule Ash.Type.Duration do
93
102
end
94
103
end
95
104
105
+
# A magnitude constraint, where `units` is a representation one. Normalizing preserves
106
+
# magnitude, so the two are independent.
107
+
defpcheck_sign(value,nil),do: {:ok,value}
108
+
109
+
defpcheck_sign(value,permitted)do
110
+
# `wrap_list` normalizes at init, but constraints also arrive here directly.
111
+
permitted=List.wrap(permitted)
112
+
113
+
ifsign(value)inpermitteddo
114
+
{:ok,value}
115
+
else
116
+
{:error,
117
+
[
118
+
[
119
+
message: "must be %{signs}",
120
+
signs: Enum.map_join(permitted," or ",&to_string/1),
0 commit comments