…and here’s what it would look like if everything were implicit, like ecto:
defmodule Scheduling do
@total_seats_available 100
def signup(attends, course, student, class) do
Repo.transact(fn ->
rec = Subspace.pack(attends, {student, class})
case Repo.get(rec) do
nil ->
# Not signed up yet, proceed with signup
class_key = Subspace.pack(course, class)
seats_data = Repo.get(class_key)
seats_left = Key.unpack(seats_data)
if seats_left == 0 do
{:error, "No remaining seats"}
else
# Decrement seats and record signup
Repo.put(class_key, Key.pack(seats_left - 1))
Repo.put(rec, <<>>)
end
_existing ->
# Already signed up
:ok
end
end)
end
def drop(attends, course, student, class) do
Repo.transact(fn ->
rec = Subspace.pack(attends, {student, class})
case Repo.get(rec) do
nil ->
# Not taking this class
:ok
_existing ->
# Increment seats and remove signup
class_key = Subspace.pack(course, class)
seats_data = Repo.get(class_key)
seats_left = Key.unpack(seats_data)
Repo.put(class_key, Key.pack(seats_left + 1))
Repo.clear(rec)
end
end)
end
def available_classes(course) do
course_range = Subspace.range(course)
Repo.transact(fn ->
classes = Repo.get_range(course_range)
|> Stream.map(fn {packed_class, packed_seats} ->
class = Subspace.unpack(course, packed_class)
availability = Key.unpack(packed_seats)
{class, availability}
end)
|> Stream.filter(fn {_class, availability} -> availability > 0 end)
|> Stream.map(fn {class, _availability} -> class end)
|> Enum.to_list()
{:ok, classes}
end)
end
def init(scheduling, course, class_names) do
scheduling_range = scheduling |> Directory.get_subspace() |> Subspace.range()
Repo.transact(fn ->
# Clear the directory
Repo.clear_range(scheduling_range)
# Add all classes
for class_name <- class_names do
add_class(course, class_name)
end
:ok
end)
end
def add_class(course, class) do
Repo.transact(fn ->
key = Subspace.pack(course, class)
value = Key.pack(@total_seats_available)
Repo.put(key, value)
end)
end
end
…and…
def switch(attends, course, student, old_class, new_class) do
Repo.transact(fn ->
with :ok <- signup(attends, course, student, new_class),
:ok <- drop(attends, course, student, old_class) do
{:ok, :switched}
end
end)
end
…other than the Key.pack for values naming pinchpoint that @jstimps called out, that’s all of of the feedback integrated. If any of the implicit functions are used outside of a transact, they’ll raise.






















