Last active
May 10, 2020 13:40
-
-
Save DanCouper/84b4e15306896d0260179f4c9ee35c1c to your computer and use it in GitHub Desktop.
collection schemas
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 Collection.Artist do | |
use Ecto.Schema | |
schema "artists" do | |
field(:name, :string) | |
end | |
def changeset(struct, params) do | |
struct | |
|> Ecto.Changeset.cast(params, [:name]) | |
|> Ecto.Changeset.validate_required([:name]) | |
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 Collection do | |
alias Collection.{Release, Repo} | |
@type track :: %{title: String.t(), artists: [String.t()]} | |
@spec add_release(%{ | |
label: String.t(), | |
title: String.t(), | |
tracks: [track()], | |
year: integer() | |
}) :: any | |
def add_release(release_map) do | |
%Release{} | |
|> Release.changeset(release_map) | |
|> Repo.insert!() | |
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 Collection.Release do | |
use Ecto.Schema | |
import Ecto.Query, only: [from: 2] | |
schema "releases" do | |
field(:title, :string) | |
field(:year, :integer) | |
field(:label, :string) | |
field(:notes, :string) | |
many_to_many(:tracks, Collection.Track, join_through: "tracks_releases") | |
many_to_many(:artists, Collection.Artist, join_through: "releases_artists") | |
end | |
def changeset(struct, params) do | |
struct | |
|> Ecto.Changeset.cast(params, [:title, :year, :label, :notes]) | |
|> Ecto.Changeset.validate_required([:title, :year]) | |
|> Ecto.Changeset.validate_number(:year, greater_than: 1940, less_than: 2020) | |
|> Ecto.Changeset.put_assoc(:tracks, get_or_insert_tracks(params[:tracks])) | |
|> Ecto.Changeset.put_assoc(:artists, get_or_insert_artists(params[:tracks])) | |
end | |
def get_or_insert_tracks(tracks) do | |
Collection.Repo.insert_all(Collection.Track, tracks, on_conflict: :nothing) | |
track_titles = Enum.map(tracks, fn %{title: title} -> title end) | |
tracks_query = from t in Collection.Track, where: t.title in ^track_titles | |
Collection.Repo.all(tracks_query) | |
end | |
def get_or_insert_artists([head | rest] = _tracks) do | |
%{artists: head_artists} = head | |
release_artists = | |
if Enum.all?(rest, fn %{artists: artists} -> artists == head_artists end) do | |
Enum.map(head_artists, fn artist -> %{name: artist} end) | |
else | |
[%{name: "Various Artists"}] | |
end | |
Collection.Repo.insert_all( | |
Collection.Artist, | |
release_artists, | |
on_conflict: :nothing | |
) | |
artists_query = from a in Collection.Artist, where: a.name in ^release_artists | |
Collection.Repo.all(artists_query) | |
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 Collection.Track do | |
use Ecto.Schema | |
import Ecto.Query, only: [from: 2] | |
schema "tracks" do | |
field(:title, :string) | |
field(:notes, :string) | |
many_to_many(:artists, Collection.Artist, join_through: "tracks_artists") | |
end | |
def changeset(struct, params) do | |
struct | |
|> Ecto.Changeset.cast(params, [:title, :notes]) | |
|> Ecto.Changeset.validate_required([:title]) | |
|> Ecto.Changeset.put_assoc(:artists, get_or_insert_artists(params[:artists])) | |
end | |
def get_or_insert_artists(artists) do | |
Collection.Repo.insert_all( | |
Collection.Artist, | |
Enum.map(artists, fn artist -> %{name: artist} end), | |
on_conflict: :nothing | |
) | |
artists_query = from a in Collection.Artist, where: a.name in ^artists | |
Collection.Repo.all(artists_query) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment