mirror of
https://github.com/zvx-echo6/navi.git
synced 2026-08-26 17:31:37 +00:00
Merge pull request #15 from zvx-echo6/feat/exists-guard
perf(offroute): EXISTS guard replaces COUNT(*) on entry_points hot path
This commit is contained in:
commit
23ed09afdf
2 changed files with 61 additions and 3 deletions
|
|
@ -197,6 +197,17 @@ class EntryPointIndex:
|
|||
cur.execute("SELECT COUNT(*) FROM entry_points")
|
||||
return cur.fetchone()[0]
|
||||
|
||||
def has_entry_points(self) -> bool:
|
||||
"""Fast non-emptiness check. SELECT EXISTS short-circuits at the first row,
|
||||
unlike SELECT COUNT(*) which scans the entire table (~73s on 2.94M rows).
|
||||
Returns False if the table is absent."""
|
||||
if not self.table_exists():
|
||||
return False
|
||||
conn = self._get_conn()
|
||||
with conn.cursor() as cur:
|
||||
cur.execute("SELECT EXISTS (SELECT 1 FROM entry_points LIMIT 1)")
|
||||
return cur.fetchone()[0]
|
||||
|
||||
def query_bbox(
|
||||
self,
|
||||
south: float,
|
||||
|
|
@ -905,7 +916,7 @@ class OffrouteRouter:
|
|||
t0 = time.time()
|
||||
|
||||
# Ensure entry point index exists
|
||||
if not self.entry_index.table_exists() or self.entry_index.get_entry_point_count() == 0:
|
||||
if not self.entry_index.has_entry_points():
|
||||
return {
|
||||
"status": "error",
|
||||
"message": "Trail entry point index not built. Run build_entry_index() first."
|
||||
|
|
@ -986,7 +997,7 @@ class OffrouteRouter:
|
|||
"""
|
||||
t0 = time.time()
|
||||
|
||||
if not self.entry_index.table_exists() or self.entry_index.get_entry_point_count() == 0:
|
||||
if not self.entry_index.has_entry_points():
|
||||
return {
|
||||
"status": "error",
|
||||
"message": "Trail entry point index not built. Run build_entry_index() first."
|
||||
|
|
@ -1066,7 +1077,7 @@ class OffrouteRouter:
|
|||
"""
|
||||
t0 = time.time()
|
||||
|
||||
if not self.entry_index.table_exists() or self.entry_index.get_entry_point_count() == 0:
|
||||
if not self.entry_index.has_entry_points():
|
||||
return {
|
||||
"status": "error",
|
||||
"message": "Trail entry point index not built. Run build_entry_index() first."
|
||||
|
|
|
|||
|
|
@ -465,3 +465,50 @@ def test_spatial_no_class_no_use_picks_foot(monkeypatch):
|
|||
r = object.__new__(OffrouteRouter)
|
||||
modes = r._spatial_eligible_modes(43.6, -116.2, {})
|
||||
assert modes == frozenset({"foot"})
|
||||
|
||||
|
||||
# ── EntryPointIndex.has_entry_points — EXISTS guard (replaces COUNT(*)) ────
|
||||
# Bare index (no __init__/DB); table_exists + _get_conn monkeypatched.
|
||||
|
||||
from services.navi_offroute.router import EntryPointIndex
|
||||
|
||||
|
||||
class _FakeCur:
|
||||
def __init__(self, row):
|
||||
self._row = row
|
||||
def __enter__(self):
|
||||
return self
|
||||
def __exit__(self, *a):
|
||||
return False
|
||||
def execute(self, q, *a):
|
||||
self.q = q
|
||||
def fetchone(self):
|
||||
return self._row
|
||||
|
||||
|
||||
class _FakeConn:
|
||||
def __init__(self, row):
|
||||
self._row = row
|
||||
def cursor(self):
|
||||
return _FakeCur(self._row)
|
||||
|
||||
|
||||
def _bare_index(monkeypatch, table_exists, row=None):
|
||||
monkeypatch.setattr(EntryPointIndex, "table_exists", lambda self: table_exists)
|
||||
monkeypatch.setattr(EntryPointIndex, "_get_conn", lambda self: _FakeConn(row))
|
||||
return object.__new__(EntryPointIndex)
|
||||
|
||||
|
||||
def test_has_entry_points_table_missing(monkeypatch):
|
||||
idx = _bare_index(monkeypatch, table_exists=False)
|
||||
assert idx.has_entry_points() is False
|
||||
|
||||
|
||||
def test_has_entry_points_empty(monkeypatch):
|
||||
idx = _bare_index(monkeypatch, table_exists=True, row=(False,))
|
||||
assert idx.has_entry_points() is False
|
||||
|
||||
|
||||
def test_has_entry_points_rows(monkeypatch):
|
||||
idx = _bare_index(monkeypatch, table_exists=True, row=(True,))
|
||||
assert idx.has_entry_points() is True
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue