# `LatticeStripe.List`
[🔗](https://github.com/szTheory/lattice_stripe/blob/v0.2.0/lib/lattice_stripe/list.ex#L1)

Represents a paginated list of Stripe objects.

Stripe returns two kinds of paginated collections:

- **Cursor-based lists** — standard list endpoints (e.g., `/v1/customers`). Use
  `starting_after` / `ending_before` to page through results.
- **Search results** — search endpoints (e.g., `/v1/customers/search`). Use
  `next_page` token to page through results. Note: search endpoints have
  **eventual consistency** — newly created objects may not appear immediately.

## Accessing Items

Use `list.data` to access items on the current page:

    {:ok, resp} = LatticeStripe.Client.request(client, req)
    resp.data.data  # list of decoded maps for this page

`LatticeStripe.List` does NOT implement `Enumerable` — `Enum.map(list, ...)` would
mislead callers into thinking they are consuming all pages when they only see page 1.
Use `list.data` for the current page. Use `stream!/2` or `stream/2` to lazily consume
all pages.

## Streaming All Pages

Use `stream!/2` when you have a client and request and want all matching items:

    req = %LatticeStripe.Request{method: :get, path: "/v1/customers", params: %{"limit" => "100"}}
    client
    |> LatticeStripe.List.stream!(req)
    |> Stream.take(200)
    |> Enum.to_list()

Use `stream/2` when you already have a list from a prior request and want the rest:

    {:ok, %Response{data: list}} = Client.request(client, req)
    list
    |> LatticeStripe.List.stream(client)
    |> Enum.each(&process_item/1)

## Memory Warning

When consuming an entire stream with no limit, you load all matching objects into
memory. Use `Stream.take(N)` to limit results and avoid unexpected memory usage.

# `t`

```elixir
@type t() :: %LatticeStripe.List{
  _first_id: String.t() | nil,
  _last_id: String.t() | nil,
  _opts: keyword(),
  _params: map(),
  data: [map()],
  extra: map(),
  has_more: boolean(),
  next_page: String.t() | nil,
  object: String.t(),
  total_count: non_neg_integer() | nil,
  url: String.t() | nil
}
```

A paginated Stripe list response.

Returned by `LatticeStripe.Client.request/2` for list and search endpoints.
Access items with `list.data`; check `list.has_more` to determine if more pages exist.

Use `stream!/2` or `stream/2` to lazily consume all pages instead of manually paginating.

- `data` - Items on the current page (list of decoded maps or typed structs)
- `has_more` - Whether more pages are available
- `url` - The URL for this list (used for cursor-based next-page construction)
- `total_count` - Total item count (only set on some endpoints)
- `next_page` - Page token for search pagination (set when `object` is `"search_result"`)
- `object` - Either `"list"` or `"search_result"`
- `extra` - Any unknown fields from the Stripe response
- `_params` / `_opts` - Stored for internal pagination; not for direct use
- `_first_id` / `_last_id` - Stored cursor IDs; not for direct use

# `from_json`

```elixir
@spec from_json(map(), map(), keyword()) :: t()
```

Builds a `%List{}` struct from decoded Stripe JSON.

Optionally stores the original request params and opts in `_params` and `_opts`
so streaming functions can reconstruct subsequent page requests.

Also computes `_first_id` and `_last_id` from data items for cursor-based
pagination — these are used by streaming functions to build next-page requests
after the data buffer has been fully consumed.

## Examples

    List.from_json(%{"object" => "list", "data" => [...], "has_more" => true, "url" => "/v1/customers"})

    List.from_json(decoded, %{limit: 10}, [stripe_account: "acct_123"])

# `stream`

```elixir
@spec stream(t(), LatticeStripe.Client.t()) :: Enumerable.t()
```

Creates a lazy stream from an existing `%List{}`, re-emitting its items
then fetching remaining pages.

The stream includes items already present in the list, followed by items
from subsequent pages (if `has_more` is true).

Raises `LatticeStripe.Error` if any subsequent page fetch fails.

## Example

    {:ok, %Response{data: list}} = Client.request(client, req)
    # Process first page manually, then stream the rest:
    list
    |> LatticeStripe.List.stream(client)
    |> Enum.each(&process_customer/1)

# `stream!`

```elixir
@spec stream!(LatticeStripe.Client.t(), LatticeStripe.Request.t()) :: Enumerable.t()
```

Creates a lazy stream that auto-paginates through all items matching the request.

Makes the initial API call, then lazily fetches subsequent pages as the stream
is consumed. Emits individual items (flattened from pages), not page structs.

Raises `LatticeStripe.Error` if any page fetch fails (after retries are exhausted).

## Example

    req = %LatticeStripe.Request{method: :get, path: "/v1/customers", params: %{"limit" => "100"}}
    client
    |> LatticeStripe.List.stream!(req)
    |> Stream.take(50)
    |> Enum.to_list()

## Memory Warning

Without `Stream.take/2`, the stream will fetch ALL matching objects.
For large collections, always limit with `Stream.take/2`.

---

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