Skip to content

upstream(tinydb): query conditions never see the document id #133

Open

Description

@cdwilson

Tracks upstream friction in TinyDB. The explanation lives in the docs; this issue is the unit of work.

Explanation: Query conditions never see the document id — the limitation, why it matters to an ODM, the workaround tinydantic carries, and the change that would remove it. That section is written to be read standalone by an upstream maintainer, so it doubles as the ready-to-send proposal if we ever file this.

Reproduction

Upstream only — no tinydantic import, so this is what a report would carry.

from tinydb import TinyDB
from tinydb.storages import MemoryStorage

db = TinyDB(storage=MemoryStorage)
db.insert({"name": "a"})


def probe(doc):
    print("search() passes:", type(doc).__name__, doc, "doc_id:", getattr(doc, "doc_id", None))
    return False


db.search(probe)
print("__iter__ yields: ", [type(d).__name__ for d in db])

Run with python repro.py.

Actual output:

search() passes: dict {'name': 'a'} doc_id: None
__iter__ yields:  ['Document']

The condition is handed the raw body mapping. The id sits right there as the dict key in the evaluation loop, but nothing the condition receives carries it — so no query object, however constructed, can express "document id equals 1". Table.__iter__ is the only API that yields Documents.

Expected: with the needs_doc_id/DocId opt-in described in the docs section, a condition that asks for the id is handed Document(body, doc_id) and every other condition keeps the current fast path untouched.

Environment: TinyDB 4.9.0, Python 3.10.20, macOS. Run 2026-08-13.

What tinydantic carries today

A whole id-translation layer: id-bearing conditions are detected in every model method and executed via doc_id=/doc_ids= operations or by iterating the table. See src/tinydantic/_query.py and the id-condition branches in src/tinydantic/_model.py.

Private API: QueryInstance._hash (read-only) in has_id_condition() — composition (&/|/~) produces plain QueryInstance objects, so the hashval tree is the only place a marker survives. Approved 2026-08-02; degrades loudly, never silently.

Upstream status

Not filed. No draft prepared.

What would close this

The needs_doc_id/DocId opt-in protocol described in the docs section, which would let tinydantic delete the translation layer entirely — or a maintainer decision to carry the workaround indefinitely.

Assisted-by: Claude:claude-opus-5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    ai-assistedCreated or investigated with help from an AI agentenhancementNew feature or requestupstreamTracks a defect or request in an upstream dependency

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions