View Source Flop.Cursor (Flop v0.23.0)

Functions for encoding, decoding and extracting cursor values.

Summary

Functions

Decodes a cursor value.

Same as Flop.Cursor.decode/1, but raises an error if the cursor is invalid.

Encodes a cursor value.

Takes a tuple with the node and the edge and the order_by field list and returns the cursor value derived from the edge map.

Takes a tuple with the node and the edge and the order_by field list and returns the cursor value derived from the node map.

Retrieves the start and end cursors from a query result.

Functions

Link to this function

decode(cursor)

View Source (since 0.8.0)
@spec decode(binary()) :: {:ok, map()} | :error

Decodes a cursor value.

Returns :error if the cursor cannot be decoded or the decoded term is not a map with atom keys.

iex> Flop.Cursor.decode("g3QAAAABZAACaWRiAAACDg==")
{:ok, %{id: 526}}

iex> Flop.Cursor.decode("AAAH")
:error

iex> f = fn a -> a + 1 end
iex> cursor = Flop.Cursor.encode(%{a: f})
iex> Flop.Cursor.decode(cursor)
:error

iex> cursor = Flop.Cursor.encode(a: "b")
iex> Flop.Cursor.decode(cursor)
:error

iex> cursor = Flop.Cursor.encode(%{"a" => "b"})
iex> Flop.Cursor.decode(cursor)
:error

Trying to decode a cursor that contains non-existent atoms also results in an error.

iex> Flop.Cursor.decode("g3QAAAABZAAGYmFybmV5ZAAGcnViYmVs")
:error
Link to this function

decode!(cursor)

View Source (since 0.9.0)
@spec decode!(binary()) :: map()

Same as Flop.Cursor.decode/1, but raises an error if the cursor is invalid.

iex> Flop.Cursor.decode!("g3QAAAABZAACaWRiAAACDg==")
%{id: 526}
Link to this function

encode(key)

View Source (since 0.8.0)
@spec encode(map()) :: binary()

Encodes a cursor value.

Flop.Cursor.encode(%{email: "peter@mail", name: "Peter"})
"g3QAAAACdwRuYW1lbQAAAAVQZXRlcncFZW1haWxtAAAACnBldGVyQG1haWw="
Link to this function

get_cursor_from_edge(item, order_by)

View Source (since 0.11.0)
@spec get_cursor_from_edge({map(), map()} | map(), [atom()]) :: map()

Takes a tuple with the node and the edge and the order_by field list and returns the cursor value derived from the edge map.

If a map is passed instead of a tuple, it retrieves the cursor value from that map.

This function can be used for the :cursor_value_func option. See also Flop.Cursor.get_cursor_from_node/2.

iex> record = %{id: 20, name: "George", age: 62}
iex> edge = %{id: 25, relation: "sibling"}
iex>
iex> Flop.Cursor.get_cursor_from_edge({record, edge}, [:id])
%{id: 25}
iex> Flop.Cursor.get_cursor_from_edge({record, edge}, [:id, :relation])
%{id: 25, relation: "sibling"}
iex> Flop.Cursor.get_cursor_from_edge(record, [:id])
%{id: 20}

If the edge is a struct that derives Flop.Schema, join and compound fields are resolved according to the configuration.

iex> record = %{id: 25, relation: "sibling"}
iex> edge = %MyApp.Pet{
...>   name: "George",
...>   owner: %MyApp.Owner{name: "Carl"}
...> }
iex>
iex> Flop.Cursor.get_cursor_from_edge({record, edge}, [:owner_name])
%{owner_name: "Carl"}
iex> Flop.Cursor.get_cursor_from_edge(edge, [:owner_name])
%{owner_name: "Carl"}

iex> record = %{id: 25, relation: "sibling"}
iex> edge = %MyApp.Pet{
...>   given_name: "George",
...>   family_name: "Gooney"
...> }
iex> Flop.Cursor.get_cursor_from_edge({record, edge}, [:full_name])
%{full_name: "Gooney George"}
iex> Flop.Cursor.get_cursor_from_edge(edge, [:full_name])
%{full_name: "Gooney George"}
Link to this function

get_cursor_from_node(item, order_by)

View Source (since 0.11.0)
@spec get_cursor_from_node({map(), map()} | map(), [atom()]) :: map()

Takes a tuple with the node and the edge and the order_by field list and returns the cursor value derived from the node map.

If a map is passed instead of a tuple, it retrieves the cursor value from that map.

This function is used as a default if no :cursor_value_func option is set. See also Flop.Cursor.get_cursor_from_edge/2.

iex> record = %{id: 20, name: "George", age: 62}
iex> edge = %{id: 25, relation: "sibling"}
iex>
iex> Flop.Cursor.get_cursor_from_node({record, edge}, [:id])
%{id: 20}
iex> Flop.Cursor.get_cursor_from_node({record, edge}, [:id, :name])
%{id: 20, name: "George"}
iex> Flop.Cursor.get_cursor_from_node(record, [:id])
%{id: 20}

If the node is a struct that derives Flop.Schema, join and compound fields are resolved according to the configuration.

iex> record = %MyApp.Pet{
...>   name: "George",
...>   owner: %MyApp.Owner{name: "Carl"}
...> }
iex> edge = %{id: 25, relation: "sibling"}
iex>
iex> Flop.Cursor.get_cursor_from_node({record, edge}, [:owner_name])
%{owner_name: "Carl"}
iex> Flop.Cursor.get_cursor_from_node(record, [:owner_name])
%{owner_name: "Carl"}

iex> record = %MyApp.Pet{
...>   given_name: "George",
...>   family_name: "Gooney"
...> }
iex> edge = %{id: 25, relation: "sibling"}
iex> Flop.Cursor.get_cursor_from_node({record, edge}, [:full_name])
%{full_name: "Gooney George"}
iex> Flop.Cursor.get_cursor_from_node(record, [:full_name])
%{full_name: "Gooney George"}
Link to this function

get_cursors(results, order_by, opts \\ [])

View Source (since 0.8.0)
@spec get_cursors([any()], [atom()], [Flop.option()]) ::
  {binary(), binary()} | {nil, nil}

Retrieves the start and end cursors from a query result.

iex> results = [%{name: "Mary"}, %{name: "Paul"}, %{name: "Peter"}]
iex> order_by = [:name]
iex>
iex> {start_cursor, end_cursor} =
...>   Flop.Cursor.get_cursors(results, order_by)
{"g3QAAAABdwRuYW1lbQAAAARNYXJ5", "g3QAAAABdwRuYW1lbQAAAAVQZXRlcg=="}
iex>
iex> Flop.Cursor.decode(start_cursor)
{:ok, %{name: "Mary"}}
iex> Flop.Cursor.decode(end_cursor)
{:ok, %{name: "Peter"}}

If the result set is empty, the cursor values will be nil.

iex> Flop.Cursor.get_cursors([], [:id])
{nil, nil}

The default function to retrieve the cursor value from the query result is Flop.Cursor.get_cursor_from_node/2, which expects the query result to be a map or a 2-tuple. You can set the cursor_value_func option to use another function. Flop also comes with Flop.Cursor.get_cursor_from_edge/2.

If the records in the result set are not maps, you can define a custom cursor value function like this:

iex> results = [{"Mary", 1936}, {"Paul", 1937}, {"Peter", 1938}]
iex> cursor_func = fn {name, year}, order_fields ->
...>   Enum.into(order_fields, %{}, fn
...>     :name -> {:name, name}
...>     :year -> {:year, year}
...>   end)
...> end
iex> opts = [cursor_value_func: cursor_func]
iex>
iex> {start_cursor, end_cursor} =
...>   Flop.Cursor.get_cursors(results, [:name, :year], opts)
{"g3QAAAACdwRuYW1lbQAAAARNYXJ5dwR5ZWFyYgAAB5A=",
  "g3QAAAACdwRuYW1lbQAAAAVQZXRlcncEeWVhcmIAAAeS"}
iex>
iex> Flop.Cursor.decode(start_cursor)
{:ok, %{name: "Mary", year: 1936}}
iex> Flop.Cursor.decode(end_cursor)
{:ok, %{name: "Peter", year: 1938}}