Skip to content

Commit

Permalink
init(ex/skate/snapshot_serde): create deserialize function (#2897)
Browse files Browse the repository at this point in the history
* init(ex/skate/snapshot_serde): create `deserialize` function

* refactor(ex/detours): refactor `update_or_create_detour_for_user` to use Serde module
  • Loading branch information
firestack authored Nov 7, 2024
1 parent 259fa4a commit d41b967
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 44 deletions.
39 changes: 18 additions & 21 deletions lib/skate/detours/detours.ex
Original file line number Diff line number Diff line change
Expand Up @@ -193,36 +193,33 @@ defmodule Skate.Detours.Detours do
end

@doc """
Update or create a detour given a user id & detour id.
Update or insert a detour given a user id and a XState Snapshot.
"""
def update_or_create_detour_for_user(user_id, uuid, attrs \\ %{}) do
user = User.get_by_id!(user_id)

previous_record = uuid != nil && Skate.Repo.get(Detour, uuid)

detour =
case uuid do
nil ->
create_detour_for_user(user_id, attrs)

_ ->
Repo.insert(
Detour.changeset(%Detour{author: user, id: uuid}, attrs),
returning: true,
conflict_target: [:id],
on_conflict: {:replace, [:state, :updated_at]}
)
def upsert_from_snapshot(author_id, %{} = snapshot) do
previous_record =
case Skate.Detours.SnapshotSerde.id_from_snapshot(snapshot) do
nil -> nil
id -> Skate.Repo.get(Detour, id)
end

case detour do
detour_db_result =
author_id
|> Skate.Detours.SnapshotSerde.deserialize(snapshot)
|> Skate.Repo.insert(
returning: true,
conflict_target: [:id],
on_conflict: {:replace, [:state, :updated_at]}
)

case detour_db_result do
{:ok, %Detour{} = new_record} ->
send_notification(new_record, previous_record, user_id)
send_notification(new_record, previous_record, author_id)

_ ->
nil
end

detour
detour_db_result
end

@doc """
Expand Down
24 changes: 24 additions & 0 deletions lib/skate/detours/snapshot_serde.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,28 @@ defmodule Skate.Detours.SnapshotSerde do
Deserializes XState JSON Snapshots to Ecto Database Changesets
Serializes Ecto Database Structs into XState JSON Snapshots
"""

@doc """
Converts a XState JSON Snapshot to Detours Database Changeset
"""
def deserialize(user_id, %{} = snapshot) do
Skate.Detours.Db.Detour.changeset(
%Skate.Detours.Db.Detour{
# `id` is `nil` by default, so a `nil` `id` should be fine
id: id_from_snapshot(snapshot),
author_id: user_id
},
%{
# Save Snapshot to DB until we've fully transitioned to serializing
# snapshots from DB data
state: snapshot
}
)
end

@doc """
Extracts the Detour ID from a XState Snapshot
"""
def id_from_snapshot(%{"context" => %{"uuid" => id}}), do: id
def id_from_snapshot(%{"context" => %{}}), do: nil
end
8 changes: 2 additions & 6 deletions lib/skate_web/controllers/detours_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,11 @@ defmodule SkateWeb.DetoursController do
alias Util.Location

@spec update_snapshot(Plug.Conn.t(), map()) :: Plug.Conn.t()
def update_snapshot(conn, %{"snapshot" => %{"context" => context} = snapshot}) do
uuid = Map.get(context, "uuid")

def update_snapshot(conn, %{"snapshot" => snapshot}) do
%{id: user_id} = AuthManager.Plug.current_resource(conn)

{:ok, %Skate.Detours.Db.Detour{id: returned_uuid}} =
Detours.update_or_create_detour_for_user(user_id, uuid, %{
state: snapshot
})
Detours.upsert_from_snapshot(user_id, snapshot)

json(conn, %{data: returned_uuid})
end
Expand Down
32 changes: 15 additions & 17 deletions test/skate_web/controllers/detours_controller_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -280,23 +280,21 @@ defmodule SkateWeb.DetoursControllerTest do
other_user = Skate.Settings.User.get_by_email("[email protected]")

# Manually insert a detour by another user
Detours.update_or_create_detour_for_user(other_user.id, 10, %{
state: %{
"context" => %{
"route" => %{
"name" => "23",
"directionNames" => %{
"0" => "Outbound",
"1" => "Inbound"
}
},
"routePattern" => %{
"headsign" => "Headsign",
"directionId" => 0
},
"nearestIntersection" => "Street A & Avenue B",
"uuid" => 10
}
Detours.upsert_from_snapshot(other_user.id, %{
"context" => %{
"route" => %{
"name" => "23",
"directionNames" => %{
"0" => "Outbound",
"1" => "Inbound"
}
},
"routePattern" => %{
"headsign" => "Headsign",
"directionId" => 0
},
"nearestIntersection" => "Street A & Avenue B",
"uuid" => 10
}
})

Expand Down

0 comments on commit d41b967

Please sign in to comment.