# `Flop.Cursor`
[🔗](https://github.com/woylie/flop/blob/0.26.4/lib/flop/cursor.ex#L1)

Functions for encoding, decoding and extracting cursor values.

# `decode`
*since 0.8.0* 

```elixir
@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

# `decode!`
*since 0.9.0* 

```elixir
@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}

# `encode`
*since 0.8.0* 

```elixir
@spec encode(map()) :: binary()
```

Encodes a cursor value.

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

# `get_cursor_from_edge`
*since 0.11.0* 

```elixir
@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"}

# `get_cursor_from_node`
*since 0.11.0* 

```elixir
@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"}

# `get_cursors`
*since 0.8.0* 

```elixir
@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}}

---

*Consult [api-reference.md](api-reference.md) for complete listing*
