Skip to content
This repository has been archived by the owner on Jun 11, 2023. It is now read-only.

Commit

Permalink
Merge pull request #408 from renatomassaro/helix-id
Browse files Browse the repository at this point in the history
Add new Helix.ID format
  • Loading branch information
renatomassaro authored Jul 4, 2018
2 parents 264ce31 + 4a7d2b7 commit ad321e6
Show file tree
Hide file tree
Showing 142 changed files with 1,568 additions and 688 deletions.
1 change: 1 addition & 0 deletions lib/account/http/controller/webhook.ex
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ defmodule Helix.Account.HTTP.Controller.Webhook do
nil ->
# Account does not exists
account = %Account{
account_id: Account.ID.generate(%{}, :account),
password: password,
email: String.downcase(email),
username: String.downcase(username),
Expand Down
8 changes: 4 additions & 4 deletions lib/account/model/account.ex
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
defmodule Helix.Account.Model.Account do

use Ecto.Schema
use HELL.ID, field: :account_id, meta: [0x0001]
use HELL.ID, field: :account_id

import Ecto.Changeset
import HELL.Ecto.Macros
import HELL.Macros

alias Comeonin.Bcrypt
Expand Down Expand Up @@ -60,6 +61,7 @@ defmodule Helix.Account.Model.Account do
|> cast(params, @creation_fields)
|> generic_validations()
|> prepare_changes()
|> put_pk(%{}, :account)
end

@spec update_changeset(t | Changeset.t, update_params) ::
Expand Down Expand Up @@ -159,10 +161,8 @@ defmodule Helix.Account.Model.Account do
|| [username: "has invalid format"]
end

defmodule Query do
import Ecto.Query
query do

alias Ecto.Queryable
alias Helix.Account.Model.Account

@spec by_id(Queryable.t, Account.idtb) ::
Expand Down
10 changes: 5 additions & 5 deletions lib/entity/model/entity.ex
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
defmodule Helix.Entity.Model.Entity do

use Ecto.Schema
use HELL.ID, field: :entity_id, autogenerate: false
use HELL.ID, field: :entity_id

import Ecto.Changeset
import HELL.Ecto.Macros

alias Ecto.Changeset
alias HELL.Constant
Expand All @@ -26,7 +27,7 @@ defmodule Helix.Entity.Model.Entity do
entity_type: type
}

@creation_fields ~w/entity_type entity_id/a
@creation_fields [:entity_type]

schema "entities" do
field :entity_id, ID,
Expand All @@ -51,12 +52,11 @@ defmodule Helix.Entity.Model.Entity do
|> cast(params, @creation_fields)
|> validate_required(@creation_fields)
|> validate_inclusion(:entity_type, EntityType.possible_types())
|> put_change(:entity_id, params.entity_id)
end

defmodule Query do
import Ecto.Query
query do

alias Ecto.Queryable
alias Helix.Server.Model.Server
alias Helix.Entity.Model.Entity
alias Helix.Entity.Model.EntityServer
Expand Down
4 changes: 4 additions & 0 deletions lib/hell/hell/binary.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
defmodule HELL.Binary do

use EntropyString, charset: "01"
end
32 changes: 32 additions & 0 deletions lib/hell/hell/ecto_macros.ex
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,36 @@ defmodule HELL.Ecto.Macros do

end
end

@doc """
Generates and then inserts the Helix.ID into the changeset.
A custom ID module may be specified at `opts`, otherwise __CALLER__.ID shall
be used.
"""
defmacro put_pk(changeset, heritage, domain, opts \\ unquote([])) do
module = get_pk_module(opts, __CALLER__.module)

gen_pk(changeset, heritage, domain, module)
end

defp gen_pk(changeset, heritage, domain, module) do
quote do

if unquote(changeset).valid? do
field = unquote(module).get_field()
id = unquote(module).generate(unquote(heritage), unquote(domain))

put_change(unquote(changeset), field, id)
else
unquote(changeset)
end

end
end

defp get_pk_module([id: module], _),
do: module
defp get_pk_module([], parent_module),
do: Module.concat(parent_module, :ID)
end
84 changes: 31 additions & 53 deletions lib/hell/hell/id.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,35 @@ defmodule HELL.ID do

defmacro __using__(params) do
model = __CALLER__.module

field = Keyword.fetch!(params, :field)
meta =
params
|> Keyword.get(:meta, [])
|> List.wrap()
|> pad()

id_root = Keyword.get(params, :root, model)

autogenerate = Keyword.get(params, :autogenerate, true)

quote do

@type id :: __MODULE__.ID.t
@type idt :: id | %__MODULE__{unquote(field) => id}
@type idtb :: idt | String.t

@primary_key false

defmodule ID do
@behaviour Ecto.Type

@type t ::
%__MODULE__{}
| %{:__struct__ => atom, root: unquote(id_root), id: tuple}

defstruct [
id: nil,
root: unquote(id_root)
]
defstruct [id: nil, root: unquote(id_root)]

@field unquote(field)

@doc false
def type,
do: :inet

def cast(id = %__MODULE__{}) do
{:ok, id}
end
@doc false
def cast(id = %__MODULE__{}),
do: {:ok, id}

# HACK: use __struct__ to avoid mutual compilation dependency.
# Extracts id from the input record as long as it is the model that
Expand All @@ -45,17 +42,14 @@ defmodule HELL.ID do
{:ok, id}
end

def cast(%Postgrex.INET{address: id}) do
{:ok, %__MODULE__{id: id}}
end
def cast(%Postgrex.INET{address: id}),
do: {:ok, %__MODULE__{id: id}}

def cast(%_{root: unquote(id_root), id: id}) when tuple_size(id) == 8 do
{:ok, %__MODULE__{id: id}}
end
def cast(%_{root: unquote(id_root), id: id}) when tuple_size(id) == 8,
do: {:ok, %__MODULE__{id: id}}

def cast(id = {_, _, _, _, _, _, _, _}) do
{:ok, %__MODULE__{id: id}}
end
def cast(id = {_, _, _, _, _, _, _, _}),
do: {:ok, %__MODULE__{id: id}}

def cast(string) when is_binary(string) do
case HELL.IPv6.binary_to_address_tuple(string) do
Expand All @@ -66,10 +60,10 @@ defmodule HELL.ID do
end
end

def cast(_) do
:error
end
def cast(_),
do: :error

@doc false
def cast!(term) do
{:ok, id} = cast(term)
id
Expand All @@ -87,9 +81,15 @@ defmodule HELL.ID do
def dump(_),
do: :error

def generate do
%__MODULE__{id: HELL.IPv6.generate_address_tuple(unquote(meta))}
end
@doc false
def generate(domain) when is_tuple(domain) or is_atom(domain),
do: generate(%{}, domain)
def generate(heritage, domain),
do: %__MODULE__{id: Helix.ID.generate(heritage, domain)}

@doc false
def get_field,
do: @field

defimpl String.Chars do
defdelegate to_string(struct),
Expand All @@ -100,33 +100,11 @@ defmodule HELL.ID do
def encode(struct, _),
do: "\"" <> HELL.ID.to_string(struct) <> "\""
end
end

# Inject the PK module as the PK autogenerator for the module
alias __MODULE__.ID

@type id :: ID.t
@type idt :: id | %__MODULE__{unquote(field) => id}
@type idtb :: idt | String.t

@primary_key false

if unquote(autogenerate) do
@ecto_autogenerate {unquote(field), {ID, :generate, []}}
end
end
end

@doc false
def pad([]),
do: [0, 0, 0]
def pad([x]),
do: [x, 0, 0]
def pad([x, y]),
do: [x, y, 0]
def pad(list = [_, _, _]),
do: list

@doc false
def to_string(%_{id: id, root: _}) when tuple_size(id) == 8 do
id
Expand Down
5 changes: 0 additions & 5 deletions lib/hell/hell/pk.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,6 @@ defmodule HELL.PK do

@type t :: String.t

@spec pk_for(atom) ::
t
defdelegate pk_for(atom),
to: HELL.PK.Header

def type,
do: :inet

Expand Down
46 changes: 0 additions & 46 deletions lib/hell/hell/pk/header.ex

This file was deleted.

Loading

0 comments on commit ad321e6

Please sign in to comment.