diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 8797207..5ceb7b6 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -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) diff --git a/src/mvp/17-list_items.md b/src/mvp/17-list_items.md index 3c8cdce..5281da2 100644 --- a/src/mvp/17-list_items.md +++ b/src/mvp/17-list_items.md @@ -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 -``` \ No newline at end of file +looks like a good starting point. 💭 \ No newline at end of file diff --git a/src/mvp/19-add-item-to-list.md b/src/mvp/19-add-item-to-list.md new file mode 100644 index 0000000..386af81 --- /dev/null +++ b/src/mvp/19-add-item-to-list.md @@ -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. ⭐