improvement: Add float type (#204)

Also update `Ash.Type` documentation to use the float module as an
example of a custom type.
This commit is contained in:
Jason Axelson 2021-03-20 18:09:27 -10:00 committed by GitHub
parent 6b8fba8ab1
commit 6c31956b56
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 71 additions and 10 deletions

27
lib/ash/type/float.ex Normal file
View file

@ -0,0 +1,27 @@
defmodule Ash.Type.Float do
@moduledoc """
Represents a float (floating point number)
A builtin type that be referenced via `:float`
"""
use Ash.Type
@impl true
def storage_type, do: :float
@impl true
def cast_input(value, _) do
Ecto.Type.cast(:float, value)
end
@impl true
def cast_stored(value, _) do
Ecto.Type.load(:float, value)
end
@impl true
def dump_to_native(value, _) do
Ecto.Type.dump(:float, value)
end
end

View file

@ -21,6 +21,7 @@ defmodule Ash.Type do
atom: Ash.Type.Atom, atom: Ash.Type.Atom,
string: Ash.Type.String, string: Ash.Type.String,
integer: Ash.Type.Integer, integer: Ash.Type.Integer,
float: Ash.Type.Float,
interval: Ash.Type.Interval, interval: Ash.Type.Interval,
function: Ash.Type.Function, function: Ash.Type.Function,
boolean: Ash.Type.Boolean, boolean: Ash.Type.Boolean,
@ -45,18 +46,11 @@ defmodule Ash.Type do
"Constraints for the elements of the list. See the contained type's docs for more." "Constraints for the elements of the list. See the contained type's docs for more."
) )
@moduledoc """ @moduledoc """
This behaviour is a superset of the Ecto.Type behavior, that also contains Describes how to convert data to `Ecto.Type` and eventually into the database.
This behaviour is a superset of the `Ecto.Type` behavior, that also contains
API level information, like what kinds of filters are allowed. API level information, like what kinds of filters are allowed.
Much better to `use Ash.Type` than to say `@behaviour Ash.Type` and define
everything yourself.
Overriding the `{:array, type}` behavior. By definining the `*_array` versions
of `cast_input`, `cast_stored`, `dump_to_native` and `apply_constraints`, you can
override how your type behaves as a collection. This is how the features of embedded
resources are implemented. No need to implement them unless you wish to override the
default behavior.
## Built in types ## Built in types
#{ #{
@ -71,6 +65,46 @@ defmodule Ash.Type do
`{:array, Type}`. The constraints available are: `{:array, Type}`. The constraints available are:
#{Ash.OptionsHelpers.docs(@doc_array_constraints)} #{Ash.OptionsHelpers.docs(@doc_array_constraints)}
## Defining Custom Types
Generally you add `use Ash.Type` to your module (it is possible to add `@behaviour
Ash.Type` and define everything yourself, but this is more work and error-prone).
Overriding the `{:array, type}` behavior. By definining the `*_array` versions
of `cast_input`, `cast_stored`, `dump_to_native` and `apply_constraints`, you can
override how your type behaves as a collection. This is how the features of embedded
resources are implemented. No need to implement them unless you wish to override the
default behavior.
Simple example of a float custom type
```Elixir
defmodule GenTracker.AshFloat do
use Ash.Type
@impl Ash.Type
def storage_type, do: :float
@impl Ash.Type
def cast_input(value, _) do
Ecto.Type.cast(:float, value)
end
@impl Ash.Type
def cast_stored(value, _) do
Ecto.Type.load(:float, value)
end
@impl Ash.Type
def dump_to_native(value, _) do
Ecto.Type.dump(:float, value)
end
end
```
All the Ash built-in types are implemented with `use Ash.Type` so they are good
examples to look at to create your own `Ash.Type`
""" """
@type constraints :: Keyword.t() @type constraints :: Keyword.t()
@callback storage_type() :: Ecto.Type.t() @callback storage_type() :: Ecto.Type.t()