Last active
November 8, 2019 04:03
-
-
Save mazz/8e5e91bbaa99bfcca2197e29564a4a40 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Db.Schema.Channel do | |
use Ecto.Schema | |
import Ecto.Changeset | |
alias Db.Type.ChannelHashId | |
@derive {Jason.Encoder, only: [ | |
:basename, | |
:ordinal, | |
:small_thumbnail_path, | |
:med_thumbnail_path, | |
:large_thumbnail_path, | |
:banner_path, | |
:uuid, | |
:org_id, | |
:hash_id, | |
:updated_at, | |
:inserted_at | |
]} | |
schema "channels" do | |
field :basename, :string | |
field :ordinal, :integer | |
field :small_thumbnail_path, :string | |
field :med_thumbnail_path, :string | |
field :large_thumbnail_path, :string | |
field :banner_path, :string | |
field :uuid, Ecto.UUID | |
field :org_id, :id | |
field :hash_id, :string | |
has_many :playlists, Db.Schema.Playlist | |
timestamps(type: :utc_datetime) | |
# timestamps() | |
end | |
@doc false | |
def changeset(channel, attrs) do | |
channel | |
|> changeset_generate_hash_id() | |
|> cast(attrs, [ | |
:uuid, | |
:ordinal, | |
:basename, | |
:large_thumbnail_path, | |
:med_thumbnail_path, | |
:small_thumbnail_path, | |
:banner_path, | |
:org_id, | |
:hash_id | |
]) | |
|> validate_required([ | |
:uuid, | |
:ordinal, | |
:basename, | |
:large_thumbnail_path, | |
:med_thumbnail_path, | |
:small_thumbnail_path, | |
:banner_path, | |
:org_id, | |
:hash_id | |
]) | |
end | |
@doc """ | |
Generate hash ID for channels | |
## Examples | |
iex> Db.Schema.MediaItem.changeset_generate_hash_id(%Db.Schema.Video{id: 42, hash_id: nil}) | |
#Ecto.Changeset<action: nil, changes: %{hash_id: \"4VyJ\"}, errors: [], data: #Db.Schema.Video<>, valid?: true> | |
""" | |
def changeset_generate_hash_id(channel) do | |
change(channel, hash_id: ChannelHashId.encode(channel.id)) | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Db.Type.ChannelHashId do | |
@moduledoc """ | |
Convert a media item integer id to hash | |
""" | |
defmodule InvalidChannelHashError do | |
@moduledoc """ | |
Exception throwed when hash is not valid | |
""" | |
defexception plug_status: 404, message: "Not found", conn: nil, router: nil | |
end | |
@coder Hashids.new( | |
min_len: 4, | |
alphabet: "23456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKMNOPQRSTUVWXYZ", | |
salt: "F41thfu1W0rDCh4Nn€L" | |
) | |
@doc """ | |
Encode a given id | |
## Examples | |
iex> Db.Type.ChannelHashId.encode(42) | |
"4VyJ" | |
""" | |
def encode(id) do | |
Hashids.encode(@coder, id) | |
end | |
@doc """ | |
Decode a given hash | |
## Examples | |
iex> Db.Type.ChannelHashId.decode("JbOz") | |
{:ok, 1337} | |
iex> Db.Type.ChannelHashId.decode("€€€€€€€€€€€€€€€€€") | |
{:error, :invalid_input_data} | |
""" | |
def decode(hash) do | |
case do_decode(hash) do | |
{:ok, [id]} -> {:ok, id} | |
error -> error | |
end | |
end | |
@doc """ | |
Decode a given hash. Raise if hash is invalid | |
## Examples | |
iex> Db.Type.ChannelHashId.decode!("JbOz") | |
1337 | |
iex> catch_throw(Db.Type.ChannelHashId.decode!("€€€")) | |
Db.Type.ChannelHashId.InvalidChannelHashError | |
""" | |
def decode!(hash) do | |
case do_decode(hash) do | |
{:ok, [id]} -> id | |
_error -> throw(InvalidChannelHashError) | |
end | |
end | |
defp do_decode(hash), | |
do: Hashids.decode(@coder, hash) | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
``` | |
[error] #PID<0.789.0> running FaithfulWordApi.Endpoint (connection #PID<0.788.0>, stream id 1) terminated | |
Server: localhost:4000 (http) | |
Request: POST //v1.3/channels/add | |
** (exit) an exception was raised: | |
** (FunctionClauseError) no function clause matching in Hashids.encode/2 | |
(hashids) lib/hashids.ex:82: Hashids.encode(%Hashids{a_len: 40, alphabet: 'yaDkQqw57BMjE4gmzKXrYvdNAp6WPbO3VRGJ8o9e', g_len: 4, guards: 'Zx2n', min_len: 4, s_len: 13, salt: [70, 52, 49, 116, 104, 102, 117, 49, 87, 48, 114, 68, 67, 104, 52, 78, 110, 8364, 76], seps: 'sUCTucHtifhSF'}, nil) | |
(db) lib/db_schema/channel.ex:79: Db.Schema.Channel.changeset_generate_hash_id/1 | |
(db) lib/db_schema/channel.ex:41: Db.Schema.Channel.changeset/2 | |
(faithful_word_api) lib/faithful_word_api/controllers/api/v1.3/v13.ex:256: FaithfulWordApi.V13.add_channel/7 | |
(faithful_word_api) lib/faithful_word_api/controllers/api/channel_controller.ex:22: FaithfulWordApi.ChannelController.addv13/2 | |
(faithful_word_api) lib/faithful_word_api/controllers/api/channel_controller.ex:1: FaithfulWordApi.ChannelController.action/2 | |
(faithful_word_api) lib/faithful_word_api/controllers/api/channel_controller.ex:1: FaithfulWordApi.ChannelController.phoenix_controller_pipeline/2 | |
(phoenix) lib/phoenix/router.ex:288: Phoenix.Router.__call__/2 | |
(faithful_word_api) lib/faithful_word_api/endpoint.ex:1: FaithfulWordApi.Endpoint.plug_builder_call/2 | |
(faithful_word_api) lib/plug/debugger.ex:122: FaithfulWordApi.Endpoint."call (overridable 3)"/2 | |
(faithful_word_api) lib/faithful_word_api/endpoint.ex:1: FaithfulWordApi.Endpoint.call/2 | |
(phoenix) lib/phoenix/endpoint/cowboy2_handler.ex:42: Phoenix.Endpoint.Cowboy2Handler.init/4 | |
(cowboy) /Users/michael/src/phx/faithfulword-phx/deps/cowboy/src/cowboy_handler.erl:41: :cowboy_handler.execute/2 | |
(cowboy) /Users/michael/src/phx/faithfulword-phx/deps/cowboy/src/cowboy_stream_h.erl:296: :cowboy_stream_h.execute/3 | |
(cowboy) /Users/michael/src/phx/faithfulword-phx/deps/cowboy/src/cowboy_stream_h.erl:274: :cowboy_stream_h.request_process/3 | |
(stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3 | |
``` |
Solution:
was passing a nil struct to .encode() because I needed to insert the item into the db before adding the hashid. This was because the item needs a .id to generate the hash. The solution chosen was to a) remove :hash_id from validate_required and b) use Ecto Multi to run the changeset and then update the insert with the hashid:
changeset = Channel.changeset(%Channel{}, %{
ordinal: ordinal,
basename: basename,
small_thumbnail_path: small_thumbnail_path,
med_thumbnail_path: med_thumbnail_path,
large_thumbnail_path: large_thumbnail_path,
banner_path: banner_path,
org_id: org_id,
uuid: Ecto.UUID.generate()
})
Multi.new()
|> Multi.insert(:item_without_hash_id, changeset)
|> Multi.run(:channel, fn _repo, %{item_without_hash_id: channel} ->
channel
|> Channel.changeset_generate_hash_id()
|> Repo.update()
end)
|> Repo.transaction()
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
add channel code: