Rocksky.Filter (Rocksky v0.12.0)

Copy Markdown View Source

Pipe-friendly builder for RSQL filter expressions, accepted by the filter parameter of the catalog and scrobble-feed queries (app.rocksky.song.getSongs, app.rocksky.artist.getArtists, app.rocksky.album.getAlbums, app.rocksky.scrobble.getScrobbles).

alias Rocksky.Filter

Filter.eq(:artist, "Daft Punk")
|> Filter.and_(Filter.gt(:duration, 200_000))
|> Filter.or_(Filter.is_in(:genre, ["house", "electro"]))
|> Filter.build()
# => artist=="Daft Punk";duration=gt=200000,genre=in=(house,electro)

Fields are atoms — :artist, or :"track.artist" for the dotted selectors of the scrobble feed — though binaries are accepted too. String values are quoted and escaped automatically when they contain characters RSQL reserves; * wildcards pass through unquoted, so Filter.eq(:artist, "Daft*") performs a case-insensitive match.

and, or and in are reserved in Elixir, hence and_/2, or_/2, is_in/2 and is_out/2.

Summary

Types

A filterable field, as an atom (:artist, :"track.artist") or binary.

t()

An RSQL filter node: a comparison, or an ;/, combination.

A comparable value: string, number or boolean.

Functions

Both sides must match (;). An or operand is parenthesized to keep RSQL precedence. Pipe-first: a |> Filter.and_(b).

The RSQL expression string to send as the filter query param. Also accepts a plain binary (identity), so query functions can take either.

field==value — equals; * in string values is a wildcard.

field=ge=value — greater than or equal.

field=gt=value — greater than.

field=in=(a,b) — matches any of the values. Raises ArgumentError on an empty list.

field!=null — the field is not NULL.

field==null — the field is NULL.

field=out=(a,b) — matches none of the values. Raises ArgumentError on an empty list.

field=le=value — less than or equal.

field=lt=value — less than.

field!=value — not equals.

Either side may match (,). Pipe-first: a |> Filter.or_(b).

Types

field()

@type field() :: atom() | String.t()

A filterable field, as an atom (:artist, :"track.artist") or binary.

t()

@type t() :: %Rocksky.Filter{expr: String.t(), kind: :comparison | :and | :or}

An RSQL filter node: a comparison, or an ;/, combination.

value()

@type value() :: String.t() | number() | boolean() | atom()

A comparable value: string, number or boolean.

Functions

and_(left, right)

@spec and_(t(), t()) :: t()

Both sides must match (;). An or operand is parenthesized to keep RSQL precedence. Pipe-first: a |> Filter.and_(b).

iex> Rocksky.Filter.eq(:artist, "Radiohead")
...> |> Rocksky.Filter.and_(Rocksky.Filter.gt(:duration, 200_000))
...> |> Rocksky.Filter.build()
"artist==Radiohead;duration=gt=200000"

build(expr)

@spec build(t() | String.t()) :: String.t()

The RSQL expression string to send as the filter query param. Also accepts a plain binary (identity), so query functions can take either.

iex> Rocksky.Filter.build("artist==Radiohead")
"artist==Radiohead"

eq(field, value)

@spec eq(field(), value()) :: t()

field==value — equals; * in string values is a wildcard.

iex> Rocksky.Filter.eq(:artist, "Radiohead") |> Rocksky.Filter.build()
"artist==Radiohead"

iex> Rocksky.Filter.eq(:artist, "Daft Punk") |> Rocksky.Filter.build()
"artist==\"Daft Punk\""

ge(field, value)

@spec ge(field(), value()) :: t()

field=ge=value — greater than or equal.

iex> Rocksky.Filter.ge(:year, 2000) |> Rocksky.Filter.build()
"year=ge=2000"

gt(field, value)

@spec gt(field(), value()) :: t()

field=gt=value — greater than.

iex> Rocksky.Filter.gt(:duration, 200_000) |> Rocksky.Filter.build()
"duration=gt=200000"

is_in(field, values)

@spec is_in(field(), [value()]) :: t()

field=in=(a,b) — matches any of the values. Raises ArgumentError on an empty list.

iex> Rocksky.Filter.is_in(:genre, ["house", "electro"]) |> Rocksky.Filter.build()
"genre=in=(house,electro)"

is_not_null(field)

@spec is_not_null(field()) :: t()

field!=null — the field is not NULL.

iex> Rocksky.Filter.is_not_null(:uri) |> Rocksky.Filter.build()
"uri!=null"

is_null(field)

@spec is_null(field()) :: t()

field==null — the field is NULL.

iex> Rocksky.Filter.is_null(:uri) |> Rocksky.Filter.build()
"uri==null"

is_out(field, values)

@spec is_out(field(), [value()]) :: t()

field=out=(a,b) — matches none of the values. Raises ArgumentError on an empty list.

iex> Rocksky.Filter.is_out(:genre, ["rock"]) |> Rocksky.Filter.build()
"genre=out=(rock)"

le(field, value)

@spec le(field(), value()) :: t()

field=le=value — less than or equal.

iex> Rocksky.Filter.le(:year, 1999) |> Rocksky.Filter.build()
"year=le=1999"

lt(field, value)

@spec lt(field(), value()) :: t()

field=lt=value — less than.

iex> Rocksky.Filter.lt(:trackNumber, 5) |> Rocksky.Filter.build()
"trackNumber=lt=5"

ne(field, value)

@spec ne(field(), value()) :: t()

field!=value — not equals.

iex> Rocksky.Filter.ne(:artist, "Eminem") |> Rocksky.Filter.build()
"artist!=Eminem"

or_(left, right)

@spec or_(t(), t()) :: t()

Either side may match (,). Pipe-first: a |> Filter.or_(b).

iex> Rocksky.Filter.eq(:artist, "Radiohead")
...> |> Rocksky.Filter.or_(Rocksky.Filter.eq(:artist, "Muse"))
...> |> Rocksky.Filter.build()
"artist==Radiohead,artist==Muse"