a method to add a view to a design document of a uid 
            
        :param query_criteria: dictionary with valid jsonmodel query criteria 
        :param uid: [optional] string with uid of design document to update
        :return: integer with status of operation

        an example of how to construct the query_criteria argument:

        query_criteria = {
            '.path.to.number': {
                'min_value': 4.5
            },
            '.path.to.string': {
                'discrete_values': [ 'pond', 'lake', 'stream', 'brook' ]
            }
        }
        
        NOTE:   only fields specified in the document schema at class initialization
                can be used as fields in query_criteria. otherwise, an error will be thrown.
                uid is automatically added to all document schemas at initialization
                
        NOTE:   the full list of all criteria are found in the reference page for the
                jsonmodel module as well as the query-rules.json file included in the
                module. 
                http://collectiveacuity.github.io/jsonModel/reference/#query-criteria

def create_view(self, query_criteria=None, uid='_all_users'):
    
        '''
            a method to add a view to a design document of a uid 
            
        :param query_criteria: dictionary with valid jsonmodel query criteria 
        :param uid: [optional] string with uid of design document to update
        :return: integer with status of operation

        an example of how to construct the query_criteria argument:

        query_criteria = {
            '.path.to.number': {
                'min_value': 4.5
            },
            '.path.to.string': {
                'discrete_values': [ 'pond', 'lake', 'stream', 'brook' ]
            }
        }
        
        NOTE:   only fields specified in the document schema at class initialization
                can be used as fields in query_criteria. otherwise, an error will be thrown.
                uid is automatically added to all document schemas at initialization
                
        NOTE:   the full list of all criteria are found in the reference page for the
                jsonmodel module as well as the query-rules.json file included in the
                module. 
                http://collectiveacuity.github.io/jsonModel/reference/#query-criteria
        '''
        
        # https://developer.couchbase.com/documentation/mobile/1.5/references/sync-gateway/admin-rest-api/index.html#/query/put__db___design__ddoc_
        # https://developer.couchbase.com/documentation/server/3.x/admin/Views/views-writing.html
    
        title = '%s.create_view' % self.__class__.__name__
    
    # validate inputs
        input_fields = {
            'uid': uid
        }
        for key, value in input_fields.items():
            if value:
                object_title = '%s(%s=%s)' % (title, key, str(value))
                self.fields.validate(value, '.%s' % key, object_title)

    # validate inputs
        if query_criteria:
            if not self.model:
                raise ValueError('%s(query_criteria={...} requires a document_schema.' % title)
            self.model.query(query_criteria)
        else:
            query_criteria = {}
        if uid != '_all_users' and self.public:
            raise ValueError('%s(uid="%s") user ids are not applicable for a public bucket. % title')
            
    # catch missing args
        if not query_criteria and not uid:
            raise IndexError('%s requires either a uid or query_criteria argument.' % title)
    
    # create a view of all user documents
        else:
            
        # retrieve the design document for the uid
            url = self.bucket_url + '/_design/%s' % uid
            design_details = {
                'views': {}
            }
            response = requests.get(url)
            if response.status_code in (200, 201):
                design_details = response.json()
                design_details['views'] = self._clean_views(design_details['views'])
        
        # create a view of all docs for the uid
            if not query_criteria:
                if uid == '_all_users':
                    return response.status_code
                else:
                    function_string = 'function(doc, meta) { if (doc.uid == "%s") { emit(null, null); } }' % uid
                    design_details['views']['_all_docs'] = { 'map': function_string }
            
        # construct a view for a query criteria
            else:
                
            # determine hashed key for criteria
                import hashlib
                import json
                from collections import OrderedDict
                ordered_criteria = OrderedDict(**query_criteria)
                hashed_criteria = hashlib.md5(json.dumps(query_criteria, sort_keys=True).encode('utf-8')).hexdigest()
            
            # determine function string for criteria
                uid_insert = 'emit();'
                if uid != '_all_users':
                    uid_insert = 'if (doc.uid == "%s") { emit(); }' % uid
                function_string = 'function(doc, meta) { %s }' % uid_insert
                emit_insert = 'emit(null, ['
                count = 0
                for key in ordered_criteria.keys():
                    if count:
                        emit_insert += ','
                    emit_insert += 'doc%s' % key
                emit_insert += ']);'
                function_string = function_string.replace('emit();', emit_insert)
            
            # construct updated design details
                design_details['views'][hashed_criteria] = { 'map': function_string }

        # send update of design document
            response = requests.put(url, json=design_details)
        
        return response.status_code