bitwalker / uniq Goto Github PK
View Code? Open in Web Editor NEWProvides UUID generation, parsing, and formatting. Supports RFC 4122, and the v6 draft extension
License: Apache License 2.0
Provides UUID generation, parsing, and formatting. Supports RFC 4122, and the v6 draft extension
License: Apache License 2.0
Including the library without having ecto
in the mix.exs
, compiling the dependency fails with the following error:
== Compilation error in file lib/uuid.ex ==
** (CompileError) lib/uuid.ex:911: module Ecto.ParameterizedType is not loaded and could not be found
(elixir 1.13.4) expanding macro: Kernel.use/1
lib/uuid.ex:911: Uniq.UUID (module)
(elixir 1.13.4) expanding macro: Kernel.if/2
lib/uuid.ex:910: Uniq.UUID (module)
Not sure whether to report this here or in other repositories, but I made an issue in rrrene/credo#1052 that causes tooling in editors using e.g. credo
to break. I'm a newbie Elixir programmer, so not sure whether the issue is something I can resolve or something uniq
can do about it, but I wanted to raise this issue here just in case.
While using dialyzer and this library, it appears that the typespec is incorrect, submitted #16 to try to fix it. Let me know what you think
I'm trying to update my application that uses Uniq to Erlang/OTP 26, but Uniq.UUID.valid?/1
is incorrectly returning false
for valid UUIDs. I ran the Uniq tests (after updating the locked Ecto to v3.9.5), and I'm seeing 16 failures, all of which are related to parsing but none of which specifically parse versions 6 or 7.
โฏ mix test
1) test can autogenerate primary keys (Uniq.Ecto.Test)
test/ecto_test.exs:47
match (=) failed
code: assert {:ok, %UUID{version: 4}} = UUID.parse(uuid)
left: {:ok, %Uniq.UUID{version: 4}}
right: {:error, {:invalid_format, <<240>>, 2, 6, 14}}
stacktrace:
test/ecto_test.exs:52: (test)
2) test generating can generate version 3 (Uniq.Test)
test/uniq_test.exs:147
match (=) failed
code: assert {:ok, %UUID{format: :default, version: 3}} = UUID.parse(default)
left: {:ok, %Uniq.UUID{format: :default, version: 3}}
right: {:error, {:invalid_format, "W", 2, 6, 14}}
stacktrace:
test/uniq_test.exs:154: (test)
3) property parsing can parse any 22-byte base64-encoded string which represents a valid uuid (Uniq.Test)
test/uniq_test.exs:95
Failed with generated values (after 0 successful runs):
* Clause: {version, variant, uuid} <- valid_uuid(:slug)
Generated: {3, <<2::size(2)>>, "AAAAAAAAMACAAAAAAAAAAA"}
match (=) failed
The following variables were pinned:
version = 3
variant = <<2::size(2)>>
code: assert {:ok, %UUID{version: ^version, variant: ^variant}} = UUID.parse(uuid)
left: {:ok, %Uniq.UUID{version: ^version, variant: ^variant}}
right: {:error, {:invalid_format, <<0>>, 2, 6, 14}}
stacktrace:
test/uniq_test.exs:97: anonymous fn/4 in Uniq.Test."property parsing can parse any 22-byte base64-encoded string which represents a valid uuid"/1
(stream_data 0.5.0) lib/stream_data.ex:2148: StreamData.shrink_failure/6
(stream_data 0.5.0) lib/stream_data.ex:2108: StreamData.check_all/7
test/uniq_test.exs:96: (test)
.
4) test generating can generate version 1 (Uniq.Test)
test/uniq_test.exs:139
match (=) failed
code: assert {:ok, %UUID{format: :default, version: 1}} = UUID.parse(default)
left: {:ok, %Uniq.UUID{format: :default, version: 1}}
right: {:error, {:invalid_format, <<218>>, 2, 6, 14}}
stacktrace:
test/uniq_test.exs:143: (test)
.
5) test generating can generate version 4 (Uniq.Test)
test/uniq_test.exs:164
match (=) failed
code: assert {:ok, %UUID{format: :default, version: 4}} = UUID.parse(default)
left: {:ok, %Uniq.UUID{format: :default, version: 4}}
right: {:error, {:invalid_format, "3", 2, 6, 14}}
stacktrace:
test/uniq_test.exs:168: (test)
6) doctest Uniq.UUID.info/2 (1) (Uniq.Test)
test/uniq_test.exs:6
Doctest failed
doctest:
iex> Uniq.UUID.info("870df8e8-3107-4487-8316-81e089b8c2cf", :keyword)
{:ok, [uuid: "870df8e8-3107-4487-8316-81e089b8c2cf",
binary: <<135, 13, 248, 232, 49, 7, 68, 135, 131, 22, 129, 224, 137, 184, 194, 207>>,
type: :default,
version: 4,
variant: :rfc4122]}
code: Uniq.UUID.info("870df8e8-3107-4487-8316-81e089b8c2cf", :keyword) === {:ok, [uuid: "870df8e8-3107-4487-8316-81e089b8c2cf",
binary: <<135, 13, 248, 232, 49, 7, 68, 135, 131, 22, 129, 224, 137, 184, 194, 207>>,
type: :default,
version: 4,
variant: :rfc4122]}
left: {:error, {:invalid_format, "\f", 2, 6, 14}}
right: {
:ok,
[uuid: "870df8e8-3107-4487-8316-81e089b8c2cf", binary: <<135, 13, 248, 232, 49, 7, 68, 135, 131, 22, 129, 224, 137, 184, 194, 207>>, type: :default, version: 4, variant: :rfc4122]
}
stacktrace:
lib/uuid.ex:364: Uniq.UUID (module)
7) doctest Uniq.UUID.info/2 (2) (Uniq.Test)
test/uniq_test.exs:6
Doctest failed
doctest:
iex> Uniq.UUID.info("870df8e8-3107-4487-8316-81e089b8c2cf")
{:ok, %Uniq.UUID{
format: :default,
version: 4,
variant: <<2::2>>,
time: 326283406408022248,
seq: 790,
node: <<129, 224, 137, 184, 194, 207>>,
bytes: <<135, 13, 248, 232, 49, 7, 68, 135, 131, 22, 129, 224, 137, 184, 194, 207>>,
}}
code: Uniq.UUID.info("870df8e8-3107-4487-8316-81e089b8c2cf") === {:ok, %Uniq.UUID{
format: :default,
version: 4,
variant: <<2::2>>,
time: 326283406408022248,
seq: 790,
node: <<129, 224, 137, 184, 194, 207>>,
bytes: <<135, 13, 248, 232, 49, 7, 68, 135, 131, 22, 129, 224, 137, 184, 194, 207>>,
}}
left: {:error, {:invalid_format, "\f", 2, 6, 14}}
right: {:ok, #UUIDv4<870df8e8-3107-4487-8316-81e089b8c2cf>}
stacktrace:
lib/uuid.ex:371: Uniq.UUID (module)
..
8) property parsing can parse any 128-bit binary with valid version/variant values (Uniq.Test)
test/uniq_test.exs:71
Failed with generated values (after 0 successful runs):
* Clause: {version, variant, uuid} <- valid_uuid()
Generated: {3, <<2::size(2)>>, <<0, 0, 0, 0, 0, 0, 48, 0, 128, 0, 0, 0, 0, 0, 0, 0>>}
match (=) failed
The following variables were pinned:
version = 3
variant = <<2::size(2)>>
code: assert {:ok, %UUID{version: ^version, variant: ^variant}} = UUID.parse(uuid)
left: {:ok, %Uniq.UUID{version: ^version, variant: ^variant}}
right: {:error, {:invalid_format, <<0>>, 2, 6, 14}}
stacktrace:
test/uniq_test.exs:73: anonymous fn/4 in Uniq.Test."property parsing can parse any 128-bit binary with valid version/variant values"/1
(stream_data 0.5.0) lib/stream_data.ex:2148: StreamData.shrink_failure/6
(stream_data 0.5.0) lib/stream_data.ex:2108: StreamData.check_all/7
test/uniq_test.exs:72: (test)
9) test generating can generate version 5 (Uniq.Test)
test/uniq_test.exs:172
match (=) failed
code: assert {:ok, %UUID{format: :default, version: 5}} = UUID.parse(default)
left: {:ok, %Uniq.UUID{format: :default, version: 5}}
right: {:error, {:invalid_format, <<243>>, 2, 6, 14}}
stacktrace:
test/uniq_test.exs:179: (test)
..
10) test parsing can parse version 5 (Uniq.Test)
test/uniq_test.exs:59
match (=) failed
The following variables were pinned:
version = 5
code: assert {:ok, %UUID{format: :raw, version: ^version}} = UUID.parse(uuids[:raw][version])
left: {:ok, %Uniq.UUID{format: :raw, version: ^version}}
right: {:error, {:invalid_format, "_", 2, 6, 14}}
stacktrace:
test/uniq_test.exs:207: Uniq.Test.parse/2
test/uniq_test.exs:60: (test)
11) property parsing can parse any 32-byte hex string which represents a valid uuid (Uniq.Test)
test/uniq_test.exs:83
Failed with generated values (after 0 successful runs):
* Clause: {version, variant, uuid} <- valid_uuid(:hex)
Generated: {3, <<2::size(2)>>, "00000000000030008000000000000000"}
match (=) failed
The following variables were pinned:
version = 3
variant = <<2::size(2)>>
code: assert {:ok, %UUID{version: ^version, variant: ^variant}} = UUID.parse(uuid)
left: {:ok, %Uniq.UUID{version: ^version, variant: ^variant}}
right: {:error, {:invalid_format, <<0>>, 2, 6, 14}}
stacktrace:
test/uniq_test.exs:85: anonymous fn/4 in Uniq.Test."property parsing can parse any 32-byte hex string which represents a valid uuid"/1
(stream_data 0.5.0) lib/stream_data.ex:2148: StreamData.shrink_failure/6
(stream_data 0.5.0) lib/stream_data.ex:2108: StreamData.check_all/7
test/uniq_test.exs:84: (test)
......
12) doctest Uniq.UUID.parse/1 (3) (Uniq.Test)
test/uniq_test.exs:6
match (=) failed
code: {:ok, uuid} = Uniq.UUID.parse("f81d4fae-7dec-11d0-a765-00a0c91e6bf6")
left: {:ok, uuid}
right: {:error, {:invalid_format, <<157>>, 2, 6, 14}}
stacktrace:
(for doctest at) lib/uuid.ex:443: (test)
.
13) test parsing can parse version 1 (Uniq.Test)
test/uniq_test.exs:47
match (=) failed
The following variables were pinned:
version = 1
code: assert {:ok, %UUID{format: :raw, version: ^version}} = UUID.parse(uuids[:raw][version])
left: {:ok, %Uniq.UUID{format: :raw, version: ^version}}
right: {:error, {:invalid_format, <<226>>, 2, 6, 14}}
stacktrace:
test/uniq_test.exs:207: Uniq.Test.parse/2
test/uniq_test.exs:48: (test)
.
14) test parsing can parse version 4 (Uniq.Test)
test/uniq_test.exs:55
match (=) failed
The following variables were pinned:
version = 4
code: assert {:ok, %UUID{format: :raw, version: ^version}} = UUID.parse(uuids[:raw][version])
left: {:ok, %Uniq.UUID{format: :raw, version: ^version}}
right: {:error, {:invalid_format, "`", 2, 6, 14}}
stacktrace:
test/uniq_test.exs:207: Uniq.Test.parse/2
test/uniq_test.exs:56: (test)
15) test parsing can parse version 3 (Uniq.Test)
test/uniq_test.exs:51
match (=) failed
The following variables were pinned:
version = 3
code: assert {:ok, %UUID{format: :raw, version: ^version}} = UUID.parse(uuids[:raw][version])
left: {:ok, %Uniq.UUID{format: :raw, version: ^version}}
right: {:error, {:invalid_format, "B", 2, 6, 14}}
stacktrace:
test/uniq_test.exs:207: Uniq.Test.parse/2
test/uniq_test.exs:52: (test)
.
16) doctest Uniq.UUID.parse/1 (4) (Uniq.Test)
test/uniq_test.exs:6
Doctest failed
doctest:
iex> match?({:ok, %Uniq.UUID{format: :default, version: 1}}, Uniq.UUID.uuid1() |> Uniq.UUID.parse())
true
code: match?({:ok, %Uniq.UUID{format: :default, version: 1}}, Uniq.UUID.uuid1() |> Uniq.UUID.parse()) === true
left: false
right: true
stacktrace:
lib/uuid.ex:456: Uniq.UUID (module)
.
Finished in 15.1 seconds (0.1s async, 15.0s sync)
4 doctests, 6 properties, 22 tests, 16 failures
Randomized with seed 100798
I looked at the code and the Erlang/OTP 26 release notes to see if I could spot the problem, but I can't.
I'm not sure if this is an actual problem as I'm not well versed in UUID, but this looks kinda weird.
iex()> Uniq.UUID.valid?("aaaaaa:aa:aaaaaa")
true
To me knowledge this string is not a valid UUID (also checked with some online validator) but I'm happy to be educated on this subject.
If we attempt to parse it:
{:ok, uuid} = Uniq.UUID.parse("aaaaaa:aa:aaaaaa")
uuid |> IO.inspect(structs: false)
%{
__struct__: Uniq.UUID,
bytes: "aaaaaa:aa:aaaaaa",
format: :raw,
node: "aaaaaa",
seq: 24890,
time: 747986083993706849,
variant: <<0::size(1)>>,
version: 3
}
Any idea here? ๐ค
Hey, since I upgraded the package I am getting the following error:
https://github.com/straw-hat-team/beam-monorepo/actions/runs/3123794947
ERROR! the application :uniq has a different value set for key :otp_version during runtime compared to compile time. Since this application environment entry was marked as compile time, this difference can lead to different behaviour than expected:
* Compile time value was set to: #Version<24.0.0>
* Runtime value was not set
To fix this error, you might:
* Make the runtime value match the compile time one
* Recompile your project. If the misconfigured application is a dependency, you may need to run "mix deps.compile uniq --force"
* Alternatively, you can disable this check. If you are using releases, you can set :validate_compile_env to false in your release configuration. If you are using Mix to start your system, you can pass the --no-validate-compile-env flag
21:45:14.798 [error] Task #PID<0.320.0> started from #PID<0.93.0> terminating
** (stop) "aborting boot"
(elixir 1.13.2) Config.Provider.boot/2
Function: &:erlang.apply/2
Args: [#Function<1.45581530/1 in Mix.Tasks.Compile.All.load_apps/3>, [uniq: "/Users/ubi/Developer/github.com/straw-hat-team/beam-monorepo/_build/dev/lib"]]
** (EXIT from #PID<0.93.0>) an exception was raised:
** (ErlangError) Erlang error: "aborting boot"
(elixir 1.13.2) Config.Provider.boot/2
I have
config :my_app, MyApp.Repo,
migration_primary_key: [type: :binary_id],
migration_foreign_key: [type: :binary_id]
(which sets it to uuid
type in DB)
@primary_key {:id, Uniq.UUID, version: 7, autogenerate: true}
@foreign_key_type Uniq.UUID
schema "users" do
# ...
many_to_many :locations, Location, join_through: "user_locations"
end
And if I call Repo.preload(user, [:locations])
I get the following error:
[error] Task #PID<0.730.0> started from #PID<0.723.0> terminating
** (Postgrex.Error) ERROR 42846 (cannot_coerce) cannot cast type uuid to bytea
query: SELECT l0."id", l0."email", l0."name", l0."inserted_at", l0."updated_at", u1."user_id"::bytea
FROM "locations" AS l0 INNER JOIN "user_locations" AS u1 ON l0."id" = u1."location_id"
WHERE (u1."user_id" = ANY($1)) ORDER BY u1."user_id"::bytea
(ecto_sql 3.9.1) lib/ecto/adapters/sql.ex:913: Ecto.Adapters.SQL.raise_sql_call_error/1
(ecto_sql 3.9.1) lib/ecto/adapters/sql.ex:828: Ecto.Adapters.SQL.execute/6
(ecto 3.9.2) lib/ecto/repo/queryable.ex:229: Ecto.Repo.Queryable.execute/4
(ecto 3.9.2) lib/ecto/repo/queryable.ex:19: Ecto.Repo.Queryable.all/3
(ecto 3.9.2) lib/ecto/repo/preloader.ex:272: Ecto.Repo.Preloader.fetch_query/8
(elixir 1.14.2) lib/task/supervised.ex:89: Task.Supervised.invoke_mfa/2
(elixir 1.14.2) lib/task/supervised.ex:34: Task.Supervised.reply/4
(stdlib 4.1.1) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
Function: &:erlang.apply/2
Args: [#Function<8.114411606/1 in Ecto.Repo.Preloader.maybe_pmap/3>,
[#Function<20.114411606/1 in Ecto.Repo.Preloader.prepare_queries/6>]]
What is the best way to make this work?
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"]
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.