{@thread.name}

moissela
2023-08-09

moissela:

Hi there, already released a new Ash extension for enhancing Ash UUID fields support.

AshUUID allows usage for UUID v4 and the new v7 draft (official paper: https://www.ietf.org/archive/id/draft-peabody-dispatch-new-uuid-format-04.html#name-uuid-version-7 , more about: https://blog.devgenius.io/analyzing-new-unique-identifier-formats-uuidv6-uuidv7-and-uuidv8-d6cc5cd7391a ).

You can use public shortened version of UUIDs through base62 encoding while keeping them stored as native raw uuid column on Postgres (with all the indexing / querying benefits).

AshUUID allows using public shortened version with prefix at the beginning (configurable, default to resource name) like Stripe does for better APIs (more about: https://dev.to/stripe/designing-apis-for-humans-object-ids-3o5a ).

New AshPostgres feature ( https://github.com/ash-project/ash_postgres/pull/162 ) allows Ash extensions to easily ship Postgres functions extensions through the new AshPostgres.CustomExtension behaviour (example: https://github.com/zoonect-oss/ash_uuid/blob/main/lib/ash_uuid/postgres_extension.ex ). With AshPostgres v1.3.41 release, AshUUID provides Postgres-side UUIDv7 generation (through uuid_generate_v7 sql function) for better db integrity.

AshUUID adoption:

  • add {:ash_uuid, "~> 0.2"} to your mix.exs project deps;
  • add AshUUID.PostgresExtension to your app Repo’s installed_extensions and set AshUUID config migration_default?: true if Postgres-side UUIDs generation is needed;
  • use the extension in your resources use Ash.Resource, data_layer: AshPostgres.DataLayer, extensions: [AshUUID]
  • simply use that for your fields uuid_attribute :id

v0.2.2 is released on Hex: feel free to open issues/PRs or to reply to this thread, feedbacks are welcome 🙂

Happy for my first contribution to the Ash community 💪🏼

https://github.com/zoonect-oss/ash_uuid

jharton:

This is awesome work!

Eduardo B. Alexandre:

Great extension man!

Quick question, I disabled prefixes globally, but when relationships are loaded, they all come with “id_” as the prefix, how can I remove that?

moissela:

Thank you! Try to force recompilation of the extension with: mix deps.compile ash_uuid –force

Eduardo B. Alexandre:

Nah, it still shows up as “id_” for every relationship (belongs_to) that I load when reading a resource

moissela:

mmm ok <@816769011533742100>: I’ll check and try to fix that as soon as possible. Could you open an issue on GH for this?

moissela:

<@816769011533742100> I did a quick test on an open project using ash_uuid and it seems to work fine 🤷🏼‍♂️ I realized this could probably be something not well described in the readme: the configuration is described like this config :ash_uuid, :ash_uuid, prefixed?: false but the first :ash_uuid should match your project’s application otp name, for example config :example_app, :ash_uuid, prefixed?: false

Eduardo B. Alexandre:

Ah, yes, I’m aware of that, it did confuse me the first time tbh, but I’m using it the correct way now:

config :feedback_cupcake, :ash_uuid,
  version: 7,
  encoded?: true,
  prefixed?: false,
  migration_default?: true

But I still have the problem above.

I will try to create a small example that triggers the issue and will create a new issue in GH (I already created one there about resources that have relationships it themselves btw).

moissela:

thanks! I’ll check both together

Eduardo B. Alexandre:

<@477481255097597972> https://github.com/zoonect-oss/ash_uuid/issues/2

moissela:

Hi <@816769011533742100> I’ve released v0.3.0 fixing both 🤞🏼

Eduardo B. Alexandre:

Amazing! I will be testing it right now 🚀

Eduardo B. Alexandre:

<@477481255097597972> I just tested it, resources with relationships with themselves seems to be working great, but many to_many relationships still returns the ids with the default prefix (`id `). Both when creating the resource or when retrieving it (like the example I gave in the GH issue ticket)

Eduardo B. Alexandre:

moissela:

Have you added AshUUID like I wrote here https://github.com/zoonect-oss/ash_uuid/issues/2#issuecomment-1675939636 ?

moissela:

You’ve to include AshUUID extension also in the BlibsBlobs resource to fix.

Eduardo B. Alexandre:

Ah.. I totally missed that comment 🤦‍♂️ Working great after adding AshUUID in the resource. Thanks again for the help and great extension!

Eduardo B. Alexandre:

Quick question, seems like the extension doesn’t work when a resource doesn’t have AshPostgres.Datalayer data_layer, is that by design?

moissela:

No, not by design 😅 I’ll check that too

Eduardo B. Alexandre:

I can create a new issue ticket in GH if you prefer

moissela:

Yep, it would be great

Eduardo B. Alexandre:

There you go: https://github.com/zoonect-oss/ash_uuid/issues/3

moissela:

Thanks, I’ll check that as soon as possible

moissela:

Hi <@816769011533742100>, v0.4.0 released with volatile and embedded resources support 😉

Eduardo B. Alexandre:

Amazing, working like a charm!

Eduardo B. Alexandre:

Hey <@477481255097597972> I believe I found another bug when using AshUUID with embedded resources, I created a ticket describing the issue: https://github.com/zoonect-oss/ash_uuid/issues/4

moissela:

Hi <@816769011533742100>, v.0.5.0 just released should fix that 🙂

kernel_io:

I’m having the occasional issue

kernel_io:

kernel_io:

kernel_io:

kernel_io:

this only happening when I try and load something related on the Queue

kernel_io:

i.e:

kernel_io:

and get_by_id is just a code_interface with get_by: [:id]

kernel_io:

it seems to think it’s initially in integer format 🤔

kernel_io:

kernel_io:

tags are a many_to_many on queue

kernel_io:

kernel_io:

hmm

kernel_io:

it could be my UUID’s aren’t actually v7 uuids

kernel_io:

I might have missed some data conversion

kernel_io:

🤡 how the hell do I have V2 UUID’s in my DB 😆

kernel_io:

okay all the data is v7 now

kernel_io:

but now I get this

kernel_io:

because it seems to think the prefix should be id , instead of queue

kernel_io:

kernel_io:

feels like Ash or whatever doesn’t look at the prefix which is set automatically on the Resource when trying to build the belongs_to relationship

kernel_io:

right, so the ‘fix’ for this is to do this

kernel_io:

add the constraints to the uuid arg so that ash_uuid knows what it is expecting, makes me think maybe we shouldn’t fail so hard when it’s an unknown prefix

kernel_io:

hope you all enjoyed being my rubber ducks 🙂

kernel_io:

so I’ve set prefixed? to false, as I don’t really need it, but I’m still getting something trying to be prefixed, I’ve deleted the _build dir numerous times so no idea why something is still trying to add prefixes

kernel_io:

I’m trying to delete a related item - it had worked before adding ash uuid, but now I see that its trying to add an id_ prefix infront of the id for the changeset - so the changeset fails as it will create a new record instead of deleting what there is

kernel_io:

<:thinkies:915154230078222336>

kernel_io:

thats the id from my event handler at the top, and then the changeset contains id_ <:thinkies:915154230078222336>

kernel_io:

need to add prefixed? false on the constraint, I swear it’s not reading my config.exs defaults

kernel_io:

okay this whole thing is tripping hard

kernel_io:

I have prefixed?: false on my app config, but occasionally cast_input/2 still gets called with prefix set to “id” and prefixed? set to true

kernel_io:

<@477481255097597972> what’s the recommended way forward for this then? all I can think of is modifying the cast_input to check the resource’s definition

kernel_io:

I don’t think it does that currently

kernel_io:

and Ash just sets the defaults on it

kernel_io:

I honestly feel like it’s a bug with Ash, as it’s only in very specific cases

kernel_io:

kernel_io:

these are just the defaults from the type, not the configured types on the app

kernel_io:

so is this a fix in ash or in this?

kernel_io:

<@197905764424089601> pinging you for input as this probably should have been in a support thread 😬

moissela:

Hi <@891520354802106389>, I can’t well understand what is the current issue by your messages, if it’s one or plus related issues and if it concern to AshUUID (I bet on that 😅) or Ash. Can you put together some code to reproduce the bug and submit an issue on github so I can try to help?

moissela:

Have you tried to run a mix deps.compile ash --force after editing the config.exs file? Sometimes it helps 🤷🏼‍♂️

moissela:

Here it should be argument :tag_id, AshUUID.UUID, allon_nil?: false I think, because :uuid is the Ash uuid standard type

zachdaniel:

Yeah, a small reproduction would be the next step here 🙂

zachdaniel:

And to make sure you’re on the latest ash and ash postgres

kernel_io:

I’ll summarise here

kernel_io:

  1. I override :uuid with AshUUID.UUID (although this wouldn’t affect what I see as the ‘bug’)
  2. when I have an action argument (and I’ll assume elsewhere) that uses :uuid (or AshUUID.UUID), the action gets built with the default constraints from AshUUID.UUID instead of the constraints that I define in the config.exs file
  3. this means I need to explicitly override the constraints on each argument to disable the prefixes - otherwise AshUUID will add a prefix etc to the ID, and things will start acting weird

kernel_io:

I think 2 is just due to how Ash works, I don’t think there is a way for it to know what the constraints should be in an agnostic way

kernel_io:

  1. other than the bug described in #2, I have had issues at times where AshUUID.UUID is too strict with parsing the ids - i.e: I have a read action that wants an ID which I’ll use to load a resource which is prefixed with a custom prefix, obviously there is no way for anything to know what I mean to use that id for, but AshUUID will explode - because by default it wants “id” prefix, and I might pass it a “fish” prefix, I don’t necessarily care about what the prefix is, all I want is for the type to drop the prefix and decode the encoded UUID

kernel_io:

to get around #4 you need to be explicit, I don’t really consider it a bug, #2 I consider being a bug, if there is a default set which gets applied to the uuid_attribute macro, then I’d expect that default to be used elsewhere AshUUID is used

kernel_io:

I’m always on the latest 😜

zachdaniel:

<@891520354802106389> hat do you mean “constraints that you define in the config.exs file”?

zachdaniel:

I haven’t used AshUUID myself yet, so maybe I’m missing something

kernel_io:

in the config.exs you set some defaults, i.e: enable prefixing, enabled encoding, what version of uuid to use. these defaults get used in the uuid_attribute macro, but not in anything else that uses AshUUID.UUID

kernel_io:

config :vmx, :ash_uuid,
  version: 7,
  encoded?: true,
  prefixed?: false,
  migration_default?: true

kernel_io:

and this is the action argument not respecting the setup I have in config.exs

moissela:

I think that I can add an uuid_argument macro for using configured defaults while keeping that overridable also in arguments

kernel_io:

🙏🏿 would be amazing, I looked through ash source code and didn’t see a way to hook it easily

moissela:

yes, without another macro it could be difficult

moissela:

I will try to fix 1) 2) 3) with a new uuid_argument macro tomorrow

moissela:

and I will add a new “strict: true | false” config for 4)

moissela:

both as default and as override

zachdaniel:

We should talk about how this is being done and where those config values are used

zachdaniel:

If you pull those in and make them defaults in the constraints function on the type, then you can apply them for any usage of the type

kernel_io:

I was messing about with that but I’m honestly not very good at macro / precompilation type stuff

kernel_io:

currently the constraints function just returns a nimble opts stuct

kernel_io:

so I wasn’t sure of how you’d make that dynamic based on application env 🙂

zachdaniel:

You could set the defaults to the values from the config

zachdaniel:

You’d do something like thisL

def constraints() do
  [
    version: [
      ...,
      default: get_config(:version, ...)
    ]
  ]
end

zachdaniel:

Then each can be ovverriden per type, but will take the defaults from the config

moissela:

<@197905764424089601> Is there already an example of configurable extension so that I can take a look at code?

moissela:

which module the get_config fn came from? is your only an example?

kernel_io:

only as an example

moissela:

ah no! you’re referencing mine AshUUID.Config.get_config/1 <@197905764424089601> , right?

kernel_io:

nope

moissela:

so, based on your advice <@197905764424089601> I think I now understand something that I didn’t understand when I developed AshUUID and I would like you to confirm it for me

moissela:

Ash will call CustomType.constraints/0 for getting constraints defaults and merge them with user’s overrides?

moissela:

If so, yes <@891520354802106389> : I can change constraints/0 for using configured defaults

kernel_io:

I have this so far

  @impl true
  def constraints() do
    Enum.map(@constraints, fn {key, value} ->
      {key, Keyword.replace(value, :default, AshUUID.Config.get_config([]) |> Map.get(key, ""))}
    end)
  end

kernel_io:

just playing with it

kernel_io:

I think we could make prefix nillable also

kernel_io:

either nil or string

moissela:

<@891520354802106389> can you submit an issue with a small resource and an action with an AshUUID argument, describing your actual problem? So that I’ve a reproducible example of your case that I can add to tests I will try to release a fix for that (and the new strict mode for 4) today

kernel_io:

I won’t have time to do it for a while unfortunately 😦

kernel_io:

have just tested this snippet of code above and it works

kernel_io:

I can make an issue with some basic code in it

kernel_io:

but won’t be able to do set up test cases etc

kernel_io:

i.e: config.ex …. resource.ex …..

expected output …..

actual output …..

kernel_io:

okay snippet doesn’t fix #4 , but it fixes #2

moissela:

I think we can remove the global configured prefix default because it make no sense. If a project needs prefixed ids is because that ids should clarify which resource belongs to, so having a global unique prefix make no sense.

kernel_io:

yup, especially considering you already precompute it when using the macro

kernel_io:

I’ve never seen an “id_”

kernel_io:

as everything has a pregenerated prefix already

moissela:

For the issue I need only the example case, I’ll take care of test cases on myself

moissela:

yes, per-resource prefix default generation through macro came next the global configured default that was present from beginning and now I think we can clear that config 🙂

moissela:

I think #4 will be resolved through removing the global configured prefix and the new “non-strict mode” config that I’ll add, can you fill an issue also for #4 ?

kernel_io:

yup

moissela:

thank you! I’ve some time to work on AshUUID this afternoon (italian time zone)

kernel_io:

I don’t think #4 is a bug to be honest

kernel_io:

I think #4 can be left alone (apart from removing the global configured prefix)

kernel_io:

because if I am using prefixes then I should be explicit with my actions to say what type of resource it’s expecting right

moissela:

Ok, I agree

moissela:

Hi <@891520354802106389> and sorry for the delay, I’ve been very busy. Just released v0.6.0 with configurable defaults on standard arguments, new uuid_argument macro (for prefixed mode when automatic prefix based on resource name is needed), some bug fixes and the new deactivable strict mode. Let me know 😉

kernel_io:

installed it and will play with it tonight’ish