Index reader.

def read_by_indexes(table_name, index_name_values=None):
    """Index reader."""
    req = datastore.RunQueryRequest()

    query = req.query
    query.kind.add().name = table_name

    if not index_name_values:
        index_name_values = []
    for name, val in index_name_values:
        queryFilter = query.filter.property_filter
        queryFilter.property.name = name
        queryFilter.operator = datastore.PropertyFilter.EQUAL
        queryFilter.value.string_value = str(val)

    loop_its = 0
    have_more = True

    while have_more:
        resp = datastore.run_query(req)

        found_something = False
        for found in resp.batch.entity_result:
            yield extract_entity(found)
            found_something = True

        if not found_something:
            # This is a guard against bugs or excessive looping - as long we
            # can keep yielding records we'll continue to execute
            loop_its += 1
            if loop_its > 5:
                raise ValueError("Exceeded the excessive query threshold")

        if resp.batch.more_results != datastore.QueryResultBatch.NOT_FINISHED:
            have_more = False
        else:
            have_more = True
            end_cursor = resp.batch.end_cursor
            query.start_cursor.CopyFrom(end_cursor)