Here's an approach that seems reasonable. First, I subclass couchdb.design.ViewDefinition. (Comments and pydocs are removed for brevity.)
import couchdb.design import inflection DESIGN_NAME="version" class CurrentVersion(couchdb.design.ViewDefinition): def __init__(self): map_fun = self.__class__.map if hasattr(self.__class__, "reduce"): reduce_fun = self.__class__.reduce else: reduce_fun = None super_args = (DESIGN_NAME, inflection.underscore(self.__class__.__name__), map_fun, reduce_fun, 'python') super(CurrentVersion, self).__init__(*super_args) @staticmethod def map(doc): if 'version_key' in doc and 'created_ts' in doc: yield (doc['version_key'], [doc['_id'], doc['created_ts']]) @staticmethod def reduce(keys, values, rereduce): max_index = 0 for index, value in enumerate(values): if value[1] > values[max_index][1]: max_index = index return values[max_index]
Now if I want to sync:
import couchdb.design from couchview.version import CurrentVersion db = get_couch_db()
The advantages of this approach are as follows:
- Organization. All constructions / representations exist as modules / classes (respectively), located in one package.
- Real code. My text editor will highlight the syntax. I can write unit tests against my map / reduce functions.
The ViewDefinition subprocess can also be used for queries.
current_version_view = couchview.version.CurrentVersion() result = current_version_view(self.db, key=version_key)
It's not ready for production yet, but I think this is a big step compared to storing map / reduce functions inside string literals.
Edit: I eventually wrote a couple of blog posts on this topic, as I could not find any other sources of advice:
source share