query.py 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. from __future__ import absolute_import
  2. from django.db.models.lookups import Exact
  3. from bitfield.types import Bit, BitHandler
  4. class BitQueryLookupWrapper(Exact): # NOQA
  5. def process_lhs(self, compiler, connection, lhs=None):
  6. lhs_sql, lhs_params = super(BitQueryLookupWrapper, self).process_lhs(
  7. compiler, connection, lhs
  8. )
  9. if not isinstance(self.rhs, (BitHandler, Bit)):
  10. return lhs_sql, lhs_params
  11. op = " & " if self.rhs else " | "
  12. rhs_sql, rhs_params = self.process_rhs(compiler, connection)
  13. params = list(lhs_params)
  14. params.extend(rhs_params)
  15. return op.join((lhs_sql, rhs_sql)), params
  16. def get_db_prep_lookup(self, value, connection):
  17. v = value.mask if isinstance(value, (BitHandler, Bit)) else value
  18. return super(BitQueryLookupWrapper, self).get_db_prep_lookup(v, connection)
  19. def get_prep_lookup(self):
  20. if isinstance(self.rhs, (BitHandler, Bit)):
  21. return self.rhs # resolve at later stage, in get_db_prep_lookup
  22. return super(BitQueryLookupWrapper, self).get_prep_lookup()
  23. class BitQuerySaveWrapper(BitQueryLookupWrapper):
  24. def as_sql(self, qn, connection):
  25. """
  26. Create the proper SQL fragment. This inserts something like
  27. "(T0.flags & value) != 0".
  28. This will be called by Where.as_sql()
  29. """
  30. engine = connection.settings_dict["ENGINE"].rsplit(".", -1)[-1]
  31. if engine.startswith("postgres"):
  32. XOR_OPERATOR = "#"
  33. elif engine.startswith("sqlite"):
  34. raise NotImplementedError
  35. else:
  36. XOR_OPERATOR = "^"
  37. if self.bit:
  38. return (
  39. "%s.%s | %d" % (qn(self.table_alias), qn(self.column), self.bit.mask),
  40. [],
  41. )
  42. return (
  43. "%s.%s %s %d"
  44. % (qn(self.table_alias), qn(self.column), XOR_OPERATOR, self.bit.mask),
  45. [],
  46. )