Hey there,
I am using Cassandra and it takes id as of type timebased uuid so I was curious if there is a way or library in Elixir that can generate Timebased UUID for me.
Thanks.
Hey there,
I am using Cassandra and it takes id as of type timebased uuid so I was curious if there is a way or library in Elixir that can generate Timebased UUID for me.
Thanks.
Which relational-mapping library are you using, if any?
I am using Xandra for cassandra in Elixir if you mean that.
A cursory look through Xandra’s documentation and source code shows that Xandra does not (yet?) expose any way to generate timeuuid’s in Elixir (but only encoding/decoding values genereated from within Cassandra).
I did find another library called ‘Cassandra’ which has not seen very much usage and has not been updated in a couple of years, but it does contain an internal (undocumented) module called Cassandra.UUID which seems to generate UUIDs in the desired format.
Looking at that module in a bit more detail, it seems like the actual work is offloaded to elixir_uuid (which is stable and widely used), and that Cassandra’s timeuuids are nothing else than ‘v1’ UUIDs.
So using elixir_uuid is probably the best approach .
Thank you for the details much appreciated.
I do tried V1 UUID but the rows where not inserted as they come it was randomized.
I can think of two possible reasons:
Actually if the type is timebased uuid then I can insert now()
which it converts to uuid internally.
ksuid is sortable uuid
KSUID is great, and monotonically increasing. Couldn’t push for it more.
I’ll throw ecto_ulid out there too. ULID is a pretty nice ID type (and while I realize this post is about IDs in Cassandra) but its lack of support in Postgres turned into a PITA. I was storing it as a :binary_id
since it’s a 128bit integer but querying by the human-readable format was impossible; I had to convert it manually and that got old.
Anyway, here’s a good write-up of the differences between ULID & KSUID. Both are likely great options for your use case.
My problem with ULID is that it is only length-compatible with UUID, not format-compatible, so it cannot be added to the UUID specs as a new version to the IETF RFC. That is why I prefer UUIDv6 proposal, which could be handled in PostgreSQL and any other implementation with almost no changes to the code.
Exactly. That was the most annoying part for me: having to convert from one format to another. I didn’t really need ULID anyway, but it was nice to get some experience with it.
By format I do not mean hexadecimal representation, but binary representation. Just to make it clear. String 46529a99-5727-4655-b1e9-58ebb8d90c6f
is NOT UUID.
Snowflake IDs, GitHub - pggalaviz/exnowflake: A decentralized, unique, time based ID generator. .
Docs:
Can you explain how to do this? I just get…
** (ArgumentError) Invalid argument; Expected: <<clock_seq::14>>, <<node::48>>
(uuid 1.1.8) lib/uuid.ex:250: UUID.uuid1/3
Thanks.
I just ported the Cassandra::Uuid::Generator
code from the official Cassandra Ruby gem:
defmodule TimeUuid do
use Bitwise, only_operators: true
@gregorian_offset 122192928000000000
def new(date_time, jitter \\ nil) do
jitter = jitter || :rand.uniform(65536)
clock_id = :rand.uniform(65536)
node_id = generate_node_id()
usecs = DateTime.to_unix(date_time, :microsecond) + jitter
t = @gregorian_offset + usecs * 10
time_hi = t &&& 0x0fff000000000000
time_mid = t &&& 0x0000ffff00000000
time_low = t &&& 0x00000000ffffffff
version = 1
clock_id = clock_id &&& 0x3fff
node_id = node_id &&& 0xffffffffffff
variant = 0x8000
n = (time_low <<< 96) ||| (time_mid <<< 48) ||| (time_hi <<< 16)
n = n ||| (version <<< 76)
n = n ||| ((clock_id ||| variant) <<< 48)
n = n ||| node_id
<<n::integer-size(128)>>
|> UUID.binary_to_string!()
end
def generate_node_id do
:math.pow(2, 47)
|> trunc()
|> :rand.uniform()
|> Bitwise.bor(0x010000000000)
end
end