field_list.py 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. __all__ = ('QueryFieldList',)
  2. class QueryFieldList(object):
  3. """Object that handles combinations of .only() and .exclude() calls"""
  4. ONLY = 1
  5. EXCLUDE = 0
  6. def __init__(self, fields=None, value=ONLY, always_include=None, _only_called=False):
  7. """The QueryFieldList builder
  8. :param fields: A list of fields used in `.only()` or `.exclude()`
  9. :param value: How to handle the fields; either `ONLY` or `EXCLUDE`
  10. :param always_include: Any fields to always_include eg `_cls`
  11. :param _only_called: Has `.only()` been called? If so its a set of fields
  12. otherwise it performs a union.
  13. """
  14. self.value = value
  15. self.fields = set(fields or [])
  16. self.always_include = set(always_include or [])
  17. self._id = None
  18. self._only_called = _only_called
  19. self.slice = {}
  20. def __add__(self, f):
  21. if isinstance(f.value, dict):
  22. for field in f.fields:
  23. self.slice[field] = f.value
  24. if not self.fields:
  25. self.fields = f.fields
  26. elif not self.fields:
  27. self.fields = f.fields
  28. self.value = f.value
  29. self.slice = {}
  30. elif self.value is self.ONLY and f.value is self.ONLY:
  31. self._clean_slice()
  32. if self._only_called:
  33. self.fields = self.fields.union(f.fields)
  34. else:
  35. self.fields = f.fields
  36. elif self.value is self.EXCLUDE and f.value is self.EXCLUDE:
  37. self.fields = self.fields.union(f.fields)
  38. self._clean_slice()
  39. elif self.value is self.ONLY and f.value is self.EXCLUDE:
  40. self.fields -= f.fields
  41. self._clean_slice()
  42. elif self.value is self.EXCLUDE and f.value is self.ONLY:
  43. self.value = self.ONLY
  44. self.fields = f.fields - self.fields
  45. self._clean_slice()
  46. if '_id' in f.fields:
  47. self._id = f.value
  48. if self.always_include:
  49. if self.value is self.ONLY and self.fields:
  50. if sorted(self.slice.keys()) != sorted(self.fields):
  51. self.fields = self.fields.union(self.always_include)
  52. else:
  53. self.fields -= self.always_include
  54. if getattr(f, '_only_called', False):
  55. self._only_called = True
  56. return self
  57. def __bool__(self):
  58. return bool(self.fields)
  59. __nonzero__ = __bool__ # For Py2 support
  60. def as_dict(self):
  61. field_list = {field: self.value for field in self.fields}
  62. if self.slice:
  63. field_list.update(self.slice)
  64. if self._id is not None:
  65. field_list['_id'] = self._id
  66. return field_list
  67. def reset(self):
  68. self.fields = set([])
  69. self.slice = {}
  70. self.value = self.ONLY
  71. def _clean_slice(self):
  72. if self.slice:
  73. for field in set(self.slice.keys()) - self.fields:
  74. del self.slice[field]