Snowflake ID for Users
Snowflake ID's are useful for giving a practically unique ID that contains machine and time data.
Snowflake ID for Users
Users and content benefit from Snowflake ID which allow lookups of machine and time data.
Snowflake ID is a format first developed by Twitter in 2010 and has been modified and used by other platforms. It uses Unix epoch time, and machine or shards and is applied to micro-blog posts (Tweets etc), users, media etc etc.
Using Snowflake ID's assigned to content (micro-blog posts) you can lookup content before and after.
I have used the Elixir Snowflake package and applied a simple Snowflake handler for content.
defmodule Folkbot.Accounts.User do
use Ecto.Schema
import Ecto.Changeset
alias Folkbot.Snowflaker
schema "users" do
field :admin, :boolean, default: false
field :banner_image, :string
field :bio, :string
field :editor, :boolean, default: false
field :email, :string
field :first_name, :string
field :host, :boolean, default: false
field :last_name, :string
field :location, :string
field :profile_image, :string
field :seller, :boolean, default: false
field :slug, :string
field :snowflake, :string
field :tagline, :string
field :username, :string
field :website, :string
timestamps()
end
@doc false
def changeset(user, attrs) do
user
|> cast(attrs, [
:username,
:first_name,
:last_name,
:slug,
:email,
:bio,
:location,
:website,
:profile_image,
:banner_image,
:tagline,
:snowflake,
:admin,
:editor,
:host,
:seller])
|> validate_required([
:username,
:email,
:website,
:admin,
:editor,
:host,
:seller])
|> snowflake_for_new_user()
end
def snowflake_for_new_user(changeset) do
Snowflaker.snowflake_for_new_content(changeset)
end
end
The Snowflaker module
defmodule Folkbot.Snowflaker do
import Ecto.Changeset
@moduledoc false
def next_snowflake() do
{:ok, snowflake} = Snowflake.next_id()
to_string(snowflake)
end
def snowflake_for_new_content(changeset) do
snowflake = next_snowflake()
put_change(changeset, :snowflake, snowflake)
end
end
Now whenever a user is created, a Snowflake ID is also created.
I have created a helper script lib/folkbot_web/scripts/user.iex.exs
import Ecto.Query
import Plug.Conn
use Ecto.Schema
import Ecto.Changeset
alias Folkbot.Accounts
alias Folkbot.Accounts.User
time = DateTime.now!("Europe/Copenhagen")
random = Enum.random(0..100000)
user_params = %{
username: "niccolox#{random}}",
website: "devekko.com",
email: "niccolox#{random}@devekko.com",
admin: true,
editor: true,
seller: true,
host: true
}
Accounts.create_user(user_params)
Gives us
iex(9)> random = Enum.random(0..100000)
3772
iex(10)> user_params = %{
...(10)> username: "niccolox#{random}}",
...(10)> website: "devekko.com",
...(10)> email: "niccolox#{random}@devekko.com",
...(10)> admin: true,
...(10)> editor: true,
...(10)> seller: true,
...(10)> host: true
...(10)> }
%{
admin: true,
editor: true,
email: "[email protected]",
host: true,
seller: true,
username: "niccolox3772}",
website: "devekko.com"
}
iex(11)> Accounts.create_user(user_params)
[debug] QUERY OK db=19.4ms decode=2.2ms queue=0.8ms idle=851.0ms
INSERT INTO "users" ("admin","editor","email","host","seller","snowflake","username","website","inserted_at","updated_at") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10) RETURNING "id" [true, true, "[email protected]", true, true, "6831485532917207040", "niccolox3772}", "devekko.com", ~N[2021-08-31 04:16:13], ~N[2021-08-31 04:16:13]]
{:ok,
%Folkbot.Accounts.User{
__meta__: #Ecto.Schema.Metadata<:loaded, "users">,
admin: true,
banner_image: nil,
bio: nil,
editor: true,
email: "[email protected]",
first_name: nil,
host: true,
id: 2,
inserted_at: ~N[2021-08-31 04:16:13],
last_name: nil,
location: nil,
profile_image: nil,
seller: true,
slug: nil,
snowflake: "6831485532917207040",
tagline: nil,
updated_at: ~N[2021-08-31 04:16:13],
username: "niccolox3772}",
website: "devekko.com"
}}
Snowflake functions can work on Snowflake ID's https://hexdocs.pm/snowflake/
Snowflake.Helper.epoch()
1630299375
iex(2)> Snowflake.Helper.machine_id()
1
iex(3)> Snowflake.Util.timestamp_of_id(6831482055310708736)
1628752244785
iex(4)> Snowflake.Util.real_timestamp_of_id(6831482055310708736)
1630382544160
iex(14)> Snowflake.Util.real_timestamp_of_id(6831482055310708736) |> DateTime.from_unix!(:millisecond)
~U[2021-08-31 04:02:24.160Z]
iex(31)> alias Folkbot.Snowflaker
Folkbot.Snowflaker
iex(32)> snowflakeid = Snowflaker.next_snowflake() |> String.to_integer
6831521411299807232
iex(33)> Snowflake.Util.real_timestamp_of_id(snowflakeid) |> DateTime.from_unix!(:millisecond)
~U[2021-08-31 06:38:47.359Z]
Git commit: https://github.com/FolkBot/folkbot/commit/3d5ad7bef0253f14d3a78a5eebda093f97a9ce16