-
-
Notifications
You must be signed in to change notification settings - Fork 181
/
calculation.ex
147 lines (137 loc) · 3.82 KB
/
calculation.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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
defmodule Ash.Resource.Calculation do
@moduledoc "Represents a named calculation on a resource"
defstruct [
:name,
:type,
:calculation,
:arguments,
:description,
:constraints,
:private?,
:allow_nil?,
:select,
:load,
:allow_async?,
filterable?: true
]
@schema [
name: [
type: :atom,
required: true,
doc: "The field name to use for the calculation value"
],
type: [
type: :any,
doc: "The type of the calculation. See `Ash.Type` for more.",
required: true
],
constraints: [
type: :keyword_list,
default: [],
doc: "Constraints to provide to the type. See `Ash.Type` for more."
],
allow_async?: [
type: :boolean,
default: false,
doc: """
If set to `true`, then the calculation may be run after the main query.
"""
],
calculation: [
type:
{:or,
[
{:spark_function_behaviour, Ash.Calculation, {Ash.Calculation.Function, 2}},
{:custom, __MODULE__, :expr_calc, []}
]},
required: true,
doc: """
The module or `{module, opts}` to use for the calculation
Also accepts a function that takes the list of records and the context.
"""
],
description: [
type: :string,
doc: "An optional description for the calculation"
],
private?: [
type: :boolean,
default: false,
doc: """
Whether or not the calculation will appear in any interfaces created off of this resource, e.g AshJsonApi and AshGraphql
See the [security guide](/documentation/topics/security.md) for more.
"""
],
select: [
type: {:list, :atom},
default: [],
doc: "A list of fields to ensure selected if the calculation is used."
],
load: [
type: :any,
default: [],
doc: "A load statement to be applied if the calculation is used."
],
allow_nil?: [
type: :boolean,
default: true,
doc: "Whether or not the calculation can return nil."
],
filterable?: [
type: {:or, [:boolean, {:in, [:simple_equality]}]},
default: true,
doc: "Whether or not the calculation should be usable in filters."
]
]
@type t :: %__MODULE__{
name: atom(),
calculation: {:ok, {atom(), any()}} | {:error, String.t()},
arguments: list(any()),
description: String.t() | nil,
private?: boolean,
allow_nil?: boolean
}
@type ref :: {module(), Keyword.t()} | module()
defmodule Argument do
@moduledoc "An argument to a calculation"
defstruct [:name, :type, :default, :allow_nil?, :constraints, :allow_expr?]
@schema [
name: [
type: :atom,
required: true,
doc: "The name of the argument"
],
type: [
type: Ash.OptionsHelpers.ash_type(),
required: true,
doc: "The type of the argument. See `Ash.Type` for more."
],
default: [
type: {:or, [{:mfa_or_fun, 0}, :literal]},
required: false,
doc: "A default value to use for the argument if not provided"
],
allow_nil?: [
type: :boolean,
default: true,
doc: "Whether or not the argument value may be nil (or may be not provided)"
],
allow_expr?: [
type: :boolean,
default: false,
doc: "Allow passing expressions as argument values. Expressions cannot be type validated."
],
constraints: [
type: :keyword_list,
default: [],
doc:
"Constraints to provide to the type when casting the value. See the type's documentation and `Ash.Type` for more."
]
]
def schema, do: @schema
end
def schema, do: @schema
def expr_calc(expr) do
{:ok, {Ash.Resource.Calculation.Expression, expr: expr}}
end
end