# Music Library

```elixir
Mix.install([
  {:kino_db, "~> 0.2.10"},
  {:exqlite, "~> 0.23.0"},
  {:kino_vega_lite, "~> 0.1.11"}
])
```

## Setup

<!-- livebook:{"attrs":"eyJkYXRhYmFzZV9wYXRoIjoiL1VzZXJzL2Nsb3VkL2dpdGh1Yi5jb20vY2xvdWQ4NDIxL211c2ljX2xpYnJhcnkvZGF0YS9tdXNpY19saWJyYXJ5X2Rldi5kYiIsInR5cGUiOiJzcWxpdGUiLCJ2YXJpYWJsZSI6ImNvbm4ifQ","chunks":null,"kind":"Elixir.KinoDB.ConnectionCell","livebook_object":"smart_cell"} -->

```elixir
opts = [
  database: "/Users/cloud/github.com/cloud8421/music_library/data/music_library_dev.db"
]

{:ok, conn} = Kino.start_child({Exqlite, opts})
```

## Number of releases per record

<!-- livebook:{"attrs":"eyJjYWNoZV9xdWVyeSI6dHJ1ZSwiY29ubmVjdGlvbiI6eyJ0eXBlIjoic3FsaXRlIiwidmFyaWFibGUiOiJjb25uIn0sImRhdGFfZnJhbWVfYWxpYXMiOiJFbGl4aXIuRXhwbG9yZXIuRGF0YUZyYW1lIiwicXVlcnkiOiJzZWxlY3RcbiAgZGlzdGluY3QganNvbl9leHRyYWN0KGFydGlzdHMsICckWzBdLm5hbWUnKSBBUyBhcnRpc3RfbmFtZSxcbiAgdGl0bGUsXG4gIGpzb25fYXJyYXlfbGVuZ3RoKHJlbGVhc2VfaWRzKSBBUyBudW1iZXJfb2ZfcmVsZWFzZXNcbmZyb20gcmVjb3Jkc1xub3JkZXIgYnkgbnVtYmVyX29mX3JlbGVhc2VzIGRlc2NcbjsiLCJyZXN1bHRfdmFyaWFibGUiOiJjb3VudF9ieV9yZWxlYXNlcyIsInRpbWVvdXQiOm51bGx9","chunks":null,"kind":"Elixir.KinoDB.SQLCell","livebook_object":"smart_cell"} -->

```elixir
count_by_releases =
  Exqlite.query!(
    conn,
    ~S"""
    select
      distinct json_extract(artists, '$[0].name') AS artist_name,
      title,
      json_array_length(release_ids) AS number_of_releases
    from records
    order by number_of_releases desc
    ;
    """,
    []
  )
```

## Count of records per artist

<!-- livebook:{"attrs":"eyJjYWNoZV9xdWVyeSI6dHJ1ZSwiY29ubmVjdGlvbiI6eyJ0eXBlIjoic3FsaXRlIiwidmFyaWFibGUiOiJjb25uIn0sImRhdGFfZnJhbWVfYWxpYXMiOiJFbGl4aXIuRXhwbG9yZXIuRGF0YUZyYW1lIiwicXVlcnkiOiJzZWxlY3QganNvbl9leHRyYWN0KGFydGlzdC52YWx1ZSwgJyQubmFtZScpIGFzIG5hbWUsIGNvdW50KDEpIGFzIGNcbmZyb20gcmVjb3JkcywganNvbl9lYWNoKHJlY29yZHMuYXJ0aXN0cykgYXJ0aXN0XG5ncm91cCBieSBuYW1lXG5vcmRlciBieSBjIGRlc2NcbjsiLCJyZXN1bHRfdmFyaWFibGUiOiJjb3VudF9ieV9hcnRpc3QiLCJ0aW1lb3V0IjpudWxsfQ","chunks":null,"kind":"Elixir.KinoDB.SQLCell","livebook_object":"smart_cell"} -->

```elixir
count_by_artist =
  Exqlite.query!(
    conn,
    ~S"""
    select json_extract(artist.value, '$.name') as name, count(1) as c
    from records, json_each(records.artists) artist
    group by name
    order by c desc
    ;
    """,
    []
  )
```

<!-- livebook:{"attrs":" ","chunks":null,"kind":"Elixir.KinoVegaLite.ChartCell","livebook_object":"smart_cell"} -->

```elixir
VegaLite.new(width: 600, title: "Count by Artist")
|> VegaLite.data_from_values(count_by_artist, only: ["c", "name"])
|> VegaLite.mark(:bar)
|> VegaLite.encode_field(:x, "c", type: :quantitative)
|> VegaLite.encode_field(:y, "name", type: :nominal)
```

## Count of records by genre

<!-- livebook:{"attrs":"eyJjYWNoZV9xdWVyeSI6dHJ1ZSwiY29ubmVjdGlvbiI6eyJ0eXBlIjoic3FsaXRlIiwidmFyaWFibGUiOiJjb25uIn0sImRhdGFfZnJhbWVfYWxpYXMiOiJFbGl4aXIuRXhwbG9yZXIuRGF0YUZyYW1lIiwicXVlcnkiOiJzZWxlY3QgZ2VucmUudmFsdWUsIGNvdW50KGdlbnJlLnZhbHVlKSBhcyBjXG5mcm9tIHJlY29yZHMsIGpzb25fZWFjaChyZWNvcmRzLmdlbnJlcykgZ2VucmVcbmdyb3VwIGJ5IGdlbnJlLnZhbHVlXG5vcmRlciBieSBjIGRlc2NcbjtcbiIsInJlc3VsdF92YXJpYWJsZSI6ImNvdW50X2J5X2dlbnJlIiwidGltZW91dCI6bnVsbH0","chunks":null,"kind":"Elixir.KinoDB.SQLCell","livebook_object":"smart_cell"} -->

```elixir
count_by_genre =
  Exqlite.query!(
    conn,
    ~S"""
    select genre.value, count(genre.value) as c
    from records, json_each(records.genres) genre
    group by genre.value
    order by c desc
    ;

    """,
    []
  )
```

```elixir
VegaLite.new(width: 600, title: "Count by genre (alt)")
|> VegaLite.data_from_values(count_by_genre, only: ["c", "value"])
|> VegaLite.mark(:bar)
|> VegaLite.encode_field(:x, "c", type: :quantitative)
|> VegaLite.encode_field(:y, "value", type: :nominal, sort: "-c")
```

<!-- livebook:{"attrs":" ","chunks":null,"kind":"Elixir.KinoVegaLite.ChartCell","livebook_object":"smart_cell"} -->

```elixir
VegaLite.new(width: 600, title: "Count by genre")
|> VegaLite.data_from_values(count_by_genre, only: ["c", "value"])
|> VegaLite.mark(:bar)
|> VegaLite.encode_field(:x, "c", type: :quantitative)
|> VegaLite.encode_field(:y, "value", type: :nominal)
```

## All unique genres

<!-- livebook:{"attrs":"eyJjYWNoZV9xdWVyeSI6dHJ1ZSwiY29ubmVjdGlvbiI6eyJ0eXBlIjoic3FsaXRlIiwidmFyaWFibGUiOiJjb25uIn0sImRhdGFfZnJhbWVfYWxpYXMiOiJFbGl4aXIuRXhwbG9yZXIuRGF0YUZyYW1lIiwicXVlcnkiOiJzZWxlY3QgZGlzdGluY3QgZ2VucmUudmFsdWVcbmZyb20gcmVjb3JkcywganNvbl9lYWNoKHJlY29yZHMuZ2VucmVzKSBnZW5yZVxuO1xuIiwicmVzdWx0X3ZhcmlhYmxlIjoiZ2VucmVzIiwidGltZW91dCI6bnVsbH0","chunks":null,"kind":"Elixir.KinoDB.SQLCell","livebook_object":"smart_cell"} -->

```elixir
genres =
  Exqlite.query!(
    conn,
    ~S"""
    select distinct genre.value
    from records, json_each(records.genres) genre
    ;

    """,
    []
  )
```

```elixir
Enum.join(genres.rows, ",")
```

## Total artists per country

<!-- livebook:{"attrs":"eyJjYWNoZV9xdWVyeSI6dHJ1ZSwiY29ubmVjdGlvbiI6eyJ0eXBlIjoic3FsaXRlIiwidmFyaWFibGUiOiJjb25uIn0sImRhdGFfZnJhbWVfYWxpYXMiOiJFbGl4aXIuRXhwbG9yZXIuRGF0YUZyYW1lIiwicXVlcnkiOiJTRUxFQ1RcbiAgICBjb3VudCgqKSBBUyB0b3RhbF9hcnRpc3RzLFxuICAgIGpzb25fZXh0cmFjdChtdXNpY2JyYWluel9kYXRhLCAnJC5jb3VudHJ5JykgQVMgY291bnRyeVxuRlJPTSBhcnRpc3RfaW5mb3NcbkdST1VQIEJZIGNvdW50cnlcbk9SREVSIEJZIHRvdGFsX2FydGlzdHMgREVTQzsiLCJyZXN1bHRfdmFyaWFibGUiOiJ0b3RhbF9hcnRpc3RzX3Blcl9jb3VudHJ5IiwidGltZW91dCI6bnVsbH0","chunks":null,"kind":"Elixir.KinoDB.SQLCell","livebook_object":"smart_cell"} -->

```elixir
total_artists_per_country =
  Exqlite.query!(
    conn,
    ~S"""
    SELECT
        count(*) AS total_artists,
        json_extract(musicbrainz_data, '$.country') AS country
    FROM artist_infos
    GROUP BY country
    ORDER BY total_artists DESC;
    """,
    []
  )
```

<!-- livebook:{"attrs":" ","chunks":null,"kind":"Elixir.KinoVegaLite.ChartCell","livebook_object":"smart_cell"} -->

```elixir
VegaLite.new(width: 600, title: "Total artists per country")
|> VegaLite.data_from_values(total_artists_per_country,
  only: ["total_artists", "country"]
)
|> VegaLite.mark(:bar)
|> VegaLite.encode_field(:x, "total_artists", type: :quantitative)
|> VegaLite.encode_field(:y, "country", type: :nominal)
```
