Searching, scanning, and querying
Don't panic; these are all just synonyms. We'll use the words interchangeably.
We have two design choices when looking at database searches. We can either return a sequence of keys or we can return a sequence of objects. As our design emphasizes storing the keys in each object, getting a sequence of objects from the database is sufficient, so we'll focus on that kind of design.
A search is inherently inefficient. We'd prefer to have more focused indices. We'll look at how we can create more useful indices in the following section. The fallback plan of brute-force scans, however, always works.
When a child class has an independent-style key, we can easily scan a shelf for all instances of some Child
class using a simple iterator over the keys. Here's a generator expression that locates all the children:
children = ( shelf[k] for k in shelf.keys() if key.startswith("Child:") )
This looks at every single key in the shelf to pick the subset that begins with "Child...