Skip to content

items() values drop the key fields when there is no getitem_projection #9

Description

@thorwhalen

The gap

MongoCollectionReader.iter_items builds each item's value by popping the key
fields out of the document:

for doc in cursor:
    key = {k: doc.pop(k) for k in self.key_fields}
    yield (key, doc)

That is right when getitem_projection excludes the key fields (the usual
configuration): __getitem__ wouldn't return them either.

It is wrong when getitem_projection is None, which means "return the whole
document". Then store[k] includes _id while items()' value does not, so

list(store.items()) != [(k, store[k]) for k in store]

— a Mapping-contract violation, in the default configuration of every
MongoCollection*Persister.

values() is unaffected: iter_values projects with getitem_projection and
pops nothing.

Why it wasn't fixed alongside #7

The correct behaviour (strip only the key fields the getitem projection would
not have returned; never mutate the doc when it is None) changes results that
mongodol/tests/int_tests/base_int_test.py::test_store_with_mappers explicitly
asserts:

assert list(store.items()) == [
    (key_output_mapper({ID: n[ID]}), value_output_mapper({k: v for k, v in n.items() if k != ID}))
    for n in nums_and_lans
]

so it needs a deliberate decision about which of the two is the contract before
the test is rewritten.

Where it is pinned

mongodol/tests/views_test.py::test_items_values_equal_getitem_values_when_no_getitem_projection
is a strict=True xfail, so it will flip the suite red the moment the behaviour
is fixed — and points here.

Surfaced while fixing #7.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions