Fix SearchParser catch-all wiping valid filters

The `_, %{}` catch-all in `normalize/1` matched any map, so an
invalid filter (e.g. `format:vin`) would reset the accumulator
even when valid filters were already collected. Add a `map_size`
guard so it only returns `%{query: ""}` for a truly empty
accumulator. Also update the moduledoc.
This commit is contained in:
Claudio Ortolina
2026-03-15 18:56:30 +00:00
parent abb6a5f8f4
commit d815928f91
+19 -5
View File
@@ -1,10 +1,20 @@
defmodule MusicLibrary.Records.SearchParser do
@moduledoc """
This module includes functions to parse a search string containing tagged entities,
e.g. artists or albums.
Parses structured search queries into filter maps.
Implementation is most likely suboptimal, non-idiomatic and failing against specific
edge cases I haven't thought about - not an expert in parsing.
Supports the following filters:
- `artist:value` — filter by artist name
- `album:value` — filter by album name
- `mbid:value` — filter by MusicBrainz ID
- `genre:value` — filter by genre
- `format:value` — filter by format (e.g. `cd`, `vinyl`)
- `type:value` — filter by type (e.g. `album`, `single`)
- `purchase_year:YYYY` — filter by purchase year
Multi-word values can be quoted: `artist:"the pineapple thief"`.
Unrecognized format/type values are silently ignored.
Bare words become free-text query terms.
"""
@type search_result :: %{
@@ -105,6 +115,10 @@ defmodule MusicLibrary.Records.SearchParser do
{:ok, %{query: ""}}
iex> MusicLibrary.Records.SearchParser.parse("type:alb")
{:ok, %{query: ""}}
iex> MusicLibrary.Records.SearchParser.parse("artist:marillion format:vin")
{:ok, %{artist: "marillion"}}
iex> MusicLibrary.Records.SearchParser.parse("artist:marillion type:alb")
{:ok, %{artist: "marillion"}}
iex> MusicLibrary.Records.SearchParser.parse("type:album")
{:ok, %{type: :album}}
iex> MusicLibrary.Records.SearchParser.parse("purchase_year:2024")
@@ -157,7 +171,7 @@ defmodule MusicLibrary.Records.SearchParser do
{:query, [value]}, acc ->
Map.update(acc, :query, value, &(&1 <> " " <> value))
_, %{} ->
_, acc when map_size(acc) == 0 ->
%{query: ""}
_, acc ->