Cache parsed GPX/FIT GeoJSON to fix large POI-export loads
CI / check (push) Successful in 42s
CI / deploy (push) Successful in 14s

A several-thousand-waypoint park4night area export re-parses the
whole file with REXML on every toggle — ~2.4s for a 5k-waypoint/3.6MB
sample, so tens of seconds for a 50k-waypoint one, likely the actual
cause behind a "Could not load" report on a 41.5MB export. MapLibre
already clusters the waypoint layer client-side, so the bottleneck was
never rendering — cache the GeoJSON conversion alongside the source
file (invalidated by mtime) instead of a bigger bbox/tiling rework.
This commit is contained in:
randy committed 2026-09-07 22:21:00 +02:00
1 parent b6a9c1546e
commit ddf2ee4990
4 files changed
+94 -9

No files matched your search

+55
View File
@@ -67,4 +67,59 @@ class GpxStoreTest < Minitest::Test
assert_equal "archive/ride-1.gpx", new_path
assert_empty @store.tree["children"].reject { |c| c["name"] == "archive" }
end
def test_geojson_is_cached_alongside_the_source_file
path = @store.save(folder: "", filename: "ride.gpx", io: StringIO.new(sample_gpx))
cache_path = @store.resolve_file(path) + ".geojson"
refute File.file?(cache_path)
first = @store.geojson(path)
assert File.file?(cache_path)
# Corrupt the cache directly to prove the second call reused it instead
# of re-parsing the (still-valid) source file.
File.write(cache_path, first.sub("waypoint", "cached-waypoint"))
assert_includes @store.geojson(path), "cached-waypoint"
end
def test_geojson_cache_is_invalidated_when_the_file_is_resaved
path = @store.save(folder: "", filename: "ride.gpx", io: StringIO.new(sample_gpx))
@store.geojson(path)
File.write(@store.resolve_file(path), sample_gpx.sub("Waypoint", "Renamed"))
FileUtils.touch(@store.resolve_file(path), mtime: Time.now + 1)
assert_includes @store.geojson(path), "Renamed"
end
def test_delete_file_removes_the_geojson_cache_too
path = @store.save(folder: "", filename: "ride.gpx", io: StringIO.new(sample_gpx))
@store.geojson(path)
cache_path = @store.resolve_file(path) + ".geojson"
@store.delete_file(path)
refute File.file?(cache_path)
end
def test_move_relocates_the_geojson_cache_too
path = @store.save(folder: "", filename: "ride.gpx", io: StringIO.new(sample_gpx))
@store.geojson(path)
new_path = @store.move(from: path, to_folder: "archive")
assert File.file?(@store.resolve_file(new_path) + ".geojson")
end
def test_geojson_raises_enoent_for_a_missing_file
assert_raises(Errno::ENOENT) { @store.geojson("nope.gpx") }
end
private
def sample_gpx
<<~GPX
<gpx><wpt lat="48.1" lon="17.1"><name>Waypoint</name></wpt></gpx>
GPX
end
end