Skip to content

Support range and null queries in the API - #7154

Open
roed-math wants to merge 4 commits into
LMFDB:mainfrom
roed-math:ai/t16-api-ranges-null
Open

Support range and null queries in the API#7154
roed-math wants to merge 4 commits into
LMFDB:mainfrom
roed-math:ai/t16-api-ranges-null

Conversation

@roed-math

Copy link
Copy Markdown
Contributor

Closes #5066.
Closes #6693.

The API query parser now accepts an inclusive range syntax under the numeric type-prefixes: conductor=i11..100 translates to {"$gte": 11, "$lte": 100}, and either endpoint may be omitted (i389.., f..2.5). Ranges are only activated under the i/f prefixes, so bare and s-prefixed values containing .. are untouched. The unprefixed value None now matches rows where the column is null (e.g. gps_gl2zhat_fine?q_gonality=None, which used to produce a SQL type error).

Two forms of value are reserved by this, and each keeps an escape. A value beginning with i or f and containing .. is now read as a numeric range, where before it fell through to the literal string (meaningful only on a text column); it remains searchable as a literal by prefixing it with s, as in si11..100. Bare None is reserved for SQL null in the same way, with sNone for the literal string "None". Both escapes are documented on the API index page next to the new syntax.

Also fixes two pre-existing bugs in the same parser block:

  • cf (contains-float) built {"contains": ...} instead of {"$contains": ...}, and therefore generated invalid SQL;
  • ls (list of strings) split qval[2] instead of qval[2:], truncating the list to its first character. This was visible in the API index page's own example: ec_curvedata?torsion_structure=ls2;2&_delim=; searched for [2], so it returned curves with torsion structure Z/2 instead of Z/2 x Z/2.

The type-prefix decoding now lives in a pure helper parse_api_value, so lmfdb/api/test_api.py can pin the parser contracts directly (inclusive endpoints, bare None vs sNone, the cf and ls regressions, malformed typed values falling back to strings) alongside end-to-end range, null, containment and list queries against real tables.


Ported from roed-math#18, where the full write-up and comment history live.

🤖 Generated with Claude Code

roed314 and others added 4 commits July 19, 2026 01:50
The API query parser now accepts the inclusive range syntax a..b under
the numeric type-prefixes i and f (either endpoint may be omitted), and
the unprefixed value None to match rows where a column is null (sNone
still gives the literal string "None").  Neither changes any working
query: i/f values containing ".." previously fell back to a junk
literal string, and bare None was compared as the string 'None', both
producing SQL type errors.  Also fixes the cf prefix, which built
{"contains": ...} instead of {"$contains": ...} and so generated
invalid SQL.  Documented on the API index page; verified with new tests
in lmfdb/api/test_api.py against devmirror (8 passed) plus html/yaml
spot-checks and pyflakes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review of #18 asked for regression coverage of the
user-visible behavior the PR changes, so extract the type-prefix value
decoding out of api_query into a pure helper parse_api_value and test it
directly:

- test_api_contains_float_query pins the cf fix ($contains, not
  contains) against nf_fields 6.0.177147.2, whose coeffs contain 0 but
  not 0.5.
- test_parse_numeric plus an i11..11 endpoint query pin the ranges as
  inclusive; strict $gt/$lt returns nothing and fails both.
- test_parse_api_value covers bare None vs sNone, the other prefixes,
  and the fallback of malformed typed values to their original strings.

Route behavior is unchanged: meta keys starting with _ are still
skipped, and a value whose conversion raises is still kept as a string
(i.. still does not become an unconstrained query).

Also document the s escape for range-looking values (si11..100) on the
API index page, since such a value used to be searchable as a literal.

Verified: sage -python -m pytest lmfdb/api/test_api.py -> 11 passed;
sage -python -m pyflakes on both changed modules is clean; reverting the
cf fix or replacing $gte/$lte with $gt/$lt fails the new tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The ls branch of the API query parser read qval[2] instead of qval[2:],
so a list of strings was truncated to its first character: the example
on the API index page, ec_curvedata?torsion_structure=ls2;2&_delim=;,
searched for [2] and returned curves with torsion structure Z/2 rather
than the intended Z/2 x Z/2.  The other list prefixes (li, lf) already
sliced correctly.

Covered by a direct assertion in test_parse_api_value and by a new
test_api_list_of_strings_query, which runs the documented example and
checks the torsion structures that come back; both fail with the old
qval[2].

Verified: sage -python -m pytest lmfdb/api/test_api.py -> 12 passed;
pyflakes clean on both changed modules.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cannot search for modular curves with q_gonality=None using the api Range queries in API

2 participants