def test_only_query_field_list_and_exclude_id(self): query = QueryFieldList(['name'], value=QueryFieldList.ONLY, _only_called=True) + QueryFieldList( ['_id'], value=QueryFieldList.EXCLUDE) expect(query.as_dict()).to_be_like({'_id': 0, 'name': 1})
def test_gets_proper_type(self): query1 = QueryFieldList() query2 = QueryFieldList() expect(query1).to_be_instance_of(QueryFieldList) query = query1 + query2 expect(query).to_be_instance_of(QueryFieldList)
def test_union_of_excludes(self): query = ( QueryFieldList(['name'], value=QueryFieldList.EXCLUDE) + QueryFieldList(['email', 'numbers'], value=QueryFieldList.EXCLUDE)) expect(query.as_dict()).to_be_like({ 'name': 0, 'email': 0, 'numbers': 0 })
def test_slice_with_only_and_exclude(self): query = (QueryFieldList() + QueryFieldList( ['numbers'], value={'$slice': 10}, _only_called=False) + QueryFieldList(['numbers'], value=QueryFieldList.EXCLUDE)) expect(query.as_dict()).to_be_like({}) # slice is assumed to act like only query = (QueryFieldList() + QueryFieldList( ['numbers'], value={'$slice': 10}, _only_called=False) + QueryFieldList( ['name'], value=QueryFieldList.ONLY, _only_called=True)) expect(query.as_dict()).to_be_like({ 'name': 1, 'numbers': { '$slice': 10 } }) query = ( QueryFieldList() + QueryFieldList( ['numbers'], value={'$slice': 10}, _only_called=False) + QueryFieldList(['name'], value={'$slice': 13}, _only_called=False)) expect(query.as_dict()).to_be_like({ 'numbers': { '$slice': 10 }, 'name': { '$slice': 13 } })
def test_always_include(self): query = QueryFieldList(always_include=['email']) query += QueryFieldList(['name'], value=QueryFieldList.ONLY, _only_called=True) expect(query.as_dict()).to_be_like({'name': 1, 'email': 1}) query = QueryFieldList(always_include=['email', 'name'], value=QueryFieldList.EXCLUDE) query += QueryFieldList(['email'], value=QueryFieldList.EXCLUDE) expect(query.as_dict()).to_be_like({})
def fields(self, _only_called=False, **kwargs): from itertools import groupby from operator import itemgetter operators = ['slice'] cleaned_fields = [] for key, value in kwargs.items(): parts = key.split('__') if parts[0] in operators: op = parts.pop(0) value = {'$' + op: value} key = '.'.join(parts) try: field_name, value = self._check_valid_field_name_to_project( key, value) except ValueError as e: raise e cleaned_fields.append((field_name, value)) fields = sorted(cleaned_fields, key=itemgetter(1)) for value, group in groupby(fields, lambda x: x[1]): fields = [field for field, value in group] self._loaded_fields += QueryFieldList(fields, value=value, _only_called=_only_called) return self
def test_default_query_field_list(self): query = QueryFieldList() expect(query).not_to_be_null() expect(query.value).to_equal(QueryFieldList.ONLY) expect(query.__nonzero__()).not_to_be_true() expect(query.__bool__()).not_to_be_true() expect(bool(query)).not_to_be_true()
def __init__(self, klass): self.__klass__ = klass self._filters = {} self._limit = None self._skip = None self._order_fields = [] self._loaded_fields = QueryFieldList() self._reference_loaded_fields = {}
def test_only_query_field_list(self): query = QueryFieldList(['name', 'email'], value=QueryFieldList.ONLY) expect(bool(query)).to_be_true() expect(query.as_dict()).to_be_like({'name': 1, 'email': 1}) expect(query.to_query(User)).to_be_like({ 'name': 1, 'email_address': 1 }) query.reset() expect(query.as_dict()).to_be_like({})
def test_exclude_query_field_list(self): query = QueryFieldList(fields=['name.last', 'email'], value=QueryFieldList.EXCLUDE) expect(bool(query)).to_be_true() expect(query.as_dict()).to_be_like({'name.last': 0, 'email': 0}) expect(query.to_query(User)).to_be_like({ 'name.last_name': 0, 'email_address': 0 }) query.reset() expect(query.as_dict()).to_be_like({})
def all_fields(self): """Include all fields. Reset all previously calls of `.only()` or `.exclude().` Usage:: # this will load 'comments' too BlogPost.objects.exclude("comments").all_fields().get(...) """ self._loaded_fields = QueryFieldList( always_include=self._loaded_fields.always_include) return self
def __init__(self, klass): if klass.__abstract__ is True: raise Exception( 'Abstract model \'{}\' could not be used for retrieving data'. format(klass.__name__)) self.__klass__ = klass self._filters = None self._limit = None self._skip = None self._order_fields = [] self._loaded_fields = QueryFieldList() self._reference_loaded_fields = {} if klass.__inherit__ is True: child_classes = [ klass.__hierarchy__, ] child_classes.extend([ child_class.__hierarchy__ for child_class in klass.__child_classes__ ]) self._filters = Q({'_cls': {'$in': child_classes}})
def test_union_of_queries_when_only_or_exclude_called(self): query1 = QueryFieldList(fields=['name.last', 'email'], value=QueryFieldList.ONLY, _only_called=True) query2 = QueryFieldList(fields=['name.first'], value=QueryFieldList.ONLY, _only_called=True) query3 = QueryFieldList(fields=['email'], value=QueryFieldList.EXCLUDE) query = query1 + query2 expect(query.as_dict()).to_be_like({ 'name.last': 1, 'email': 1, 'name.first': 1 }) query = query + query3 expect(query.as_dict()).to_be_like({'name.last': 1, 'name.first': 1}) # try again exclude 'email' that is not in the fields now query = query + QueryFieldList(['email'], value=QueryFieldList.EXCLUDE) expect(query.as_dict()).to_be_like({'name.last': 1, 'name.first': 1}) # the same but exclude first now query = QueryFieldList(['email'], value=QueryFieldList.EXCLUDE) + query expect(query.as_dict()).to_be_like({'name.last': 1, 'name.first': 1}) # exclude first field present in fields query = (QueryFieldList(['name.last'], value=QueryFieldList.EXCLUDE) + query) expect(query.as_dict()).to_be_like({'name.first': 1}) # exclude works only with full names not with prefixes query = (QueryFieldList(['name'], value=QueryFieldList.EXCLUDE) + query) expect(query.as_dict()).to_be_like({'name.first': 1})
def fields(self, _only_called=False, **kwargs): """Manipulate how you load this document's fields. Used by `.only()` and `.exclude()` to manipulate which fields to retrieve. Fields also allows for a greater level of control for example: Retrieving a Subrange of Array Elements: You can use the `$slice` operator to retrieve a subrange of elements in an array. For example to get the first 5 comments:: BlogPost.objects.fields(slice__comments=5).get(...) or 5 comments after skipping 10 comments:: BlogPost.objects.fields(slice__comments=(10, 5)).get(...) or you can also use negative values, for example skip 10 comment from the end and retrieve 5 comments forward:: BlogPost.objects.fields(slice__comments=(-10, 5)).get(...) Besides slice, it is possible to include or exclude fields (but it is strongly recommended to use `.only()` and `.exclude()` methods instead):: BlogPost.objects.fields( slice__comments=5, _id=QueryFieldList.EXCLUDE, title=QueryFieldList.ONLY ).get(...) :param kwargs: A dictionary identifying what to include """ # Check for an operator and transform to mongo-style if there is one operators = ["slice"] cleaned_fields = [] for key, value in kwargs.items(): parts = key.split('__') if parts[0] in operators: op = parts.pop(0) value = {'$' + op: value} key = '.'.join(parts) try: field_name, value = self._check_valid_field_name_to_project( key, value) except ValueError as e: raise e cleaned_fields.append((field_name, value)) # divide fields on groups by their values # (ONLY group, EXCLUDE group etc.) and add them to _loaded_fields # as an appropriate QueryFieldList fields = sorted(cleaned_fields, key=operator.itemgetter(1)) for value, group in itertools.groupby(fields, lambda x: x[1]): fields = [field for field, value in group] self._loaded_fields += QueryFieldList(fields, value=value, _only_called=_only_called) return self
def all_fields(self): self._loaded_fields = QueryFieldList( always_include=self._loaded_fields.always_include) return self
def test_slice_query_field_list(self): query = QueryFieldList(['numbers'], value={'$slice': 10}, _only_called=False) expect(query.as_dict()).to_be_like({'numbers': {'$slice': 10}})
def test_slice_and_always_include(self): query = (QueryFieldList(['numbers'], always_include=['numbers']) + QueryFieldList( ['numbers'], value={'$slice': 10}, _only_called=False)) expect(query.as_dict()).to_be_like({'numbers': {'$slice': 10}})
def test_not_only_called_projection(self): query = (QueryFieldList() + QueryFieldList( ['name'], value=QueryFieldList.ONLY, _only_called=False)) expect(query.as_dict()).to_be_like({'name': 1})
def test_wrong_value(self): query = (QueryFieldList( ['name'], value=QueryFieldList.ONLY, _only_called=False) + QueryFieldList(['name'], value='Wrong', _only_called=False)) expect(query.as_dict()).to_be_like({'name': 1})