# `Refine.Flop`

Adapter for using [Flop](https://hex.pm/packages/flop) with Refine.

Translates Flop's filter and pagination parameters into Refine search options.
Facet value selection (OR sets within a facet) remains part of Refine's own options,
while Flop handles field filters and offset pagination.

# `create_facets_table_return`

```elixir
@type create_facets_table_return() ::
  {:ok, String.t()}
  | {:error, :column_not_found, String.t()}
  | {:error, :column_names_not_unique}
  | {:error, :facets_table_exists, String.t()}
  | {:error, :identity_column_already_exists, String.t()}
  | {:error, :identity_column_invalid_type, String.t()}
  | {:error, :identity_column_not_found, String.t()}
  | {:error, :invalid_table_name, String.t()}
  | {:error, :table_names_not_unique}
  | {:error, Exception.t()}
```

# `database_option`

```elixir
@type database_option() :: {:repo, repo()} | postgrex_option()
```

# `database_options`

```elixir
@type database_options() :: [database_option()]
```

# `facet_config`

```elixir
@type facet_config() :: %{
  facet_label: String.t() | nil,
  facet_name: String.t(),
  join_table: String.t() | nil,
  label_column: String.t() | nil,
  label_path: String.t() | nil,
  value_column: String.t() | nil,
  value_path: String.t() | nil,
  width_bucket: [integer() | float()] | nil
}
```

# `facet_configs`

```elixir
@type facet_configs() :: [facet_config()]
```

# `facets_table_config`

```elixir
@type facets_table_config() ::
  %{
    add_identity_column_if_not_exists: boolean() | nil,
    facets_table: String.t(),
    facets: facet_configs(),
    identity_column: String.t(),
    joins: join_configs() | nil,
    roaringbitmap_type: String.t() | nil,
    source_table: String.t()
  }
  | keyword()
```

# `flop`

```elixir
@type flop() :: struct()
```

# `flop_meta`

```elixir
@type flop_meta() :: struct()
```

# `flop_params`

```elixir
@type flop_params() :: map()
```

# `join_config`

```elixir
@type join_config() :: %{
  table: String.t(),
  match: String.t(),
  to: String.t(),
  on: String.t() | nil
}
```

# `join_configs`

```elixir
@type join_configs() :: [join_config()]
```

# `order_by_entry`

```elixir
@type order_by_entry() ::
  {String.t(), order_direction()}
  | {String.t(), order_direction(), sort_nulls()}
```

# `order_direction`

```elixir
@type order_direction() :: :asc | :desc
```

# `postgrex_option`

```elixir
@type postgrex_option() :: {:timeout, integer() | :infinity} | {:log, boolean()}
```

# `postgrex_options`

```elixir
@type postgrex_options() :: [postgrex_option()]
```

# `repo`

```elixir
@type repo() :: module()
```

# `search_option`

```elixir
@type search_option() ::
  {:facets, map()}
  | {:limit, integer()}
  | {:offset, integer()}
  | {:order_by, [order_by_entry()]}
  | {:query, Ecto.Query.t()}
  | {:repo, repo()}
  | {:result_fields, [String.t()]}
  | postgrex_option()
```

# `search_options`

```elixir
@type search_options() :: [search_option()]
```

# `search_return`

```elixir
@type search_return() :: {:ok, search_return_data()} | {:error, Exception.t()}
```

# `search_return_data`

```elixir
@type search_return_data() :: %{
  facets: map(),
  rows: [map()],
  total_count: integer(),
  types: map(),
  flop_meta: map() | nil
}
```

# `sort_nulls`

```elixir
@type sort_nulls() :: :first | :last | :default
```

# `search`

```elixir
@spec search(facets_table_config(), flop_params(), search_options()) ::
  search_return()
```

Runs a Refine search using Flop params, resolving the base query and
pagination from `opts`.

Returns Refine's search result map with an added `flop_meta` key holding a
`Flop.Meta` struct built from the search's `total_count`.

Raises if the `flop` dependency is not available; if a schema cannot be
resolved from `for` or the base query; or if the Flop params are invalid.

# `to_search_options`

```elixir
@spec to_search_options(flop_params(), search_options()) :: search_options()
```

Translates Flop params into Refine search options.

Returns `opts` with `:query` set to the Flop-filtered query and
`:limit` / `:offset` resolved. All other options are passed through.

This does not produce a `Flop.Meta` struct; use `search/3` for that.

## Options

  - `:for` - the Ecto schema backing the Flop params. Required if no `:query`
    is given, or if the query's source schema can't be determined.
  - `:query` - a base Ecto query. Defaults to a query built from `:for`.
  - `:limit` and `:offset` - explicit pagination; takes precedence over
    Flop's. Must be given together or not at all.

Raises if the `flop` dependency is not available; if a schema cannot be
resolved from `for` or the base query; or if the Flop params are invalid.

