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