

first ( User, ) Use UUID v6 to avoid ordering issuesĪlternatively, you could use UUID v6 to generate sequentially ordered values. With EctoExtras, the above example could look like that: # Without UUIDs Repo. It implements a set of simple helper functions that I find missing from the default Ecto implementation. oneīTW you can check out my EctoExtras package. one # With UUIDs User |> first () |> Repo. To avoid inconsistent results, always make sure to subsort your results by primary key: # Without UUIDs User |> first |> Repo. One catch here is that the inserted_at column is not guaranteed to be unique. In most cases, you’ll probably want to use inserted_at instead of id. To remediate that, make sure to always explicitly pass the column name by which you want to sort your collection. It results in a seemingly buggy behavior of first and last methods. Unfortunately, it has nothing to do with when it was generated compared to other UUID values from the same table. It means that a single UUID from the table will always have a first place when sorting. PostgreSQL can still sort them using the deterministic algorithm. On the contrary, due to UUID’s totally random nature, it is generated in a non-sequential order. We can assume that the most recently created object will have the highest ID value.

Integer primary keys are generated sequentially. By default, they sort objects based on their primary key. I’ve opened a PR trying to improve it.īinary UUID format displayed in Phoenix logs Implicit ordering issueįirst and last Query.API methods may seem broken when used with UUIDs.
#Elixir ecto manual
Unfortunately, currently, Ecto displays the binary format in the logs, so you’ll need to do the manual conversion to work with them.


You only need the string format to construct the UUID queries. You need to follow the similar steps of adding a new GUID type column and based on the value from the old integer foreign key, you must assign correct UUID keys.
#Elixir ecto how to
I will not detail how to migrate associations because it will differ for every use case. MigrationError, " Irreversible migration" end end Migration def up alter table ( " users" ) do add :uuid, :uuid, default: fragment ( " gen_random_uuid()" ), null: false end rename_column table ( " users" ), :id, to: :integer_id rename_column table ( " users" ), :uuid, to: :id execute " ALTER TABLE users drop constraint users_pkey " execute " ALTER TABLE users ADD PRIMARY KEY (id) " # Optionally you remove auto-incremented # default value for integer_id column execute " ALTER TABLE ONLY users ALTER COLUMN integer_id DROP DEFAULT " alter table ( " users" ) do modify :integer_id, :bigint, null: true end execute " DROP SEQUENCE IF EXISTS users_id_seq" end def down do raise Ecto. Then rename the old id column to integer_id, unset it as the primary key in favor of the new uuid column after renaming it to id. You need to start by running a similar migration that will create a new uuid column. If you did not create the project yet, you could use a -binary-id flag to configure it automatically: mix phx.new your_app -binary-id How to migrate a table from integer to UUID primary key?Ĭhanging the primary key type in the table is not straightforward. If you’re starting a new project and would like all your schemas to leverage UUIDs for primary keys without customizing their migrations, you need to add the following line to your config file.Ĭonfig/config.exs config :your_app, yourapp. Insert query with returning option Using UUID as a default Let’s have a look at the resulting SQL query with and without returning: config: INSERT INTO "users" ( "email", "inserted_at", "updated_at" ) VALUES ( $ 1, $ 2, $ 3 ) ", ~ N, ~ N ]
#Elixir ecto code
It’s possible to ship code like: defmodule YourAppWeb. Properly scoping access to resources in web apps with non-trivial business logic is hard.
