bitwalker / uniq

Provides UUID generation, parsing, and formatting. Supports RFC 4122, and the v6 draft extension
Apache License 2.0
98 stars 15 forks source link

Comparing UUID7 doesn't seem to produce the expected results #21

Open themusicman opened 8 months ago

themusicman commented 8 months ago

I am attempting to sort a list of UUIDs and when I use Uniq.UUID.compare to do that I am not getting the list of UUIDs not sorted properly.

Here is the code used to produce and sort the UUIDs and debugging output.

Produce the UUIDs:

uuids_with_index =
  1..10
  |> Enum.to_list()
  |> Enum.map(fn i ->
    {i, Uniq.UUID.uuid7()}
  end)

Output:

uuids_with_index #=> [
  {1, "018dd112-d7d4-79b7-9c3f-cd8f5a268bad"},
  {2, "018dd112-d7d4-7963-ac79-96d0ba13f0e3"},
   {3, "018dd112-d7d4-7348-8dd5-e7a8fed42a22"},
   {4, "018dd112-d7d4-7a48-a433-fcb3294b9fb3"},
   {5, "018dd112-d7d4-72fb-9650-558ff08be388"},
   {6, "018dd112-d7d4-7f7a-80fd-7bf8daeab8ce"},
   {7, "018dd112-d7d4-7b67-8c66-f0b665a19e4f"},
   {8, "018dd112-d7d4-7a80-bad6-2d0378fc51c5"},
   {9, "018dd112-d7d4-74f9-a64f-2ab48c5f1ee8"},
   {10, "018dd112-d7d4-74a4-804b-686439c83abc"}
]

Create the list and reverse it:

uuids = Enum.map(uuids_with_index, fn {_i, uuid} -> uuid end) |> Enum.reverse()

Output:

uuids #=> ["018dd112-d7d4-74a4-804b-686439c83abc", "018dd112-d7d4-74f9-a64f-2ab48c5f1ee8",
 "018dd112-d7d4-7a80-bad6-2d0378fc51c5", "018dd112-d7d4-7b67-8c66-f0b665a19e4f",
 "018dd112-d7d4-7f7a-80fd-7bf8daeab8ce", "018dd112-d7d4-72fb-9650-558ff08be388",
 "018dd112-d7d4-7a48-a433-fcb3294b9fb3", "018dd112-d7d4-7348-8dd5-e7a8fed42a22",
 "018dd112-d7d4-7963-ac79-96d0ba13f0e3", "018dd112-d7d4-79b7-9c3f-cd8f5a268bad"]

Attempt to sort them:

sorted =
  Enum.sort(uuids, fn a, b ->
    case Uniq.UUID.compare(a, b) do
      :eq -> true
      :lt -> true
      :gt -> false
    end
  end)

Sorted output:

sorted #=> ["018dd112-d7d4-7f7a-80fd-7bf8daeab8ce", "018dd112-d7d4-7b67-8c66-f0b665a19e4f",
 "018dd112-d7d4-7a80-bad6-2d0378fc51c5", "018dd112-d7d4-7a48-a433-fcb3294b9fb3",
 "018dd112-d7d4-79b7-9c3f-cd8f5a268bad", "018dd112-d7d4-7963-ac79-96d0ba13f0e3",
 "018dd112-d7d4-74f9-a64f-2ab48c5f1ee8", "018dd112-d7d4-74a4-804b-686439c83abc",
 "018dd112-d7d4-7348-8dd5-e7a8fed42a22", "018dd112-d7d4-72fb-9650-558ff08be388"]
dkuku commented 3 months ago

It's because the resolution is 1ms and all your uuids are generated in the same millisecond. I'm facing the same problem, it cases flaky tests. You need to either add 1ms delay before generating the next uuid. @bitwalker It would be good to have a "special" version that has better time resolution for use in unit tests. It could be named unsafe_uuidv7 so people won't use it by accident. I proposed it also in ex_machina https://github.com/beam-community/ex_machina/issues/463