Page MenuHomePhorge

No OneTemporary

Size
10 KB
Referenced Files
None
Subscribers
None
diff --git a/lib/flake_id.ex b/lib/flake_id.ex
index 20428cf..997fcee 100644
--- a/lib/flake_id.ex
+++ b/lib/flake_id.ex
@@ -1,125 +1,100 @@
# FlakeID: Decentralized, k-ordered ID generation service
# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: LGPL-3.0-only
defmodule FlakeID do
@moduledoc """
Decentralized, k-ordered ID generation service.
"""
import Kernel, except: [to_string: 1]
@doc """
Converts a binary Flake to a String
## Examples
iex> FlakeID.to_string(<<0, 0, 1, 109, 67, 124, 251, 125, 95, 28, 30, 59, 36, 42, 0, 0>>)
"9n2ciuz1wdesFnrGJU"
"""
- # compatibility with older serial integers
- def to_string(<<0::integer-size(64), id::integer-size(64)>>) do
- Kernel.to_string(id)
- end
-
def to_string(<<_::integer-size(64), _::integer-size(48), _::integer-size(16)>> = binary_flake) do
<<integer::integer-size(128)>> = binary_flake
Base62.encode(integer)
end
def to_string(string), do: string
@doc """
Converts a String to a binary Flake
## Examples
iex> FlakeID.from_string("9n2ciuz1wdesFnrGJU")
<<0, 0, 1, 109, 67, 124, 251, 125, 95, 28, 30, 59, 36, 42, 0, 0>>
"""
- @spec from_string(String.t() | integer) :: nil | <<_::128>>
+ @spec from_string(binary()) :: nil | <<_::128>>
def from_string(string)
-
- # zero or -1 is a null flake
- for i <- [-1, 0] do
- def from_string(unquote(i)), do: <<0::integer-size(128)>>
- def from_string(unquote(Kernel.to_string(i))), do: <<0::integer-size(128)>>
- end
-
- def from_string(int) when is_integer(int) do
- int
- |> Kernel.to_string()
- |> from_string()
- end
-
def from_string(<<_::integer-size(128)>> = flake), do: flake
-
- def from_string(string) when is_binary(string) and byte_size(string) < 18 do
- case Integer.parse(string) do
- {id, ""} -> <<0::integer-size(64), id::integer-size(64)>>
- _ -> nil
- end
- end
-
+ def from_string(string) when is_binary(string) and byte_size(string) < 18, do: nil
def from_string(string), do: string |> Base62.decode!() |> from_integer
@doc """
Converts a binary Flake to an integer
## Examples
iex> FlakeID.to_integer(<<0, 0, 1, 109, 67, 124, 251, 125, 95, 28, 30, 59, 36, 42, 0, 0>>)
28939165907792829150732718047232
"""
@spec to_integer(<<_::128>>) :: non_neg_integer
def to_integer(binary_flake)
def to_integer(<<integer::integer-size(128)>>), do: integer
@doc """
Converts an integer to a binary Flake
## Examples
iex> FlakeID.from_integer(28939165907792829150732718047232)
<<0, 0, 1, 109, 67, 124, 251, 125, 95, 28, 30, 59, 36, 42, 0, 0>>
"""
@spec from_integer(integer) :: <<_::128>>
def from_integer(integer) do
<<_time::integer-size(64), _node::integer-size(48), _seq::integer-size(16)>> =
<<integer::integer-size(128)>>
end
@doc """
Generates a string with Flake
"""
@spec get :: String.t()
def get, do: FlakeID.Worker.get() |> to_string()
@doc """
Checks that ID is a valid FlakeID
## Examples
iex> FlakeID.flake_id?("9n2ciuz1wdesFnrGJU")
true
iex> FlakeID.flake_id?("#cofe")
false
iex> FlakeID.flake_id?("pleroma.social")
false
"""
@spec flake_id?(String.t()) :: boolean
def flake_id?(id), do: flake_id?(String.to_charlist(id), true)
defp flake_id?([c | cs], true) when c >= ?0 and c <= ?9, do: flake_id?(cs, true)
defp flake_id?([c | cs], true) when c >= ?A and c <= ?Z, do: flake_id?(cs, true)
defp flake_id?([c | cs], true) when c >= ?a and c <= ?z, do: flake_id?(cs, true)
defp flake_id?([], true), do: true
defp flake_id?(_, _), do: false
end
diff --git a/lib/flake_id/ecto/compat_type.ex b/lib/flake_id/ecto/compat_type.ex
new file mode 100644
index 0000000..1f3fdb1
--- /dev/null
+++ b/lib/flake_id/ecto/compat_type.ex
@@ -0,0 +1,68 @@
+# FlakeID: Decentralized, k-ordered ID generation service
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: LGPL-3.0-only
+
+defmodule FlakeID.Ecto.CompatType do
+ @moduledoc """
+ Provides a compatibility Ecto type for someone wishes to migrate from integer ids to flakes.
+
+ ## Schema Example
+
+ @primary_key {:id, FlakeID.Ecto.CompatType, autogenerate: true}
+
+ schema "posts" do
+ add :body, :string
+ end
+
+ """
+
+ import Kernel, except: [to_string: 1]
+
+ @behaviour Ecto.Type
+
+ def embed_as(_), do: :self
+
+ def equal?(term1, term2), do: term1 == term2
+
+ def type, do: :uuid
+
+ defdelegate autogenerate, to: FlakeID, as: :get
+
+ def cast(value) do
+ {:ok, to_string(value)}
+ end
+
+ def load(value) do
+ {:ok, to_string(value)}
+ end
+
+ def dump(value) do
+ {:ok, from_string(value)}
+ end
+
+ defp to_string(<<0::integer-size(64), id::integer-size(64)>>), do: Kernel.to_string(id)
+ defp to_string(binary_flake), do: FlakeID.to_string(binary_flake)
+
+ # zero or -1 is a null flake
+ for i <- [-1, 0] do
+ defp from_string(unquote(i)), do: <<0::integer-size(128)>>
+ defp from_string(unquote(Kernel.to_string(i))), do: <<0::integer-size(128)>>
+ end
+
+ defp from_string(int) when is_integer(int) do
+ int
+ |> Kernel.to_string()
+ |> from_string()
+ end
+
+ defp from_string(<<_::integer-size(128)>> = flake), do: flake
+
+ defp from_string(string) when is_binary(string) and byte_size(string) < 18 do
+ case Integer.parse(string) do
+ {id, ""} -> <<0::integer-size(64), id::integer-size(64)>>
+ _ -> nil
+ end
+ end
+
+ defp from_string(string), do: FlakeID.from_string(string)
+end
diff --git a/test/flake_id/ecto/compat_type_test.exs b/test/flake_id/ecto/compat_type_test.exs
new file mode 100644
index 0000000..c5ea4ce
--- /dev/null
+++ b/test/flake_id/ecto/compat_type_test.exs
@@ -0,0 +1,57 @@
+defmodule FlakeID.Ecto.CompatTypeTest do
+ use ExUnit.Case, async: true
+
+ alias FlakeID.Ecto.CompatType
+
+ @flake_string "9n2ciuz1wdesFnrGJU"
+ @flake_binary <<0, 0, 1, 109, 67, 124, 251, 125, 95, 28, 30, 59, 36, 42, 0, 0>>
+ @fake_flake <<0::integer-size(64), 42::integer-size(64)>>
+
+ test "cast/1" do
+ assert CompatType.cast(@flake_binary) == {:ok, @flake_string}
+ assert CompatType.cast(@flake_string) == {:ok, @flake_string}
+ end
+
+ test "load/1" do
+ assert CompatType.load(@flake_binary) == {:ok, @flake_string}
+ assert CompatType.load(@flake_string) == {:ok, @flake_string}
+ end
+
+ test "dump/1" do
+ assert CompatType.dump(@flake_string) == {:ok, @flake_binary}
+ assert CompatType.dump(@flake_binary) == {:ok, @flake_binary}
+ end
+
+ test "equal?/2" do
+ assert CompatType.equal?(@flake_binary, @flake_binary) == true
+ end
+
+ test "autogenerate/0" do
+ flake = CompatType.autogenerate()
+
+ assert String.valid?(flake)
+ assert FlakeID.flake_id?(flake)
+ end
+
+ describe "fake flakes (compatibility with older serial integers)" do
+ test "with an integer" do
+ assert CompatType.dump(42) == {:ok, @fake_flake}
+ end
+
+ test "with an integer as string" do
+ assert CompatType.dump("42") == {:ok, @fake_flake}
+ end
+
+ test "zero or -1 is a null flake" do
+ null_flake = <<0::integer-size(128)>>
+ assert CompatType.dump(0) == {:ok, null_flake}
+ assert CompatType.dump(-1) == {:ok, null_flake}
+ assert CompatType.dump("0") == {:ok, null_flake}
+ assert CompatType.dump("-1") == {:ok, null_flake}
+ end
+
+ test "cast" do
+ assert CompatType.cast(@fake_flake) == {:ok, "42"}
+ end
+ end
+end
diff --git a/test/flake_id_test.exs b/test/flake_id_test.exs
index 8bcad76..927088d 100644
--- a/test/flake_id_test.exs
+++ b/test/flake_id_test.exs
@@ -1,86 +1,57 @@
defmodule FlakeIDTest do
use ExUnit.Case, async: true
doctest FlakeID
@flake_string "9n2ciuz1wdesFnrGJU"
@flake_binary <<0, 0, 1, 109, 67, 124, 251, 125, 95, 28, 30, 59, 36, 42, 0, 0>>
@flake_integer 28_939_165_907_792_829_150_732_718_047_232
test "flake_id?/1" do
assert FlakeID.flake_id?(@flake_string)
refute FlakeID.flake_id?("http://example.com/activities/3ebbadd1-eb14-4e20-8118-b6f79c0c7b0b")
refute FlakeID.flake_id?("#cofe")
end
test "get/0" do
flake = FlakeID.get()
assert String.valid?(flake)
assert FlakeID.flake_id?(flake)
end
describe "to_string/1" do
test "with binary" do
assert FlakeID.to_string(@flake_binary) == @flake_string
bin = <<1::integer-size(64), 2::integer-size(48), 3::integer-size(16)>>
assert FlakeID.to_string(bin) == "LygHa16ApeN"
end
test "does nothing with other types" do
assert FlakeID.to_string("cofe") == "cofe"
assert FlakeID.to_string(42) == 42
end
end
describe "from_string/1" do
test "with a flake string" do
assert FlakeID.from_string(@flake_string) == @flake_binary
end
- test "with an integer" do
- assert FlakeID.from_string(42) == <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42>>
- end
-
- test "with an integer as string" do
- assert FlakeID.from_string("42") == <<0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42>>
- end
-
test "with a flake binary" do
assert FlakeID.from_string(@flake_binary) == @flake_binary
end
test "with a non flake string" do
assert FlakeID.from_string("cofe") == nil
end
end
test "to_integer/1" do
assert FlakeID.to_integer(@flake_binary) == @flake_integer
end
test "from_integer/1" do
assert FlakeID.from_integer(@flake_integer) == @flake_binary
end
-
- describe "fake flakes (compatibility with older serial integers)" do
- test "from_string/1" do
- fake_flake = <<0::integer-size(64), 42::integer-size(64)>>
- assert FlakeID.from_string("42") == fake_flake
- assert FlakeID.from_string(42) == fake_flake
- end
-
- test "to_string/1" do
- fake_flake = <<0::integer-size(64), 42::integer-size(64)>>
- assert FlakeID.to_string(fake_flake) == "42"
- end
-
- test "zero or -1 is a null flake" do
- null_flake = <<0::integer-size(128)>>
- assert FlakeID.from_string(0) == null_flake
- assert FlakeID.from_string(-1) == null_flake
- assert FlakeID.from_string("0") == null_flake
- assert FlakeID.from_string("-1") == null_flake
- end
- end
end

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jul 21, 3:04 AM (4 h, 8 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1695638
Default Alt Text
(10 KB)

Event Timeline