Run this notebook

Use Livebook to open this notebook and explore new ideas.

It is easy to get started, on your machine or the cloud.

Click below to open and run it in your Livebook at .

(or change your Livebook location)

# CURD Rice 🍚 :: for ricing CRUD ## Sheaf 🌾 Manipulation ```elixir defmodule R do def recompile() do Mix.Task.reenable("app.start") Mix.Task.reenable("compile") Mix.Task.reenable("compile.all") compilers = Mix.compilers() Enum.each(compilers, &Mix.Task.reenable("compile.#{&1}")) Mix.Task.run("compile.all") end end R.recompile() ``` <!-- livebook:{"branch_parent_index":0} --> ## CRUD Helper -- set up a family of sheafs for discussions UI ```elixir R.recompile() alias Vyasa.Sangh alias Vyasa.Sangh.Sheaf ``` ### CRUD Helper Module This has a purge function and a seed function. Intent is to use this during the UI creation phase for discussions. ```elixir R.recompile() defmodule CRUDHelper do alias Vyasa.Sangh alias Vyasa.Sangh.Sheaf alias EctoLtree @roots [ {"Hey there, this is the start of a discussion about how to set up the discussions UI", "freebird"}, {"Hello folks, let's talk about why fruits are absolutely the best thing on earth.", "fruitfinder"}, {"I like cars, what about y'all?", "carboi"} ] @second_layer [ {"What do you think about the future of discussions?", "discussion_enthusiast"}, {"Fruits are not just tasty; they're also healthy!", "health_freak"}, {"Cars have changed so much over the years, haven't they?", "car_historian"}, {"How do you feel about online discussions?", "digital_native"}, {"What's your favorite fruit and why?", "fruit_lover"}, {"What car model do you dream of owning?", "car_dreamer"}, {"What features do you think discussions should have?", "feature_fanatic"}, {"Do you prefer sweet or savory fruits?", "taste_explorer"}, {"What was your first car experience like?", "first_driver"} ] @third_layer [ # For first root's children [ {"I think discussions should be more interactive.", "interactivity_lover"}, {"Have you tried any new discussion platforms?", "platform_explorer"}, {"What would improve online discussions for you?", "improvement_seeker"} ], # For second root's children [ {"I love fruits that are both sweet and tangy!", "sweet_tangy_lover"}, {"Have you ever tried exotic fruits?", "exotic_fruit_explorer"}, {"What's your go-to fruit for a snack?", "snack_time_fruit"} ], # For third root's children [ {"Electric cars are the future!", "electric_car_enthusiast"}, {"What's your opinion on self-driving cars?", "self_driving_advocate"}, {"Car maintenance tips anyone?", "maintenance_master"} ] ] @doc """ Seeds a family of sheafs. With 3 roots, 3 children per root and 3 children per 2nd level root. """ def seed_family(sangh_session_id) do # Create root sheafs created_root_sheafs = @roots |> Enum.map(fn {body, user_signature} -> payload = %{ id: Ecto.UUID.generate(), active: false, body: body, marks: [], traits: ["published"], session_id: sangh_session_id, signature: user_signature, # Each root has 3 children child_count: length(@second_layer) } case Sangh.create_sheaf(payload) do {:ok, sheaf} -> sheaf {:error, reason} -> IO.puts("Error creating root sheaf: #{reason}") end end) # Create second layer sheafs created_second_layer_sheafs = created_root_sheafs |> Enum.flat_map(fn root -> Enum.map(@second_layer, fn {body, user_signature} -> payload = %{ id: Ecto.UUID.generate(), active: false, body: body, marks: [], traits: ["published"], session_id: sangh_session_id, signature: user_signature, # Each second layer has 3 children child_count: length(@third_layer) } case Sangh.create_child_sheaf_from_parent(root, payload) do {:ok, child_sheaf} -> child_sheaf {:error, reason} -> IO.puts("Error creating second layer sheaf: #{reason}") end end) end) # Create third layer sheafs _created_third_layer_sheafs = created_second_layer_sheafs |> Enum.flat_map(fn child -> Enum.flat_map(@third_layer, fn layer -> Enum.map(layer, fn {body, user_signature} -> payload = %{ id: Ecto.UUID.generate(), active: false, body: body, marks: [], traits: ["published"], session_id: sangh_session_id, signature: user_signature, # Third layer has no children child_count: 0 } case Sangh.create_child_sheaf_from_parent(child, payload) do {:ok, grandchild_sheaf} -> grandchild_sheaf {:error, reason} -> IO.puts("Error creating third layer sheaf: #{reason}") end end) end) end) # insert test map to one of the roots: updated_root_sheaf_with_mark = hd(created_root_sheafs) |> Sangh.update_sheaf(%{marks: [Stubs.Vyasa.Sangh.Mark.get_dummy_mark()]}) IO.inspect(updated_root_sheaf_with_mark, label: "CHECK ME OUT") end @doc """ Indiscriminately purges all the sheafs in the session. Deletes child sheafs before deleting their parents to avoid foreign key constraint errors. Handles stale entries gracefully. """ def purge(sangh_session_id) do # Retrieve all root sheafs for the session root_sheafs = Sangh.get_root_sheafs_by_session(sangh_session_id) |> Vyasa.Repo.preload(:marks) # _deleted_marks = root_sheafs |> Enum.map(fn s -> s |> Sangh.delete_marks_in_sheaf() end) _second_level_deletes = root_sheafs |> Enum.map(fn root -> Sangh.get_child_sheafs_by_session(sangh_session_id, Sheaf.encode_path(root.id), 2) end) |> Enum.map(fn sheafs -> sheafs |> Enum.map(fn s -> Sangh.delete_sheaf(s) end) end) _first_level_deletes = root_sheafs |> Enum.map(fn root -> Sangh.get_child_sheafs_by_session(sangh_session_id, Sheaf.encode_path(root.id), 1) end) |> Enum.map(fn sheafs -> sheafs |> Enum.map(fn s -> Sangh.delete_sheaf(s) end) end) _root_level_deletes = root_sheafs |> Enum.map(fn root -> Sangh.get_child_sheafs_by_session(sangh_session_id, Sheaf.encode_path(root.id), 0) end) |> Enum.map(fn sheafs -> sheafs |> Enum.map(fn s -> Sangh.delete_sheaf(s) end) end) end end ``` ### Creating the Family Tree This is for some basic setup while creating the discussion view. ```elixir # set based on current session: sangh_session_id = "164eb05d-221a-4939-b180-8394e1a5515f" sangh_session_id = "907c4d5e-77a1-4c51-96d1-185b8f314fde" sangh_session_id = "907c4d5e-77a1-4c51-96d1-185b8f314fde" CRUDHelper.purge(sangh_session_id) CRUDHelper.seed_family(sangh_session_id) ``` #### Verifying the Family Fixture ```elixir root = hd(Sangh.get_root_sheafs_by_session(sangh_session_id)) Sangh.get_child_sheafs_by_session(sangh_session_id, Sheaf.encode_path(root.id), 2) |>Enum.count() %{data: root_sheafs} = Sangh.get_root_sheafs_by_session(sangh_session_id, 1) root_sheafs ``` ## Sheaf Lattice Definition So this is how we define a flatmap (which we call :kv_verses), so our intent is to use a similar pattern for keeping state in the discussions mode ```elixir alias Vyasa.Sangh alias Vyasa.Sangh.Sheaf alias Vyasa.Written.{Source} alias Vyasa.Written default_lang = "en" source_title = "hanuman_chalisa" chap_no = 1 %Source{id: sid} = source = Written.get_source_by_title(source_title) chaps = Written.list_chapters_by_source(sid, default_lang) %{verses: verses, translations: [ts | _], title: chap_title, body: chap_body} = chap = Written.get_chapter(chap_no, sid, default_lang) Enum.into(verses, %{}, &{&1.id, &1}) # Written.get_chapter(1, sid, @default_lang) ``` #### Defining Lattices for Discussion Context So we will be keeping a flatmap for state. First about the sheaf states themselves. These will be streams of their own: A) sheafs stream: [ sheaf path label slugs ] => %Sheaf{} B) sheaf_ui stream [ sheaf id ] => sheaf ui state * this will have mark's info for them also ==> for now we shall also load all the marks per sheaf now for ui state: the Marks UI state looks like this: %VyasaWeb.Context.Components.UiState.Marks{ is_expanded_view?: false, show_sheaf_modal?: false, is_editable_marks?: false, mark_id_to_ui: %{} } for sheaf ui do a composition: so sheaf ui state likely can just contain the marks ui state extra info: pagination info needs to be in the ui state <!-- livebook:{"break_markdown":true} --> ###### Sheaf Lattice Definition ```elixir alias Vyasa.Sangh.SheafLattice sangh_session_id = "164eb05d-221a-4939-b180-8394e1a5515f" R.recompile() alias Vyasa.Sangh alias Vyasa.Sangh.Sheaf alias Vyasa.Written.{Source} alias Vyasa.Written # this is the function exposed for it: sheaf_lattice = SheafLattice.create_complete_sheaf_lattice(sangh_session_id) # here's the manual way of doing it # %{data: root_sheafs} = Sangh.get_root_sheafs_by_session(sangh_session_id, 1) # levels = [0, 1, 2] # sheaf_lattice = # levels # |> Enum.flat_map(fn level -> # root_sheafs # |> Enum.map(fn sheaf -> to_string(sheaf.path) end) # |> Enum.flat_map(fn sheaf_id -> # Sangh.get_child_sheafs_by_session(sangh_session_id, sheaf_id, level) # end) # |> Enum.map(fn s -> {s.path.labels, s} end) # end) # |> Enum.into(%{}) ``` ##### Reading a sheaf lattice Here, I've put in examples of using the helper functions for reading sheafs. Test this out by setting test_input correctly to the label of a valid leaf-sheaf, this may change based on the seed function. ```elixir alias Vyasa.Sangh.SheafLattice example_leaf_sheaf = hd(SheafLattice.read_sheaf_lattice(sheaf_lattice, 2, nil)) test_input = [a, b, c] = example_leaf_sheaf.path.labels # OR manually set test input in this block: # test_input = ["8955df0c", "2628a71a", "f9ce1eee"] ``` ```elixir # fetch all sheafs in a particular level SheafLattice.read_sheaf_lattice(sheaf_lattice) # should return an empty array since it's beyond the max-3 depth SheafLattice.read_sheaf_lattice(sheaf_lattice, 3, nil) SheafLattice.read_sheaf_lattice(sheaf_lattice, 0, nil) SheafLattice.read_sheaf_lattice(sheaf_lattice, 1, nil) SheafLattice.read_sheaf_lattice(sheaf_lattice, 2, nil) # ["8955df0c", "2628a71a", "f9ce1eee"], # # # # fetch based on specific matches of a single label SheafLattice.read_sheaf_lattice(sheaf_lattice, 0, a) SheafLattice.read_sheaf_lattice(sheaf_lattice, 1, b) SheafLattice.read_sheaf_lattice(sheaf_lattice, 2, c) # # # # # fetch based on complete matches: SheafLattice.read_sheaf_lattice(sheaf_lattice, 1, [a, b]) SheafLattice.read_sheaf_lattice(sheaf_lattice, 2, [a, b, c]) # # # # # fetch immediate children based on particular parent # # # # # fetch immediate children of a specific level 0 node: SheafLattice.read_sheaf_lattice(sheaf_lattice, 1, [a, nil]) # # # # # fetch immediate children of a specific level 1 node: SheafLattice.read_sheaf_lattice(sheaf_lattice, 2, [a, b, nil]) SheafLattice.read_sheaf_lattice(sheaf_lattice, 1, ["1bebc4d1", nil]) |> Enum.map(fn s -> s.path.labels end) # |> Enum.count() ``` #### Sheaf UI States Intent here is to keep ui state auxilliary to the actual data state. The shape of the data and ui lattices shall be exactly the same, so that the same read_sheaf_lattice() can be used on both ui and data state lattices. ```elixir R.recompile() # getting info about the sheaf's marks and stuff: [ test_root_sheaf | _]= SheafLattice.read_sheaf_lattice(sheaf_lattice, 0, nil) |> Enum.map(fn s -> s |> Vyasa.Repo.preload(:marks) end) |> Enum.map(fn %{marks: [_|_] = _m} = s -> s %{marks: [] = _m} -> nil end) |> Enum.reject(fn s -> is_nil(s) end) alias VyasaWeb.Context.Components.UiState.Sheaf, as: SheafUiState SheafUiState.get_initial_ui_state(test_root_sheaf) # sheaf_lattice # |> Enum.map(fn {k, } end) sheaf_ui_lattice = sheaf_lattice |> Enum.map(fn {k, %Sheaf{ marks: _marks } = sheaf} -> sheaf_ui = sheaf |> SheafUiState.get_initial_ui_state() {k, sheaf_ui} end) |> Enum.into(%{}) sheaf_lattice |> SheafLattice.read_sheaf_lattice(2, "08e53d81") sheaf_ui_lattice |> SheafLattice.read_sheaf_lattice(2, "08e53d81") test_root_sheaf |> SheafUiState.get_initial_ui_state() # SheafUi ``` <!-- livebook:{"branch_parent_index":0} --> ## Creation Related Test Section ```elixir {:ok, %{id: s_id}} = Vyasa.Sangh.create_session() ``` ```elixir {:ok, sangh} = Vyasa.Sangh.create_sheaf(%{id: Ecto.UUID.generate(), session_id: s_id}) ``` ```elixir {:ok, child_sangh} = Vyasa.Sangh.create_sheaf(%{id: Ecto.UUID.generate(), parent: sangh, session_id: s_id}) {:ok, grandchild_sangh} = Vyasa.Sangh.create_sheaf(%{id: Ecto.UUID.generate(), parent: child_sangh, session_id: s_id}) ``` ```elixir # sheaf_lattice = Vyasa.Sangh.get_child_sheafs_by_session("a33b4f92-90de-45a0-88b0-c19518491182", "085994cc", 2) # |> Enum.map(fn sheaf -> # {sheaf.path.labels, sheaf} # end) # |> Enum.into(%{}) # # length(sangh.path.labels) sheaf_lattice |> Enum.map(fn {["085994cc" | [ "01a1bb12" | _]] = k , sheaf} -> sheaf _ -> nil end) # |> Enum.into(%{}) ```
See source

Have you already installed Livebook?

If you already installed Livebook, you can configure the default Livebook location where you want to open notebooks.
Livebook up Checking status We can't reach this Livebook (but we saved your preference anyway)
Run notebook

Not yet? Install Livebook in just a minute

Livebook is open source, free, and ready to run anywhere.

Run in the cloud

on select platforms

To run on Linux, Docker, embedded devices, or Elixir’s Mix, check our README.

PLATINUM SPONSORS
SPONSORS
Code navigation with go to definition of modules and functions Read More