diff --git a/python/semantic_kernel/connectors/redis.py b/python/semantic_kernel/connectors/redis.py index 575624895aca..5ad4dd4c5fc6 100644 --- a/python/semantic_kernel/connectors/redis.py +++ b/python/semantic_kernel/connectors/redis.py @@ -278,7 +278,7 @@ async def ensure_collection_exists(self, **kwargs) -> None: raise VectorStoreOperationException("Invalid index type supplied.") fields = _definition_to_redis_fields(self.definition, self.collection_type) index_definition = IndexDefinition( - prefix=f"{self.collection_name}:", index_type=INDEX_TYPE_MAP[self.collection_type] + prefix=[f"{self.collection_name}:"], index_type=INDEX_TYPE_MAP[self.collection_type] ) await self.redis_database.ft(self.collection_name).create_index(fields, definition=index_definition, **kwargs) @@ -706,7 +706,7 @@ def _add_key(self, key: TKey, record: dict[str, Any]) -> dict[str, Any]: @override async def _inner_delete(self, keys: Sequence[str], **kwargs: Any) -> None: - await asyncio.gather(*[self.redis_database.json().delete(key, **kwargs) for key in keys]) + await asyncio.gather(*[self.redis_database.json().delete(self._get_redis_key(key), **kwargs) for key in keys]) @override def _serialize_dicts_to_store_models( diff --git a/python/tests/unit/connectors/memory/test_redis_store.py b/python/tests/unit/connectors/memory/test_redis_store.py index e779ad945a97..b2ed9182453e 100644 --- a/python/tests/unit/connectors/memory/test_redis_store.py +++ b/python/tests/unit/connectors/memory/test_redis_store.py @@ -270,11 +270,31 @@ async def test_get( assert records is not None +@mark.parametrize("prefix", [True, False]) @mark.parametrize("type_", ["hashset", "json"]) -async def test_delete(collection_hash, collection_json, type_): - collection = collection_hash if type_ == "hashset" else collection_json +async def test_delete( + collection_hash, + collection_json, + collection_with_prefix_hash, + collection_with_prefix_json, + mock_delete_hash, + mock_delete_json, + type_, + prefix, +): + if prefix: + collection = collection_with_prefix_hash if type_ == "hashset" else collection_with_prefix_json + else: + collection = collection_hash if type_ == "hashset" else collection_json + await collection._inner_delete(["id1"]) + expected_key = "test:id1" if prefix else "id1" + if type_ == "hashset": + mock_delete_hash.assert_called_once_with(expected_key) + else: + mock_delete_json.assert_called_once_with(expected_key) + async def test_collection_exists(collection_hash, mock_collection_exists): await collection_hash.collection_exists() @@ -294,12 +314,26 @@ async def test_ensure_collection_deleted(collection_hash, mock_ensure_collection async def test_create_index(collection_hash, mock_ensure_collection_exists): await collection_hash.ensure_collection_exists() + index_definition = mock_ensure_collection_exists.call_args.kwargs["definition"] + + # A bare string prefix is treated as an iterable by redis-py and becomes + # five one-character prefixes. Assert the generated command uses one prefix. + assert index_definition.args == ["ON", "HASH", "PREFIX", 1, "test:", "SCORE", 1.0] + + +def test_create_index_prefix_must_be_sequence(): + from redis.commands.search.index_definition import IndexDefinition, IndexType + + index_definition = IndexDefinition(prefix="test:", index_type=IndexType.HASH) + + assert index_definition.args == ["ON", "HASH", "PREFIX", 5, "t", "e", "s", "t", ":", "SCORE", 1.0] + async def test_create_index_manual(collection_hash, mock_ensure_collection_exists): from redis.commands.search.index_definition import IndexDefinition, IndexType fields = ["fields"] - index_definition = IndexDefinition(prefix="test:", index_type=IndexType.HASH) + index_definition = IndexDefinition(prefix=["test:"], index_type=IndexType.HASH) await collection_hash.ensure_collection_exists(index_definition=index_definition, fields=fields)