Add a secondary index for a collection ``collection`` on one or
    more ``fields``.

    The values at each of the ``fields`` are loaded from existing
    objects and their object ids added to the index.

    You can later iterate the objects of an index via
    ``each_indexed_object``.

    If you update an object and call ``save_object``, the index will
    be updated with the latest values from the updated object.

    If you delete an object via ``delete_object``, the object will
    be removed from any indexes on the object's collection.

    If a function is provided for ``transformer``, the values
    extracted from each object in the collection will be passed to
    the ``transformer``.  The ``transformer`` should return a list
    of values that will go into the index.

    If ``unique`` is true, then there may only be at most one object
    in the collection with a unique set of values for each the
    ``fields`` provided.

    If ``case_insensitive`` is true, then the value stored in the
    index will be lower-cased and comparisons thereto will be
    lower-cased as well.

def add_index(collection,
              name,
              fields,
              transformer=None,
              unique=False,
              case_insensitive=False):
    """
    Add a secondary index for a collection ``collection`` on one or
    more ``fields``.

    The values at each of the ``fields`` are loaded from existing
    objects and their object ids added to the index.

    You can later iterate the objects of an index via
    ``each_indexed_object``.

    If you update an object and call ``save_object``, the index will
    be updated with the latest values from the updated object.

    If you delete an object via ``delete_object``, the object will
    be removed from any indexes on the object's collection.

    If a function is provided for ``transformer``, the values
    extracted from each object in the collection will be passed to
    the ``transformer``.  The ``transformer`` should return a list
    of values that will go into the index.

    If ``unique`` is true, then there may only be at most one object
    in the collection with a unique set of values for each the
    ``fields`` provided.

    If ``case_insensitive`` is true, then the value stored in the
    index will be lower-cased and comparisons thereto will be
    lower-cased as well.
    """
    assert len(name) > 0
    assert len(fields) > 0
    indexes = _db[collection].indexes
    index = indexes.setdefault(name, aadict())
    index.transformer = transformer
    index.value_map = {}  # json([value]) => set(object_id)
    index.unique = unique
    index.case_insensitive = case_insensitive
    index.fields = fields
    for obj in each_object(collection):
        _add_to_index(index, obj)
    _logger.info('added %s, %s index to collection %s on fields: %s',
        'unique' if unique else 'non-unique',
        'case-insensitive' if case_insensitive else 'case-sensitive',
        collection, ', '.join(fields))