Is there any global configuration I change use to change both the default Ash.UUID.generate/0 function and gen_random_uuid() functions for uuid fields?
For example, I want to use uuid_v7 by default.
I know I can at least change the default Ash.UUID.generate/0 by using the default option in each attribute, but I believe in some cases that is not sufficient (ex. with an ash_authenticationuser_resource)
Ah, that’s true. I added a separated field for the id and it worked just fine.
That actually brings me to another question.
Is it possible to configure an Ash.Type to use some specific fragment for when generating migrations?
For example, I have my own Ash.Type for UUIDV7. I want to make it that when i add this attribute to some resource, it will automatically set the default postgres value as uuid_generate_v7() the same way that adding the default uuid primary key field for Ash adds the gen_random_uuid().
Of course, I can add that using the migration_defaults function, but that means that I need to do that for basically every resource in my system (since they all use my UUIDV7 type), it would be great if I could make that be added automatically.
I saw that there is a AshPostgres.Type that adds a callback for a function called value_to_postgres_default, but that function doesn’t seem to be used to generate that default.
Maybe we could add a new callback for AshPostgres.Type called @callback migration_default/0 where the user defines what is the default migration default value for the type that implements it?
Ah, so TBH I don’t think you actually want all usages of that type get a default value. Otherwise belongs_to :something, SomethingElse, type: UUIDV7 would also get a default value, which would fail to insert if that relationship is optional.
What I’d suggest is adding this to your app:
defmodule MyApp.Resource do
def macro __using__(opts) do
quote do
use Ash.Resource, unquote(opts)
import MyApp.Resource
end
end
def macro uuid_v7_primary_key(name, opts) do
quote do
attribute unquote(name), UUIDV7, unquote(Keyword.put(opts, default: &UUIDV7.generate/0))
end
end
end
Then you can use MyApp.Resource instead of use Ash.Resource, and have uuid_v7_primary_key available.
With all of that said, the next release of Ash will have uuidv7 built in to core, so maybe you just want to use that?
Yep, that is actually what I used. Here is my implementation:
defmodule UUIDV7.Macros do
@moduledoc false
defmacro uuid_v7_primary_key(name, opts \\ []) do
default =
quote do
fn -> UUIDV7.Type.generator([]) end
end
field_opts =
opts
|> Keyword.put_new(:primary_key?, true)
|> Keyword.put_new(:allow_nil?, false)
|> Keyword.put_new(:default, default)
|> Keyword.put_new(:writable?, false)
quote do
attribute unquote(name), UUIDV7.Type, unquote(field_opts)
end
end
defmacro uuid_v7_attribute(name, opts \\ []) do
default =
quote do
fn -> UUIDV7.Type.generator([]) end
end
field_opts =
opts
|> Keyword.put_new(:primary_key?, false)
|> Keyword.put_new(:allow_nil?, false)
|> Keyword.put_new(:default, default)
|> Keyword.put_new(:writable?, false)
quote do
attribute unquote(name), UUIDV7.Type, unquote(field_opts)
end
end
end
What bothered me with that is that this would not add default as uuid_generate_v7() in the postgres layer, it will be nil but the uuid_primary_key will add gen_random_uuid() as the default in postgres layer.
Is that built-in uuidv7 implementation already in master? Can it be tested already? that would be super great!