- Add contacts_inserted_at_desc_id_desc_idx so /contacts list runs as an Index Scan (~0.4ms) instead of a Seq Scan + top-N heapsort (~77ms on 58k rows) - Add Microwaveprop.Cache: tiny ETS-backed TTL cache for memoizing expensive-but-stale-tolerant values - Cache total_entries for unsearched /contacts page loads (30s TTL, invalidated on insert) - Cache the entire /contacts/map payload (pre-encoded JSON + band list), moving load_contacts into Radio.contact_map_payload; invalidated on new contact insert. Mount goes from ~150-300ms to ~5ms. - Fix /map overlay blinking on load: reuse the Leaflet GridLayer across renderScores calls and just redraw() against the updated ScoreGrid, instead of removeLayer + new layer which flashed between tile regens - Make mode optional on submission: schema change (null: true), submission_changeset no longer requires it, blank strings normalise to nil, CSV import accepts 6-column (no mode) or 7-column layouts - core_components .input adds a red asterisk to labels when required, giving users a visual cue for which fields must be filled on /submit
46 lines
1.5 KiB
Elixir
46 lines
1.5 KiB
Elixir
defmodule Microwaveprop.CacheTest do
|
|
use ExUnit.Case, async: false
|
|
|
|
alias Microwaveprop.Cache
|
|
|
|
setup do
|
|
Cache.clear()
|
|
:ok
|
|
end
|
|
|
|
describe "fetch_or_store/3" do
|
|
test "invokes the function and returns the value on a cold cache" do
|
|
assert Cache.fetch_or_store(:the_key, 1_000, fn -> 42 end) == 42
|
|
end
|
|
|
|
test "returns the cached value without invoking the function on a warm hit" do
|
|
Cache.fetch_or_store(:the_key, 1_000, fn -> 42 end)
|
|
assert Cache.fetch_or_store(:the_key, 1_000, fn -> raise "should not run" end) == 42
|
|
end
|
|
|
|
test "re-invokes the function once the TTL expires" do
|
|
Cache.put(:the_key, 1, -1)
|
|
assert Cache.fetch_or_store(:the_key, 1_000, fn -> 2 end) == 2
|
|
end
|
|
|
|
test "isolates values by key" do
|
|
assert Cache.fetch_or_store(:a, 1_000, fn -> 1 end) == 1
|
|
assert Cache.fetch_or_store(:b, 1_000, fn -> 2 end) == 2
|
|
assert Cache.fetch_or_store(:a, 1_000, fn -> raise "no" end) == 1
|
|
assert Cache.fetch_or_store(:b, 1_000, fn -> raise "no" end) == 2
|
|
end
|
|
end
|
|
|
|
describe "put/3 and invalidate/1" do
|
|
test "put/3 stores a value with the given TTL" do
|
|
Cache.put(:k, "hello", 1_000)
|
|
assert Cache.fetch_or_store(:k, 1_000, fn -> "other" end) == "hello"
|
|
end
|
|
|
|
test "invalidate/1 removes an entry, forcing the next fetch to recompute" do
|
|
Cache.put(:k, "stale", 60_000)
|
|
Cache.invalidate(:k)
|
|
assert Cache.fetch_or_store(:k, 1_000, fn -> "fresh" end) == "fresh"
|
|
end
|
|
end
|
|
end
|