Source code for langchain_community.storage.upstash_redis

from typing import Any, Iterator, List, Optional, Sequence, Tuple, cast

from langchain_core._api.deprecation import deprecated
from langchain_core.stores import BaseStore, ByteStore


class _UpstashRedisStore(BaseStore[str, str]):
    """使用Upstash Redis作为基础存储的BaseStore实现。"""

    def __init__(
        self,
        *,
        client: Any = None,
        url: Optional[str] = None,
        token: Optional[str] = None,
        ttl: Optional[int] = None,
        namespace: Optional[str] = None,
    ) -> None:
        """使用HTTP API初始化UpstashRedisStore。

必须提供Upstash Redis客户端或一个URL。

参数:
    client:一个Upstash Redis实例
    url:UPSTASH_REDIS_REST_URL
    token:UPSTASH_REDIS_REST_TOKEN
    ttl:如果提供,键的过期时间(以秒为单位),
         如果为None,则键永远不会过期
    namespace:如果提供,所有键将以此命名空间为前缀。
"""
        try:
            from upstash_redis import Redis
        except ImportError as e:
            raise ImportError(
                "UpstashRedisStore requires the upstash_redis library to be installed. "
                "pip install upstash_redis"
            ) from e

        if client and url:
            raise ValueError(
                "Either an Upstash Redis client or a url must be provided, not both."
            )

        if client:
            if not isinstance(client, Redis):
                raise TypeError(
                    f"Expected Upstash Redis client, got {type(client).__name__}."
                )
            _client = client
        else:
            if not url or not token:
                raise ValueError(
                    "Either an Upstash Redis client or url and token must be provided."
                )
            _client = Redis(url=url, token=token)

        self.client = _client

        if not isinstance(ttl, int) and ttl is not None:
            raise TypeError(f"Expected int or None, got {type(ttl)} instead.")

        self.ttl = ttl
        self.namespace = namespace

    def _get_prefixed_key(self, key: str) -> str:
        """获取带有命名空间前缀的键。

参数:
    key(str):原始键。

返回:
    str:带有命名空间前缀的键。
"""
        delimiter = "/"
        if self.namespace:
            return f"{self.namespace}{delimiter}{key}"
        return key

    def mget(self, keys: Sequence[str]) -> List[Optional[str]]:
        """获取与给定键相关联的值。"""

        keys = [self._get_prefixed_key(key) for key in keys]
        return cast(
            List[Optional[str]],
            self.client.mget(*keys),
        )

    def mset(self, key_value_pairs: Sequence[Tuple[str, str]]) -> None:
        """设置给定的键值对。"""
        for key, value in key_value_pairs:
            self.client.set(self._get_prefixed_key(key), value, ex=self.ttl)

    def mdelete(self, keys: Sequence[str]) -> None:
        """删除给定的键。"""
        _keys = [self._get_prefixed_key(key) for key in keys]
        self.client.delete(*_keys)

    def yield_keys(self, *, prefix: Optional[str] = None) -> Iterator[str]:
        """在存储中生成密钥。"""
        if prefix:
            pattern = self._get_prefixed_key(prefix)
        else:
            pattern = self._get_prefixed_key("*")

        cursor, keys = self.client.scan(0, match=pattern)
        for key in keys:
            if self.namespace:
                relative_key = key[len(self.namespace) + 1 :]
                yield relative_key
            else:
                yield key

        while cursor != 0:
            cursor, keys = self.client.scan(cursor, match=pattern)
            for key in keys:
                if self.namespace:
                    relative_key = key[len(self.namespace) + 1 :]
                    yield relative_key
                else:
                    yield key


[docs]@deprecated("0.0.1", alternative="UpstashRedisByteStore") class UpstashRedisStore(_UpstashRedisStore): """使用Upstash Redis作为底层存储来存储字符串的BaseStore实现。 已弃用,推荐使用更通用的UpstashRedisByteStore。"""
[docs]class UpstashRedisByteStore(ByteStore): """使用Upstash Redis作为底层存储来实现BaseStore。"""
[docs] def __init__( self, *, client: Any = None, url: Optional[str] = None, token: Optional[str] = None, ttl: Optional[int] = None, namespace: Optional[str] = None, ) -> None: self.underlying_store = _UpstashRedisStore( client=client, url=url, token=token, ttl=ttl, namespace=namespace )
[docs] def mget(self, keys: Sequence[str]) -> List[Optional[bytes]]: """获取与给定键相关联的值。""" return [ value.encode("utf-8") if value is not None else None for value in self.underlying_store.mget(keys) ]
[docs] def mset(self, key_value_pairs: Sequence[Tuple[str, bytes]]) -> None: """设置给定的键值对。""" self.underlying_store.mset( [ (k, v.decode("utf-8")) if v is not None else None for k, v in key_value_pairs ] )
[docs] def mdelete(self, keys: Sequence[str]) -> None: """删除给定的键。""" self.underlying_store.mdelete(keys)
[docs] def yield_keys(self, *, prefix: Optional[str] = None) -> Iterator[str]: """在存储中生成密钥。""" yield from self.underlying_store.yield_keys(prefix=prefix)