# Upgrading to v0.18

## Bump Your Deps

Update Backpex to the latest version:

```elixir
defp deps do
  [
    {:backpex, "~> 0.18.0"}
  ]
end
```

## Move layout to callback (recommended)

The `layout` option in `use Backpex.LiveResource` stores the layout module reference in a module attribute, which creates a compile-time dependency. In most Phoenix applications this leads to a compile cycle:

```
YourLive → YourLayouts → YourWeb (:html) → YourRouter → YourLive
```

This causes a change in any of these files to recompile all of them, slowing down development.

To fix this, move the layout from the `use` option to the new `layout/1` callback:

**Before:**

```elixir
defmodule MyAppWeb.PostLive do
  use Backpex.LiveResource,
    layout: {MyAppWeb.Layouts, :admin},
    adapter_config: [...]
end
```

**After:**

```elixir
defmodule MyAppWeb.PostLive do
  use Backpex.LiveResource,
    adapter_config: [...]

  @impl Backpex.LiveResource
  def layout(_assigns), do: {MyAppWeb.Layouts, :admin}
end
```

The `layout` option continues to work, so this change is not required. However, we recommend migrating to the callback to avoid compile cycles.

You can verify the improvement by running:

```bash
mix xref graph --format cycles --label compile-connected
```

## Filter System Refactoring

The filter system has been refactored to use Ecto changeset-based validation. **This is a breaking change that affects custom filters.** See the [Filter Validation Guide](../filter/filter-validation.md) for full documentation.

### Migration Checklist

1. **Add `type/1` callback** to all custom filters
   - Return `:string` for single-value filters
   - Return `{:array, :string}` for multi-select filters
   - Return `:map` for range filters (with start/end values)
   - Return `:integer`, `:float`, etc. for numeric filters

2. **Remove value parsing** from `query/4`
   - Values are already cast to the correct type
   - Invalid values are filtered out before reaching `query/4`

3. **Optionally add `changeset/3`** for custom validation
   - Use standard `Ecto.Changeset` validation functions

4. **Optionally display validation errors** in `render_form/1`
   - The `@errors` assign is now available (defaults to `[]`)
   - Use the `.error` component for error display

No changes required if you're only using built-in filters with `use Backpex.Filters.<Type>`.

### Before / After

```elixir
# Before (v0.17) - query/4 received raw URL strings
def query(query, attribute, value, _assigns) do
  case Integer.parse(value) do
    {int_value, ""} -> where(query, [x], field(x, ^attribute) > ^int_value)
    _ -> query
  end
end

# After (v0.18) - query/4 receives validated, casted values
@impl Backpex.Filter
def type(_assigns), do: :integer

@impl Backpex.Filter
def query(query, attribute, value, _assigns) do
  where(query, [x], field(x, ^attribute) > ^value)
end
```

### Adapter and Criteria Changes

If you're building a custom adapter or directly calling `Backpex.Adapters.Ecto.apply_filters/4`:

- `apply_filters` now takes 4 arguments: `(query, filter_values, filter_configs, assigns)`
- The criteria keyword list now uses `filter_values` and `filter_configs` keys instead of `filters`
- `filter_options/2` has been removed from `Backpex.LiveResource` — use `@filter_values` assign or `LiveResource.build_criteria/1` instead
- `empty_filter_key/0` has been removed from `Backpex.LiveResource`

### New Filter Validation Error Strings

The new filter validation introduces error messages that flow through `Backpex.translate_error/1` and your configured `error_translator_function`. If you use Gettext for translation, add entries for these strings in the `errors` domain:

| msgid | Used by |
|---|---|
| `contains invalid options` | Boolean, MultiSelect filters |
| `has invalid start value` | Range filter |
| `has invalid end value` | Range filter |
| `start must be less than or equal to end` | Range filter |
| `has invalid date format` | Range filter |
| `is not a valid option` | Select filter |
