图片解析应用
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

147 lines
4.7 KiB

  1. from json import JSONDecodeError, JSONDecoder, JSONEncoder
  2. import redis
  3. from ..helpers import get_protocol_version, nativestr
  4. from .commands import JSONCommands
  5. from .decoders import bulk_of_jsons, decode_list
  6. class JSON(JSONCommands):
  7. """
  8. Create a client for talking to json.
  9. :param decoder:
  10. :type json.JSONDecoder: An instance of json.JSONDecoder
  11. :param encoder:
  12. :type json.JSONEncoder: An instance of json.JSONEncoder
  13. """
  14. def __init__(
  15. self, client, version=None, decoder=JSONDecoder(), encoder=JSONEncoder()
  16. ):
  17. """
  18. Create a client for talking to json.
  19. :param decoder:
  20. :type json.JSONDecoder: An instance of json.JSONDecoder
  21. :param encoder:
  22. :type json.JSONEncoder: An instance of json.JSONEncoder
  23. """
  24. # Set the module commands' callbacks
  25. self._MODULE_CALLBACKS = {
  26. "JSON.ARRPOP": self._decode,
  27. "JSON.DEBUG": self._decode,
  28. "JSON.GET": self._decode,
  29. "JSON.MERGE": lambda r: r and nativestr(r) == "OK",
  30. "JSON.MGET": bulk_of_jsons(self._decode),
  31. "JSON.MSET": lambda r: r and nativestr(r) == "OK",
  32. "JSON.RESP": self._decode,
  33. "JSON.SET": lambda r: r and nativestr(r) == "OK",
  34. "JSON.TOGGLE": self._decode,
  35. }
  36. _RESP2_MODULE_CALLBACKS = {
  37. "JSON.ARRAPPEND": self._decode,
  38. "JSON.ARRINDEX": self._decode,
  39. "JSON.ARRINSERT": self._decode,
  40. "JSON.ARRLEN": self._decode,
  41. "JSON.ARRTRIM": self._decode,
  42. "JSON.CLEAR": int,
  43. "JSON.DEL": int,
  44. "JSON.FORGET": int,
  45. "JSON.GET": self._decode,
  46. "JSON.NUMINCRBY": self._decode,
  47. "JSON.NUMMULTBY": self._decode,
  48. "JSON.OBJKEYS": self._decode,
  49. "JSON.STRAPPEND": self._decode,
  50. "JSON.OBJLEN": self._decode,
  51. "JSON.STRLEN": self._decode,
  52. "JSON.TOGGLE": self._decode,
  53. }
  54. _RESP3_MODULE_CALLBACKS = {}
  55. self.client = client
  56. self.execute_command = client.execute_command
  57. self.MODULE_VERSION = version
  58. if get_protocol_version(self.client) in ["3", 3]:
  59. self._MODULE_CALLBACKS.update(_RESP3_MODULE_CALLBACKS)
  60. else:
  61. self._MODULE_CALLBACKS.update(_RESP2_MODULE_CALLBACKS)
  62. for key, value in self._MODULE_CALLBACKS.items():
  63. self.client.set_response_callback(key, value)
  64. self.__encoder__ = encoder
  65. self.__decoder__ = decoder
  66. def _decode(self, obj):
  67. """Get the decoder."""
  68. if obj is None:
  69. return obj
  70. try:
  71. x = self.__decoder__.decode(obj)
  72. if x is None:
  73. raise TypeError
  74. return x
  75. except TypeError:
  76. try:
  77. return self.__decoder__.decode(obj.decode())
  78. except AttributeError:
  79. return decode_list(obj)
  80. except (AttributeError, JSONDecodeError):
  81. return decode_list(obj)
  82. def _encode(self, obj):
  83. """Get the encoder."""
  84. return self.__encoder__.encode(obj)
  85. def pipeline(self, transaction=True, shard_hint=None):
  86. """Creates a pipeline for the JSON module, that can be used for executing
  87. JSON commands, as well as classic core commands.
  88. Usage example:
  89. r = redis.Redis()
  90. pipe = r.json().pipeline()
  91. pipe.jsonset('foo', '.', {'hello!': 'world'})
  92. pipe.jsonget('foo')
  93. pipe.jsonget('notakey')
  94. """
  95. if isinstance(self.client, redis.RedisCluster):
  96. p = ClusterPipeline(
  97. nodes_manager=self.client.nodes_manager,
  98. commands_parser=self.client.commands_parser,
  99. startup_nodes=self.client.nodes_manager.startup_nodes,
  100. result_callbacks=self.client.result_callbacks,
  101. cluster_response_callbacks=self.client.cluster_response_callbacks,
  102. cluster_error_retry_attempts=self.client.cluster_error_retry_attempts,
  103. read_from_replicas=self.client.read_from_replicas,
  104. reinitialize_steps=self.client.reinitialize_steps,
  105. lock=self.client._lock,
  106. )
  107. else:
  108. p = Pipeline(
  109. connection_pool=self.client.connection_pool,
  110. response_callbacks=self._MODULE_CALLBACKS,
  111. transaction=transaction,
  112. shard_hint=shard_hint,
  113. )
  114. p._encode = self._encode
  115. p._decode = self._decode
  116. return p
  117. class ClusterPipeline(JSONCommands, redis.cluster.ClusterPipeline):
  118. """Cluster pipeline for the module."""
  119. class Pipeline(JSONCommands, redis.client.Pipeline):
  120. """Pipeline for the module."""