Skip to content

Commit 6290276

Browse files
cleanup and add more tests
1 parent 8a59945 commit 6290276

File tree

4 files changed

+132
-10
lines changed

4 files changed

+132
-10
lines changed

redisvl/index/index.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -757,7 +757,9 @@ async def from_existing(
757757
)
758758

759759
# Validate modules
760-
installed_modules = convert_bytes(await redis_client.module_list())
760+
installed_modules = unpack_redis_modules(
761+
convert_bytes(await redis_client.module_list())
762+
)
761763
validate_modules(installed_modules, [{"name": "search", "ver": 20810}])
762764

763765
# Fetch index info and convert to schema

redisvl/redis/connection.py

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ def convert_index_info_to_schema(index_info: Dict[str, Any]) -> Dict[str, Any]:
6161
prefixes = index_info["index_definition"][3][0]
6262
storage_type = index_info["index_definition"][1].lower()
6363

64-
attributes = index_info["attributes"]
64+
index_fields = index_info["attributes"]
6565

6666
def parse_vector_attrs(attrs):
6767
vector_attrs = {attrs[i].lower(): attrs[i + 1] for i in range(6, len(attrs), 2)}
@@ -74,18 +74,25 @@ def parse_vector_attrs(attrs):
7474
def parse_attrs(attrs):
7575
return {attrs[i].lower(): attrs[i + 1] for i in range(6, len(attrs), 2)}
7676

77-
fields = []
78-
for attr in attributes:
79-
field = {"name": attr[1], "type": attr[5].lower()}
80-
if attr[5] == "VECTOR":
81-
field["attrs"] = parse_vector_attrs(attr)
77+
schema_fields = []
78+
79+
for field_attrs in index_fields:
80+
# parse field info
81+
name = field_attrs[1] if storage_type == "hash" else field_attrs[3]
82+
field = {"name": name, "type": field_attrs[5].lower()}
83+
if storage_type == "json":
84+
field["path"] = field_attrs[1]
85+
# parse field attrs
86+
if field_attrs[5] == "VECTOR":
87+
field["attrs"] = parse_vector_attrs(field_attrs)
8288
else:
83-
field["attrs"] = parse_attrs(attr)
84-
fields.append(field)
89+
field["attrs"] = parse_attrs(field_attrs)
90+
# append field
91+
schema_fields.append(field)
8592

8693
return {
8794
"index": {"name": index_name, "prefix": prefixes, "storage_type": storage_type},
88-
"fields": fields,
95+
"fields": schema_fields,
8996
}
9097

9198

tests/unit/test_async_search_index.py renamed to tests/integration/test_async_search_index.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,16 @@ def async_index(index_schema):
1818
return AsyncSearchIndex(schema=index_schema)
1919

2020

21+
@pytest.fixture
22+
def async_index_from_dict():
23+
return AsyncSearchIndex.from_dict({"index": {"name": "my_index"}, "fields": fields})
24+
25+
26+
@pytest.fixture
27+
def async_index_from_yaml():
28+
return AsyncSearchIndex.from_yaml("schemas/test_json_schema.yaml")
29+
30+
2131
def test_search_index_properties(index_schema, async_index):
2232
assert async_index.schema == index_schema
2333
# custom settings
@@ -32,6 +42,73 @@ def test_search_index_properties(index_schema, async_index):
3242
assert async_index.key("foo").startswith(async_index.prefix)
3343

3444

45+
def test_search_index_from_yaml(async_index_from_yaml):
46+
assert async_index_from_yaml.name == "json-test"
47+
assert async_index_from_yaml.client == None
48+
assert async_index_from_yaml.prefix == "json"
49+
assert async_index_from_yaml.key_separator == ":"
50+
assert async_index_from_yaml.storage_type == StorageType.JSON
51+
assert async_index_from_yaml.key("foo").startswith(async_index_from_yaml.prefix)
52+
53+
54+
def test_search_index_from_dict(async_index_from_dict):
55+
assert async_index_from_dict.name == "my_index"
56+
assert async_index_from_dict.client == None
57+
assert async_index_from_dict.prefix == "rvl"
58+
assert async_index_from_dict.key_separator == ":"
59+
assert async_index_from_dict.storage_type == StorageType.HASH
60+
assert len(async_index_from_dict.schema.fields) == len(fields)
61+
assert async_index_from_dict.key("foo").startswith(async_index_from_dict.prefix)
62+
63+
64+
@pytest.mark.asyncio
65+
async def test_search_index_from_existing(async_client, async_index):
66+
async_index.set_client(async_client)
67+
await async_index.create(overwrite=True)
68+
69+
async_index2 = await AsyncSearchIndex.from_existing(async_index.name, async_client)
70+
assert async_index2.schema == async_index.schema
71+
72+
73+
@pytest.mark.asyncio
74+
async def test_search_index_from_existing_complex(async_client):
75+
schema = {
76+
"index": {
77+
"name": "test",
78+
"prefix": "test",
79+
"storage_type": "json",
80+
},
81+
"fields": [
82+
{"name": "user", "type": "tag", "path": "$.user"},
83+
{"name": "credit_score", "type": "tag", "path": "$.metadata.credit_score"},
84+
{"name": "job", "type": "text", "path": "$.metadata.job"},
85+
{
86+
"name": "age",
87+
"type": "numeric",
88+
"path": "$.metadata.age",
89+
"attrs": {"sortable": False},
90+
},
91+
{
92+
"name": "user_embedding",
93+
"type": "vector",
94+
"attrs": {
95+
"dims": 3,
96+
"distance_metric": "cosine",
97+
"algorithm": "flat",
98+
"datatype": "float32",
99+
},
100+
},
101+
],
102+
}
103+
async_index = AsyncSearchIndex.from_dict(schema, redis_client=async_client)
104+
await async_index.create(overwrite=True)
105+
106+
async_index2 = await AsyncSearchIndex.from_existing(
107+
async_index.name, redis_client=async_client
108+
)
109+
assert async_index2.schema == async_index.schema
110+
111+
35112
def test_search_index_no_prefix(index_schema):
36113
# specify an explicitly empty prefix...
37114
index_schema.index.prefix = ""

tests/integration/test_search_index.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,42 @@ def test_search_index_from_existing(client, index):
6767
assert index2.schema == index.schema
6868

6969

70+
def test_search_index_from_existing_complex(client):
71+
schema = {
72+
"index": {
73+
"name": "test",
74+
"prefix": "test",
75+
"storage_type": "json",
76+
},
77+
"fields": [
78+
{"name": "user", "type": "tag", "path": "$.user"},
79+
{"name": "credit_score", "type": "tag", "path": "$.metadata.credit_score"},
80+
{"name": "job", "type": "text", "path": "$.metadata.job"},
81+
{
82+
"name": "age",
83+
"type": "numeric",
84+
"path": "$.metadata.age",
85+
"attrs": {"sortable": False},
86+
},
87+
{
88+
"name": "user_embedding",
89+
"type": "vector",
90+
"attrs": {
91+
"dims": 3,
92+
"distance_metric": "cosine",
93+
"algorithm": "flat",
94+
"datatype": "float32",
95+
},
96+
},
97+
],
98+
}
99+
index = SearchIndex.from_dict(schema, redis_client=client)
100+
index.create(overwrite=True)
101+
102+
index2 = SearchIndex.from_existing(index.name, redis_client=client)
103+
assert index.schema == index2.schema
104+
105+
70106
def test_search_index_no_prefix(index_schema):
71107
# specify an explicitly empty prefix...
72108
index_schema.index.prefix = ""

0 commit comments

Comments
 (0)