Skip to content

Commit

Permalink
Merge pull request #667 from naymspace/feature/adapter-bang
Browse files Browse the repository at this point in the history
standardize and improve resource and adapter modules
  • Loading branch information
Flo0807 authored Jan 24, 2025
2 parents b683984 + facf5c5 commit b89cb87
Show file tree
Hide file tree
Showing 19 changed files with 249 additions and 151 deletions.
2 changes: 1 addition & 1 deletion demo/lib/demo_web/item_actions/soft_delete.ex
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ defmodule DemoWeb.ItemActions.SoftDelete do
socket =
try do
updates = [set: [deleted_at: datetime]]
{:ok, _items} = Backpex.Resource.update_all(items, updates, "deleted", socket.assigns.live_resource)
{:ok, _count} = Backpex.Resource.update_all(items, updates, "deleted", socket.assigns.live_resource)

socket
|> clear_flash()
Expand Down
4 changes: 2 additions & 2 deletions demo/lib/demo_web/live/ticket_live.ex
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ defmodule DemoWeb.TicketLive do
<Backpex.HTML.CoreComponents.icon name="hero-information-circle" class="h-5 w-5" />
<p>
This resource uses the <strong>Ash adapter</strong>, which is currently in a very early alpha stage.
Currently, only <strong>index</strong> and <strong>show</strong> are functional in a very basic form.
We are working on supporting more Backpex features in the future.
Currently, only <strong>index</strong>, <strong>show</strong> and <strong>delete</strong> are functional in a
very basic form. We are working on supporting more Backpex features in the future.
</p>
</div>
"""
Expand Down
4 changes: 4 additions & 0 deletions demo/lib/demo_web/live/user_live.ex
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ defmodule DemoWeb.UserLive do
where: is_nil(u.deleted_at)
end

def item_query(query, _live_action, _assigns) do
query
end

def init_order(_assigns) do
%{by: :username, direction: :asc}
end
Expand Down
4 changes: 2 additions & 2 deletions guides/actions/item-actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ defmodule DemoWeb.ItemAction.SoftDelete do

socket =
try do
{:ok, _items} =
{:ok, _count_} =
Backpex.Resource.update_all(
socket.assigns,
items,
Expand Down Expand Up @@ -201,4 +201,4 @@ The `c:Backpex.ItemAction.handle/3` function is called when the item action is t

By default an item action is triggered immediately when the user clicks on the corresponding icon in the resource table or in the show view, but an item actions also supports a confirmation dialog. To enable the confirmation dialog you need to implement the `c:Backpex.ItemAction.confirm/1` function and return a string that will be displayed in the confirmation dialog. The confirmation dialog will be displayed when the user clicks on the icon in the resource table.

You might want to use the `c:Backpex.ItemAction.cancel_label/0` (defaults to "Cancel") and `c:Backpex.ItemAction.confirm_label/0` (defaults to "Apply") functions to set the labels of the buttons in the dialog.
You might want to use the `c:Backpex.ItemAction.cancel_label/1` (defaults to "Cancel") and `c:Backpex.ItemAction.confirm_label/1` (defaults to "Apply") functions to set the labels of the buttons in the dialog.
6 changes: 6 additions & 0 deletions guides/live_resource/item-query.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,16 @@ use Backpex.LiveResource,
query
|> where([post], post.published)
end

def item_query(query, _live_action, _assigns) do
query
end
```

The example above will filter all posts by a published boolean on `index` view. We also made use of the named binding. It's always the name of the provided schema in `snake_case`. It is recommended to build your `item_query` on top of the incoming query. Otherwise you will likely get binding errors.

Make sure to always cover all possible cases or add a fallback `item_query/3` function that just returns the query.

> #### Important {: .info}
>
> Note that it is not possible to use an anonymous function for `item_query` configuration. You must refer to a public function defined within a module.
17 changes: 17 additions & 0 deletions guides/upgrading/v0.10.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Upgrading to v0.10

## Bump Your Deps

Update Backpex to the latest version:

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

## LiveView 1.0

See [phoenix_live_view changelog](https://github.com/phoenixframework/phoenix_live_view/blob/main/CHANGELOG.md) for info on how to upgrade to `1.0`.
47 changes: 47 additions & 0 deletions guides/upgrading/v0.11.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Upgrading to v0.11

## Bump Your Deps

Update Backpex to the latest version:

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

## Parameter changes in core modules

In case you are using `Backpex.Resource` or one of the `Backpex.Adapter` modules (`Backpex.Adapters.Ecto` or
`Backpex.Adapters.Ash`) directly check out the updated function definitions. This will also apply in case you built your
own adapter.

## Make sure to cover all cases with the `item_query/3` function

We have removed code that ensures that a fallback item query function is always added to your LiveResource.

Make sure to always cover all possible cases or add a fallback `item_query/3` function that just returns the query.

For example:

```elixir
# in your resource configuration file (live resource)
use Backpex.LiveResource,
# ...other options
adapter_config: [
# ...other adapter options
item_query: &__MODULE__.item_query/3
]

def item_query(query, :index, _assigns) do
query
|> where([post], post.published)
end

# make sure to add this fallback function
def item_query(query, _live_action, _assigns) do
query
end
```
2 changes: 1 addition & 1 deletion guides/upgrading/v0.3.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Update Backpex to the latest version:
```elixir
defp deps do
[
{:backpex, "~> 0.3.1"}
{:backpex, "~> 0.3.0"}
]
end
```
Expand Down
18 changes: 15 additions & 3 deletions guides/upgrading/v0.5.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Upgrading to v0.5

## Bump Your Deps

Update Backpex to the latest version:

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

## Uploads: Item in `consume_upload/4` now contains changes

Previously, we passed the item without its changes to the `consume_upload/4` callback function. With 0.5, we now pass the persisted item (with its changes) to the function.
Expand Down Expand Up @@ -66,7 +78,7 @@ defmodule MyAppWeb.Admin.ItemActions.Delete do

socket =
try do
{:ok, _items} =
{:ok, _count} =
Backpex.Resource.update_all(
socket.assigns,
items,
Expand Down Expand Up @@ -100,7 +112,7 @@ defmodule MyAppWeb.Admin.ItemActions.Delete do

socket =
try do
{:ok, _items} =
{:ok, _count} =
Backpex.Resource.update_all(
socket.assigns,
items,
Expand All @@ -126,4 +138,4 @@ Note that the data is now casted. Therefore you now have atom keys instead of st

## Refactor the use of icons

We have refactored the way we use icons in Backpex. Previously, we installed [the Heroicons hex.pm package](https://hex.pm/packages/heroicons). We now require a Tailwind plugin that generates the styles for a new `Backpex.HTML.CoreComponents.icon/1` component. This is the default way of using heroicons in new Phoenix projects. We documented the new way in the [installation guide](get_started/installation.md#provide-tailwind-plugin-for-icons).
We have refactored the way we use icons in Backpex. Previously, we installed [the Heroicons hex.pm package](https://hex.pm/packages/heroicons). We now require a Tailwind plugin that generates the styles for a new `Backpex.HTML.CoreComponents.icon/1` component. This is the default way of using heroicons in new Phoenix projects. We documented the new way in the [installation guide](get_started/installation.md#provide-tailwind-plugin-for-icons).
14 changes: 13 additions & 1 deletion guides/upgrading/v0.6.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Upgrading to v0.6

# Change `Backpex.Fields.ManyToMany` to `Backpex.Fields.HasMany`
## Bump Your Deps

Update Backpex to the latest version:

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

## Change `Backpex.Fields.ManyToMany` to `Backpex.Fields.HasMany`

With version 0.6, we have combined the `Backpex.Fields.ManyToMany` and `Backpex.Fields.HasMany` field. The functionality of the fields is now combined in the `Backpex.Fields.HasMany` field. The API of the field has not changed, so you can simply replace `Backpex.Fields.ManyToMany` with `Backpex.Fields.HasMany` in your resource configuration.
14 changes: 13 additions & 1 deletion guides/upgrading/v0.7.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Upgrading to v0.7

## Bump Your Deps

Update Backpex to the latest version:

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

## Update calls to [`Backpex.Field.handle_index_editable/2`](Backpex.Field.html#handle_index_editable/3)

We have updated the arity and syntax of [`Backpex.Field.handle_index_editable/2`](Backpex.Field.html#handle_index_editable/3). It is now [`Backpex.Field.handle_index_editable/3`](Backpex.Field.html#handle_index_editable/3) and accepts the `socket`, the `value` and the `change`. We now need the value to update the form accordingly.
Expand Down Expand Up @@ -28,7 +40,7 @@ We have updated certain functions in `Backpex.Resource`.

The following functions are affected:
- `Backpex.Resource.update/6` (`update/5` before)
- `Backpex.Resource.insert/6` (`insert/5` before)
- [`Backpex.Resource.insert/6`]() (`insert/5` before)
- [`Backpex.Resource.change/7`]()
- [`Backpex.Resource.put_assocs/2`]() (has been removed)

Expand Down
43 changes: 43 additions & 0 deletions guides/upgrading/v0.8.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,49 @@ You now have to provide a Keyword list with the `name`, `topic` and `event_prefi

In addition, all options of the LiveResource and the corresponding adapters are now validated at compile time.

### Refactor item query

With the release of the adapter pattern, the `item_query/3` function has to be configured in the adapter config.

If you had an `item_query/3` configuration like this:

```elixir
# in your resource configuration file (live resource)
use Backpex.LiveResource,
# ...options

@impl Backpex.LiveResource
def item_query(query, :index, _assigns) do
query
|> where([post], post.published)
end
```

change it to an adapter config:

```elixir
# in your resource configuration file (live resource)
use Backpex.LiveResource,
# ...other options
adapter_config: [
# ...other adapter options
item_query: &__MODULE__.item_query/3
]

def item_query(query, :index, _assigns) do
query
|> where([post], post.published)
end

def item_query(query, _live_action_, _assigns) do
query
end
```

See [Item Query documentation](../live_resource/item-query.md) for more information.

> Note that the `item_query/3` function is only used in `Backpex.Adapters.Ecto`.
### Changed `Backpex.Resource` parameters

If you are not using this module directly in your code, you can safely ignore this section.
Expand Down
23 changes: 8 additions & 15 deletions lib/backpex/adapter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -27,48 +27,41 @@ defmodule Backpex.Adapter do
Should return `nil` if no result was found.
"""
@callback get(term(), term(), term()) :: term()

@doc """
Gets a database record with the given primary key value.
Should raise an exception if no result was found.
"""
@callback get!(term(), term(), term()) :: term()
@callback get(term(), map(), module()) :: {:ok, struct() | nil} | {:error, term()}

@doc """
Returns a list of items by given criteria.
"""
@callback list(term(), term(), term(), term()) :: term()
@callback list(keyword(), map(), module()) :: {:ok, list()}

@doc """
Gets the total count of the current live_resource.
Possibly being constrained the item query and the search- and filter options.
"""
@callback count(term(), term(), term(), term()) :: term()
@callback count(keyword(), map(), module()) :: {:ok, non_neg_integer()}

@doc """
Inserts given item.
"""
@callback insert(term(), term()) :: term()
@callback insert(struct(), module()) :: {:ok, struct()} | {:error, term()}

@doc """
Updates given item.
"""
@callback update(term(), term()) :: term()
@callback update(struct(), module()) :: {:ok, struct()} | {:error, term()}

@doc """
Updates given items.
"""
@callback update_all(term(), term(), term()) :: term()
@callback update_all(list(struct()), keyword(), module()) :: {:ok, non_neg_integer()}

@doc """
Applies a change to a given item.
"""
@callback change(term(), term(), term(), term(), term(), term()) :: term()
@callback change(struct(), map(), term(), list(), module(), keyword()) :: Ecto.Changeset.t()

@doc """
Deletes multiple items.
"""
@callback delete_all(list(), term()) :: {:ok, term()} | {:error, term()}
@callback delete_all(list(struct()), module()) :: {:ok, term()} | {:error, term()}
end
Loading

0 comments on commit b89cb87

Please sign in to comment.