Questions about multi_decrement in Todo Trek Example

Hoping someone can help me understand one bit of code that appears in the To Do Trek example by @chrismccord

QUESTION 1:

The delete_todo function calls multi_decrement_positions as follows:

multi_decrement_positions(:dec_rest_in_list, todo, list_id: todo.list_id)

and the that function is defined as follows:

defp multi_decrement_positions(%Ecto.Multi{} = multi, name, %type{} = struct, where_query) do
    multi_update_all(multi, name, fn _ ->
      from(t in type,
        where: ^where_query,
        where:
          t.position > subquery(from og in type, where: og.id == ^struct.id, select: og.position),
        update: [inc: [position: -1]]
      )
    end)
  end

My question is with the subquery that is basically establishing the “old_position” of the todo that is being removed. I don’t understand why that subquery needs to be done. The “todo” that is being deleted is passed as a parameter and already knows its position. Couldn’t multi_decrement be defined as follows?

Note: The reason I’m asking is because I’m passing in a many-to-many struct that doesn’t have a primary key id so og.id == ^struct.id is going to fail. But it knows its position. And the ^where_query has already identified the subset of structs that make up “the list.”

defp multi_decrement_positions(%Ecto.Multi{} = multi, name, %type{} = struct, where_query) do
    multi_update_all(multi, name, fn _ ->
      from(t in type,
        where: ^where_query,
        where:
          t.position > struct.position,
        update: [inc: [position: -1]]
      )
    end)
  end

QUESTION 2:
Totally stupid question. What does the ‘og’ in the subquery stand for? That acronym is driving me crazy. It’s like a personalized license plate that I can’t figure out. :smiley:

QUESTION 3:
I’m studying this To Do example because it shows sortable lists that are also streamable. Items can be repositioned.

When a user has repositioned an item in a stream that has multiple items already displayed, does it make sense to try to update the stream (versus regenerating it)? Updating it would require identifying all the items in the stream that need to be deleted and then inserting the items with the new positions in the correct place. It seems like it is better to just regenerate the stream after an item has been moved (since there is a domino effect on the entire stream). Or is there a reason why it’s better to make changes on the stream versus regenerating in this case?

  1. To avoid the race of the potentially stale position (the position could have changed since you last read it)
  2. original
  3. refetching simplifies a lot of cases, but in this case you can stream insert at the new position since the position is the proper index in the list, so you don’t need to refetch
1 Like

Thank you @chrismccord!

One last question about number 1. In a situation where a “List” is only touched by one user (not a team), do race conditions still need to be considered?

Some users love to double-click. On EVERYTHING

That can easily cause a race between multiple requests, and will break things when you least expect it.

1 Like

ohhhhh. I see some code clean up in my future.

Thank you @al2o3cr!