Skip to content

Commit

Permalink
document remove_item_from_list/3 function for dwyl/mvp#422 ref dwyl/m…
Browse files Browse the repository at this point in the history
  • Loading branch information
nelsonic committed Sep 14, 2023
1 parent 600af36 commit 0bf93a0
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 74 deletions.
1 change: 1 addition & 0 deletions src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@
- [Cids](mvp/15-item-cid.md)
- [Lists](mvp/16-lists.md)
- [Reordering](mvp/18-reordering.md)
- [Add `item` to `list`](src/mvp/19-add-item-to-list.md)
- [Stats](mvp/20-stats.md)
75 changes: 1 addition & 74 deletions src/mvp/17-list_items.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,77 +181,4 @@ We wrote this using `SQL` because it's easier to debug.
If `Ecto` had a `Repo.last` function, I would use that instead.
If you want to help with refactoring this,
[stackoverflow.com/questions/32653391/select-latest-entry-ecto-phoenix](https://stackoverflow.com/questions/32653391/how-to-select-the-latest-entry-from-database-with-ecto-phoenix)
looks like a good starting point. 💭






## Add _Existing_ `itmes` to the "All" `list`

One final function we need
in order to _retroactively_ add `lists`
to our `MVP` App that started out _without_ `lists`
is a function to add all the _existing_ `items`
to the newly created "All" `list`.

### Test `add_items_to_all_list/1`

> **Note**: This is a _temporary_ function that we will `delete`
once all the _existing_ people using the `MVP`
have transitioned their `items` to the "All" `list`.
But we still need to have a _test_ for it!

Open
`test/app/list_items_test.exs`
and add the following test:

```elixir
test "add_items_to_all_list/1 to seed the All list" do
person_id = 0
all_list = App.List.get_list_by_text!(person_id, "All")
count_before = App.ListItem.next_position_on_list(all_list.id)
assert count_before == 1

item_ids = App.ListItem.get_items_on_all_list(person_id)
assert length(item_ids) == 0

App.ListItem.add_items_to_all_list(person_id)
updated_item_ids = App.ListItem.get_items_on_all_list(person_id)
assert length(updated_item_ids) ==
length(App.Item.all_items_for_person(person_id))

count_after = App.ListItem.next_position_on_list(all_list.id)
assert count_before + length(updated_item_ids) == count_after
end
```

That's a very long test.
Take a moment to read it through.
Remember: this will be deleted,
it's just data migration code.


### Define `add_items_to_all_list/1`

In the
`lib/app/list_item.ex`
file,
add the `add_items_to_all_list/1` function definition:

```elixir
def add_items_to_all_list(person_id) do
all_list = App.List.get_list_by_text!(person_id, "All")
all_items = App.Item.all_items_for_person(person_id)
item_ids_in_all_list = get_items_on_all_list(person_id)

all_items
|> Enum.with_index()
|> Enum.each(fn {item, index} ->
unless Enum.member?(item_ids_in_all_list, item.id) do
add_list_item(item, all_list, person_id, (index + 1) / 1)
end
end)
end
```
looks like a good starting point. 💭
119 changes: 119 additions & 0 deletions src/mvp/19-add-item-to-list.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# Make `Lists` _Useful_

To make our `lists` feature _useful_
we need to be able to:
1. _Create_ new **custom `lists`**.
2. _Add_ an `item` to the `list`.
3. _Remove_ an `item` from a `list`.

## Create _new_ `list`

> **TODO**: Document the functions
> and interface implemented in:
> https://github.com/dwyl/mvp/pull/165

## Add `item` to `list`



We _first_

## _Remove_ `item` from `list`

_Most_ of the time `people` _don't_ want
an `item` to be on multiple `lists`.
So we need a function to _remove_ an `item` from a `list`
when it gets moved to a different `list`.
Thankfully it's pretty straightforward.

### Test `remove_item_from_list/3`

Open the `test/app/list_test.exs` file
and add the following test:

```elixir
test "remove_item_from_list/3 removes the item.cid from the list.seq" do
# Random Person ID
person_id = 386
all_list = App.List.get_all_list_for_person(person_id)

# Create items:
assert {:ok, %{model: item1}} =
Item.create_item(%{text: "buy land!", person_id: person_id, status: 2})
assert {:ok, %{model: item2}} =
Item.create_item(%{text: "prepare for societal collapse", person_id: person_id, status: 2})

# Add both items to the list:
seq = "#{item1.cid},#{item2.cid}"
{:ok, %{model: list}} = App.List.update_list_seq(all_list.cid, person_id, seq)
assert list.seq == seq

# Remove the first item from the list:
{:ok, %{model: list}} = App.List.remove_item_from_list(item1.cid, all_list.cid, person_id)

# Only item2 should be on the list.seq:
updated_seq = "#{item2.cid}"
# Confirm removed:
assert list.seq == updated_seq
end
```

Running this test (before implementing the function)
will result in the following error:

```sh
mix test test/app/list_test.exs
```

E.g:

```elixir
warning: App.List.remove_item_from_list/2 is undefined or private
test/app/list_test.exs:141: App.ListTest."test remove_item_from_list/3 removes the item.cid from the list.seq"/1



1) test remove_item_from_list/3 removes the item.cid from the list.seq (App.ListTest)
test/app/list_test.exs:124
** (UndefinedFunctionError) function App.List.remove_item_from_list/2 is undefined or private
code: {:ok, %{model: list}} = App.List.remove_item_from_list(item1.cid, all_list.cid)
stacktrace:
(app 1.0.0) App.List.remove_item_from_list("zb2rhdaNQbkwwfEB9z65yRAtzmZvZmC5A3ei6tSkzySXaiKfi", "zb2rhid7hk43h1P24u7x88dAesrCVmh4uR53mUscxDAemyDaQ")
test/app/list_test.exs:141: (test)


Finished in 0.1 seconds (0.1s async, 0.00s sync)
11 tests, 1 failure
```

Thankfully this is easy to resolve.


### Implement `remove_item_from_list/3` function

Open the
`lib/app/list.ex`
file
and add the following function defition:

```elixir
def remove_item_from_list(item_cid, list_cid, person_id) do
list = get_list_by_cid!(list_cid)
# get existing list.seq
seq =
get_list_seq(list)
# remove the item_cid from the list.seq:
|> Useful.remove_item_from_list(item_cid)
|> Enum.join(",")

update_list(list, %{seq: seq, person_id: person_id})
end
```

This uses the super simple function:
[`Useful.remove_item_from_list/2`](https://hexdocs.pm/useful/1.13.1/Useful.html#remove_item_from_list/2)
which we published
in our library of
[`Useful`](https://github.com/dwyl/useful)
functions. ⭐

0 comments on commit 0bf93a0

Please sign in to comment.